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