Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "shadertoy_shader.h"
     18 #include "utils.h"
     19 
     20 #define _USE_MATH_DEFINES
     21 #include <math.h>
     22 
     23 namespace {
     24 bool CompileShader10(GLuint shader, const std::string& shader_string) {
     25   std::string prefix = "#version 100\n";
     26   std::string string_with_prefix = prefix + shader_string;
     27   const char* shader_str[] = { string_with_prefix.data() };
     28   glShaderSource(shader, 1, shader_str, NULL);
     29   glCompileShader(shader);
     30 
     31   GLint success;
     32   GLchar infoLog[512];
     33   glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
     34   if (!success)
     35   {
     36     glGetShaderInfoLog(shader, 512, NULL, infoLog);
     37     LOGI("Shader Failed to compile: %s -- %s\n", *shader_str, infoLog);
     38     return false;
     39   }
     40   return true;
     41 }
     42 };  // namespace
     43 
     44 
     45 ShadertoyShader::ShadertoyShader() :
     46  uiResolution_(-1), uiGlobalTime_(-1), uiFrame_(-1), uiTimeDelta_(-1),
     47  uiChannel0_(-1), unViewport_(-1), unCorners_(-1), shader_program_(0) {
     48 
     49   GLuint tex_ids[4];
     50   glGenTextures(4, &tex_ids[0]);
     51   for (int ii = 0; ii < 4; ii++) {
     52     input_textures_[ii].width = 0;
     53     input_textures_[ii].height = 0;
     54     input_textures_[ii].id = tex_ids[ii];
     55   }
     56 }
     57 
     58 ShadertoyShader::~ShadertoyShader() {
     59   GLuint ids[] = { input_textures_[0].id, input_textures_[1].id, input_textures_[2].id, input_textures_[3].id, };
     60   glDeleteTextures(4, ids);
     61 }
     62 
     63 void ShadertoyShader::CreateShaderFromString(const std::string& shader_string) {
     64   CreateShader(shader_string);
     65 }
     66 
     67 void ShadertoyShader::GetUniformLocations() {
     68   glUseProgram(shader_program_);
     69   uiResolution_ = glGetUniformLocation(shader_program_, "iResolution");
     70   uiGlobalTime_ = glGetUniformLocation(shader_program_, "iGlobalTime");
     71   uiFrame_ = glGetUniformLocation(shader_program_, "iFrame");
     72   uiTimeDelta_ = glGetUniformLocation(shader_program_, "iTimeDelta");
     73   uiChannel0_ = glGetUniformLocation(shader_program_, "iChannel0");
     74 
     75   if (uiChannel0_ != -1)
     76     glUniform1i(uiChannel0_, 0);
     77 
     78   unViewport_ = glGetUniformLocation(shader_program_, "unViewport");
     79   unCorners_ = glGetUniformLocation(shader_program_, "unCorners");
     80 
     81   glUseProgram(0);
     82 }
     83 
     84 void ShadertoyShader::CreateShader(const std::string fragment_string) {
     85   std::string vertex_string = SHADER0([]() {
     86     attribute vec2 pos;
     87     void main() {
     88       gl_Position = vec4(pos.xy, 0.0, 1.0);
     89     }
     90   });
     91 
     92   std::string shader_toy_fragment_header = SHADER0([]() {
     93     precision highp float;
     94     uniform vec3 iResolution;
     95     uniform float iGlobalTime;
     96     uniform vec4 iMouse;
     97     uniform int iFrame;
     98     uniform float iTimeDelta;
     99     uniform vec3 iChannelResolution[4];
    100     uniform sampler2D iChannel0;
    101     vec4 texture2DGrad(sampler2D s, in vec2 uv, vec2 gx, vec2 gy) { return texture2D(s, uv); }
    102     vec4 texture2DLod(sampler2D s, in vec2 uv, in float lod) { return texture2D(s, uv); }
    103     void mainImage(out vec4 c, in vec2 f);
    104   });
    105 
    106   std::string shader_toy_fragment_footer = SHADER0([]() {
    107     void main(void) {
    108       vec4 shader_color = vec4(0, 0, 0, 1);
    109       mainImage(shader_color, gl_FragCoord.xy);
    110       shader_color.w = 1.0;
    111       gl_FragColor = shader_color;
    112     }
    113   });
    114 
    115   std::string complete_fragment_string = shader_toy_fragment_header + fragment_string + shader_toy_fragment_footer;
    116 
    117   GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    118   CompileShader10(vertex_shader, vertex_string);
    119 
    120   GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    121   CompileShader10(fragment_shader, complete_fragment_string);
    122 
    123   // Link shaders
    124   shader_program_ = glCreateProgram();
    125   LinkProgram(shader_program_, vertex_shader, fragment_shader);
    126 
    127   GetUniformLocations();
    128 
    129   glDeleteShader(vertex_shader);
    130   glDeleteShader(fragment_shader);
    131 }
    132 
    133 void ShadertoyShader::PrepareForDraw(int width, int height, float global_time, int frame, float time_delta) {
    134   glUseProgram(shader_program_);
    135 
    136   // Set the uniforms
    137   if (uiResolution_ != -1)
    138     glUniform3f(uiResolution_, (float)width, (float)height, 1);
    139   if (uiGlobalTime_ != -1)
    140     glUniform1f(uiGlobalTime_, global_time);
    141   if (uiFrame_ != -1)
    142     glUniform1f(uiFrame_, (float)frame);
    143   if (uiTimeDelta_ != -1)
    144     glUniform1f(uiTimeDelta_, time_delta);
    145 
    146   glActiveTexture(GL_TEXTURE0);
    147   glBindTexture(GL_TEXTURE_2D, input_textures_[0].id);
    148   glActiveTexture(GL_TEXTURE1);
    149   glBindTexture(GL_TEXTURE_2D, input_textures_[1].id);
    150   glActiveTexture(GL_TEXTURE2);
    151   glBindTexture(GL_TEXTURE_2D, input_textures_[2].id);
    152   glActiveTexture(GL_TEXTURE3);
    153   glBindTexture(GL_TEXTURE_2D, input_textures_[3].id);
    154 
    155   if (unViewport_ != -1)
    156     glUniform4f(unViewport_, 0, 0, (float)width, (float)height);
    157 }
    158