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