Remember to clear the needs_update flag on 1D textures after upload.
[movit] / effect.cpp
1 #define GL_GLEXT_PROTOTYPES 1
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <assert.h>
6 #include "effect.h"
7 #include "effect_chain.h"
8 #include "util.h"
9
10 #include <GL/gl.h>
11 #include <GL/glext.h>
12
13 GLint get_uniform_location(GLuint glsl_program_num, const std::string &prefix, const std::string &key)
14 {
15         std::string name = prefix + "_" + key;
16         return glGetUniformLocation(glsl_program_num, name.c_str());
17 }
18
19 void set_uniform_int(GLuint glsl_program_num, const std::string &prefix, const std::string &key, int value)
20 {
21         GLint location = get_uniform_location(glsl_program_num, prefix, key);
22         if (location == -1) {
23                 return;
24         }
25         check_error();
26         glUniform1i(location, value);
27         check_error();
28 }
29
30 void set_uniform_float(GLuint glsl_program_num, const std::string &prefix, const std::string &key, float value)
31 {
32         GLint location = get_uniform_location(glsl_program_num, prefix, key);
33         if (location == -1) {
34                 return;
35         }
36         check_error();
37         glUniform1f(location, value);
38         check_error();
39 }
40
41 void set_uniform_float_array(GLuint glsl_program_num, const std::string &prefix, const std::string &key, const float *values, size_t num_values)
42 {
43         GLint location = get_uniform_location(glsl_program_num, prefix, key);
44         if (location == -1) {
45                 return;
46         }
47         check_error();
48         glUniform1fv(location, num_values, values);
49         check_error();
50 }
51
52 void set_uniform_vec2(GLuint glsl_program_num, const std::string &prefix, const std::string &key, const float *values)
53 {
54         GLint location = get_uniform_location(glsl_program_num, prefix, key);
55         if (location == -1) {
56                 return;
57         }
58         check_error();
59         glUniform2fv(location, 1, values);
60         check_error();
61 }
62
63 void set_uniform_vec3(GLuint glsl_program_num, const std::string &prefix, const std::string &key, const float *values)
64 {
65         GLint location = get_uniform_location(glsl_program_num, prefix, key);
66         if (location == -1) {
67                 return;
68         }
69         check_error();
70         glUniform3fv(location, 1, values);
71         check_error();
72 }
73
74 void set_uniform_vec4_array(GLuint glsl_program_num, const std::string &prefix, const std::string &key, const float *values, size_t num_values)
75 {
76         GLint location = get_uniform_location(glsl_program_num, prefix, key);
77         if (location == -1) {
78                 return;
79         }
80         check_error();
81         glUniform4fv(location, num_values, values);
82         check_error();
83 }
84
85 bool Effect::set_int(const std::string &key, int value)
86 {
87         if (params_int.count(key) == 0) {
88                 return false;
89         }
90         *params_int[key] = value;
91         return true;
92 }
93
94 bool Effect::set_float(const std::string &key, float value)
95 {
96         if (params_float.count(key) == 0) {
97                 return false;
98         }
99         *params_float[key] = value;
100         return true;
101 }
102
103 bool Effect::set_vec2(const std::string &key, const float *values)
104 {
105         if (params_vec2.count(key) == 0) {
106                 return false;
107         }
108         memcpy(params_vec2[key], values, sizeof(float) * 2);
109         return true;
110 }
111
112 bool Effect::set_vec3(const std::string &key, const float *values)
113 {
114         if (params_vec3.count(key) == 0) {
115                 return false;
116         }
117         memcpy(params_vec3[key], values, sizeof(float) * 3);
118         return true;
119 }
120
121 void Effect::register_int(const std::string &key, int *value)
122 {
123         assert(params_int.count(key) == 0);
124         params_int[key] = value;
125 }
126
127 void Effect::register_float(const std::string &key, float *value)
128 {
129         assert(params_float.count(key) == 0);
130         params_float[key] = value;
131 }
132
133 void Effect::register_vec2(const std::string &key, float *values)
134 {
135         assert(params_vec2.count(key) == 0);
136         params_vec2[key] = values;
137 }
138
139 void Effect::register_vec3(const std::string &key, float *values)
140 {
141         assert(params_vec3.count(key) == 0);
142         params_vec3[key] = values;
143 }
144
145 void Effect::register_1d_texture(const std::string &key, float *values, size_t size)
146 {
147         assert(params_tex_1d.count(key) == 0);
148
149         Texture1D tex;
150         tex.values = values;
151         tex.size = size;
152         tex.needs_update = false;
153         glGenTextures(1, &tex.texture_num);
154
155         glBindTexture(GL_TEXTURE_1D, tex.texture_num);
156         check_error();
157         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
158         check_error();
159         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
160         check_error();
161         glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, size, 0, GL_LUMINANCE, GL_FLOAT, values);
162         check_error();
163
164         params_tex_1d[key] = tex;
165 }
166
167 void Effect::invalidate_1d_texture(const std::string &key)
168 {
169         assert(params_tex_1d.count(key) != 0);
170         params_tex_1d[key].needs_update = true;
171 }
172
173 void Effect::add_self_to_effect_chain(EffectChain *chain, const std::vector<Effect *> &inputs)
174 {
175         chain->add_effect_raw(this, inputs);
176 }
177
178 // Output convenience uniforms for each parameter.
179 // These will be filled in per-frame.
180 std::string Effect::output_convenience_uniforms() const
181 {
182         std::string output = "";
183         for (std::map<std::string, float*>::const_iterator it = params_float.begin();
184              it != params_float.end();
185              ++it) {
186                 char buf[256];
187                 sprintf(buf, "uniform float PREFIX(%s);\n", it->first.c_str());
188                 output.append(buf);
189         }
190         for (std::map<std::string, float*>::const_iterator it = params_vec2.begin();
191              it != params_vec2.end();
192              ++it) {
193                 char buf[256];
194                 sprintf(buf, "uniform vec2 PREFIX(%s);\n", it->first.c_str());
195                 output.append(buf);
196         }
197         for (std::map<std::string, float*>::const_iterator it = params_vec3.begin();
198              it != params_vec3.end();
199              ++it) {
200                 char buf[256];
201                 sprintf(buf, "uniform vec3 PREFIX(%s);\n", it->first.c_str());
202                 output.append(buf);
203         }
204         for (std::map<std::string, Texture1D>::const_iterator it = params_tex_1d.begin();
205              it != params_tex_1d.end();
206              ++it) {
207                 char buf[256];
208                 sprintf(buf, "uniform sampler1D PREFIX(%s);\n", it->first.c_str());
209                 output.append(buf);
210         }
211         return output;
212 }
213
214 void Effect::set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
215 {
216         for (std::map<std::string, float*>::const_iterator it = params_float.begin();
217              it != params_float.end();
218              ++it) {
219                 set_uniform_float(glsl_program_num, prefix, it->first, *it->second);
220         }
221         for (std::map<std::string, float*>::const_iterator it = params_vec2.begin();
222              it != params_vec2.end();
223              ++it) {
224                 set_uniform_vec2(glsl_program_num, prefix, it->first, it->second);
225         }
226         for (std::map<std::string, float*>::const_iterator it = params_vec3.begin();
227              it != params_vec3.end();
228              ++it) {
229                 set_uniform_vec3(glsl_program_num, prefix, it->first, it->second);
230         }
231
232         for (std::map<std::string, Texture1D>::const_iterator it = params_tex_1d.begin();
233              it != params_tex_1d.end();
234              ++it) {
235                 glActiveTexture(GL_TEXTURE0 + *sampler_num);
236                 check_error();
237                 glBindTexture(GL_TEXTURE_1D, it->second.texture_num);
238                 check_error();
239
240                 if (it->second.needs_update) {
241                         glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE16F_ARB, it->second.size, 0, GL_LUMINANCE, GL_FLOAT, it->second.values);
242                         check_error();
243                         it->second.needs_update = false;
244                 }
245
246                 set_uniform_int(glsl_program_num, prefix, it->first, *sampler_num);
247                 ++*sampler_num;
248         }
249 }
250
251 void Effect::clear_gl_state() {}