/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "shadertoy_shader.h" #include "utils.h" #define _USE_MATH_DEFINES #include namespace { bool CompileShader10(GLuint shader, const std::string& shader_string) { std::string prefix = "#version 100\n"; std::string string_with_prefix = prefix + shader_string; const char* shader_str[] = { string_with_prefix.data() }; glShaderSource(shader, 1, shader_str, NULL); glCompileShader(shader); GLint success; GLchar infoLog[512]; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 512, NULL, infoLog); LOGI("Shader Failed to compile: %s -- %s\n", *shader_str, infoLog); return false; } return true; } }; // namespace ShadertoyShader::ShadertoyShader() : uiResolution_(-1), uiGlobalTime_(-1), uiFrame_(-1), uiTimeDelta_(-1), uiChannel0_(-1), unViewport_(-1), unCorners_(-1), shader_program_(0) { GLuint tex_ids[4]; glGenTextures(4, &tex_ids[0]); for (int ii = 0; ii < 4; ii++) { input_textures_[ii].width = 0; input_textures_[ii].height = 0; input_textures_[ii].id = tex_ids[ii]; } } ShadertoyShader::~ShadertoyShader() { GLuint ids[] = { input_textures_[0].id, input_textures_[1].id, input_textures_[2].id, input_textures_[3].id, }; glDeleteTextures(4, ids); } void ShadertoyShader::CreateShaderFromString(const std::string& shader_string) { CreateShader(shader_string); } void ShadertoyShader::GetUniformLocations() { glUseProgram(shader_program_); uiResolution_ = glGetUniformLocation(shader_program_, "iResolution"); uiGlobalTime_ = glGetUniformLocation(shader_program_, "iGlobalTime"); uiFrame_ = glGetUniformLocation(shader_program_, "iFrame"); uiTimeDelta_ = glGetUniformLocation(shader_program_, "iTimeDelta"); uiChannel0_ = glGetUniformLocation(shader_program_, "iChannel0"); if (uiChannel0_ != -1) glUniform1i(uiChannel0_, 0); unViewport_ = glGetUniformLocation(shader_program_, "unViewport"); unCorners_ = glGetUniformLocation(shader_program_, "unCorners"); glUseProgram(0); } void ShadertoyShader::CreateShader(const std::string fragment_string) { std::string vertex_string = SHADER0([]() { attribute vec2 pos; void main() { gl_Position = vec4(pos.xy, 0.0, 1.0); } }); std::string shader_toy_fragment_header = SHADER0([]() { precision highp float; uniform vec3 iResolution; uniform float iGlobalTime; uniform vec4 iMouse; uniform int iFrame; uniform float iTimeDelta; uniform vec3 iChannelResolution[4]; uniform sampler2D iChannel0; vec4 texture2DGrad(sampler2D s, in vec2 uv, vec2 gx, vec2 gy) { return texture2D(s, uv); } vec4 texture2DLod(sampler2D s, in vec2 uv, in float lod) { return texture2D(s, uv); } void mainImage(out vec4 c, in vec2 f); }); std::string shader_toy_fragment_footer = SHADER0([]() { void main(void) { vec4 shader_color = vec4(0, 0, 0, 1); mainImage(shader_color, gl_FragCoord.xy); shader_color.w = 1.0; gl_FragColor = shader_color; } }); std::string complete_fragment_string = shader_toy_fragment_header + fragment_string + shader_toy_fragment_footer; GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); CompileShader10(vertex_shader, vertex_string); GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); CompileShader10(fragment_shader, complete_fragment_string); // Link shaders shader_program_ = glCreateProgram(); LinkProgram(shader_program_, vertex_shader, fragment_shader); GetUniformLocations(); glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); } void ShadertoyShader::PrepareForDraw(int width, int height, float global_time, int frame, float time_delta) { glUseProgram(shader_program_); // Set the uniforms if (uiResolution_ != -1) glUniform3f(uiResolution_, (float)width, (float)height, 1); if (uiGlobalTime_ != -1) glUniform1f(uiGlobalTime_, global_time); if (uiFrame_ != -1) glUniform1f(uiFrame_, (float)frame); if (uiTimeDelta_ != -1) glUniform1f(uiTimeDelta_, time_delta); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, input_textures_[0].id); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, input_textures_[1].id); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, input_textures_[2].id); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, input_textures_[3].id); if (unViewport_ != -1) glUniform4f(unViewport_, 0, 0, (float)width, (float)height); }