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