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 {
CompileShader10(GLuint shader,const std::string & shader_string)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 
ShadertoyShader()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 
~ShadertoyShader()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 
CreateShaderFromString(const std::string & shader_string)63 void ShadertoyShader::CreateShaderFromString(const std::string& shader_string) {
64   CreateShader(shader_string);
65 }
66 
GetUniformLocations()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 
CreateShader(const std::string fragment_string)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 
PrepareForDraw(int width,int height,float global_time,int frame,float time_delta)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