CMake: Disable some features when using MinGW and full cmake config
[blender.git] / source / blender / gpu / intern / gpu_basic_shader.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_basic_shader.c
29  *  \ingroup gpu
30  *
31  * GLSL shaders to replace fixed function OpenGL materials and lighting. These
32  * are deprecated in newer OpenGL versions and missing in OpenGL ES 2.0. Also,
33  * two sided lighting is no longer natively supported on NVidia cards which
34  * results in slow software fallback.
35  *
36  * Todo:
37  * - Replace glLight and glMaterial functions entirely with GLSL uniforms, to
38  *   make OpenGL ES 2.0 work.
39  * - Replace glTexCoord and glColor with generic attributes.
40  * - Optimize for case where fewer than 3 or 8 lights are used.
41  * - Optimize for case where specular is not used.
42  * - Optimize for case where no texture matrix is used.
43  */
44
45 #include "BLI_math.h"
46 #include "BLI_utildefines.h"
47
48 #include "GPU_basic_shader.h"
49 #include "GPU_glew.h"
50 #include "GPU_shader.h"
51
52 /* State */
53
54 static const bool USE_GLSL = false;
55
56 static struct {
57         GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
58         bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
59
60         int bound_options;
61
62         int lights_enabled;
63         int lights_directional;
64 } GPU_MATERIAL_STATE;
65
66 /* Init / exit */
67
68 void GPU_basic_shaders_init(void)
69 {
70         memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE));
71 }
72
73 void GPU_basic_shaders_exit(void)
74 {
75         int i;
76         
77         for (i = 0; i < GPU_SHADER_OPTION_COMBINATIONS; i++)
78                 if (GPU_MATERIAL_STATE.cached_shaders[i])
79                         GPU_shader_free(GPU_MATERIAL_STATE.cached_shaders[i]);
80 }
81
82 /* Shader lookup / create */
83
84 static bool solid_compatible_lighting(void)
85 {
86         int enabled = GPU_MATERIAL_STATE.lights_enabled;
87         int directional = GPU_MATERIAL_STATE.lights_directional;
88
89         /* more than 3 lights? */
90         if (enabled >= (1 << 3))
91                 return false;
92
93         /* all directional? */
94         return ((directional & enabled) == enabled);
95 }
96
97 #if 0
98 static int detect_options()
99 {
100         GLint two_sided;
101         int options = 0;
102
103         if (glIsEnabled(GL_TEXTURE_2D))
104                 options |= GPU_SHADER_TEXTURE_2D;
105         if (glIsEnabled(GL_COLOR_MATERIAL))
106                 options |= GPU_SHADER_USE_COLOR;
107
108         if (glIsEnabled(GL_LIGHTING))
109                 options |= GPU_SHADER_LIGHTING;
110
111         glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &two_sided);
112         if (two_sided == GL_TRUE)
113                 options |= GPU_SHADER_TWO_SIDED;
114         
115         return options;
116 }
117 #endif
118
119 static GPUShader *gpu_basic_shader(int options)
120 {
121         /* glsl code */
122         extern char datatoc_gpu_shader_basic_vert_glsl[];
123         extern char datatoc_gpu_shader_basic_frag_glsl[];
124         GPUShader *shader;
125
126         /* detect if we can do faster lighting for solid draw mode */
127         if (options & GPU_SHADER_LIGHTING)
128                 if (solid_compatible_lighting())
129                         options |= GPU_SHADER_SOLID_LIGHTING;
130
131         /* cached shaders */
132         shader = GPU_MATERIAL_STATE.cached_shaders[options];
133
134         if (!shader && !GPU_MATERIAL_STATE.failed_shaders[options]) {
135                 /* create shader if it doesn't exist yet */
136                 char defines[64*GPU_SHADER_OPTIONS_NUM] = "";
137
138                 if (options & GPU_SHADER_USE_COLOR)
139                         strcat(defines, "#define USE_COLOR\n");
140                 if (options & GPU_SHADER_TWO_SIDED)
141                         strcat(defines, "#define USE_TWO_SIDED\n");
142                 if (options & GPU_SHADER_TEXTURE_2D)
143                         strcat(defines, "#define USE_TEXTURE\n");
144
145                 if (options & GPU_SHADER_SOLID_LIGHTING)
146                         strcat(defines, "#define USE_SOLID_LIGHTING\n");
147                 else if (options & GPU_SHADER_LIGHTING)
148                         strcat(defines, "#define USE_SCENE_LIGHTING\n");
149
150                 shader = GPU_shader_create(
151                         datatoc_gpu_shader_basic_vert_glsl,
152                         datatoc_gpu_shader_basic_frag_glsl,
153                         NULL,
154                         NULL,
155                         defines, 0, 0, 0);
156                 
157                 if (shader) {
158                         /* set texture map to first texture unit */
159                         if (options & GPU_SHADER_TEXTURE_2D)
160                                 glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
161
162                         GPU_MATERIAL_STATE.cached_shaders[options] = shader;
163                 }
164                 else
165                         GPU_MATERIAL_STATE.failed_shaders[options] = true;
166         }
167
168         return shader;
169 }
170
171 /* Bind / unbind */
172
173 void GPU_basic_shader_bind(int options)
174 {
175         if (USE_GLSL) {
176                 if (options) {
177                         GPUShader *shader = gpu_basic_shader(options);
178
179                         if (shader)
180                                 GPU_shader_bind(shader);
181                 }
182                 else {
183                         GPU_shader_unbind();
184                 }
185         }
186         else {
187                 int bound_options = GPU_MATERIAL_STATE.bound_options;
188
189                 if (options & GPU_SHADER_LIGHTING) {
190                         glEnable(GL_LIGHTING);
191
192                         if (options & GPU_SHADER_USE_COLOR)
193                                 glEnable(GL_COLOR_MATERIAL);
194                         else
195                                 glDisable(GL_COLOR_MATERIAL);
196
197                         if (options & GPU_SHADER_TWO_SIDED)
198                                 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
199                         else
200                                 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
201                 }
202                 else if (bound_options & GPU_SHADER_LIGHTING) {
203                         glDisable(GL_LIGHTING);
204                         glDisable(GL_COLOR_MATERIAL);
205                         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
206                 }
207
208                 if (options & GPU_SHADER_TEXTURE_2D) {
209                         GLint env_mode = (options & (GPU_SHADER_USE_COLOR|GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
210                         glEnable(GL_TEXTURE_2D);
211                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
212                 }
213                 else if (bound_options & GPU_SHADER_TEXTURE_2D) {
214                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
215                         glDisable(GL_TEXTURE_2D);
216                 }
217         }
218
219         GPU_MATERIAL_STATE.bound_options = options;
220 }
221
222 int GPU_basic_shader_bound_options(void)
223 {
224         /* ideally this should disappear, anything that uses this is making fragile
225          * assumptions that the basic shader is bound and not another shader */
226         return GPU_MATERIAL_STATE.bound_options;
227 }
228
229 /* Material Colors */
230
231 void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
232         int shininess, float alpha)
233 {
234         float gl_diffuse[4], gl_specular[4];
235
236         if (diffuse)
237                 copy_v3_v3(gl_diffuse, diffuse);
238         else
239                 zero_v3(gl_diffuse);
240         gl_diffuse[3] = alpha;
241
242         if (specular)
243                 copy_v3_v3(gl_specular, specular);
244         else
245                 zero_v3(gl_specular);
246         gl_specular[3] = 1.0f;
247
248         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse);
249         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gl_specular);
250         glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
251 }
252
253 void GPU_basic_shader_light_set(int light_num, GPULightData *light)
254 {
255         int light_bit = (1 << light_num);
256
257         /* note that light position is affected by the current modelview matrix! */
258
259         GPU_MATERIAL_STATE.lights_enabled &= ~light_bit;
260         GPU_MATERIAL_STATE.lights_directional &= ~light_bit;
261
262         if (light) {
263                 float position[4], diffuse[4], specular[4];
264
265                 glEnable(GL_LIGHT0+light_num);
266
267                 /* position */
268                 if (light->type == GPU_LIGHT_SUN) {
269                         copy_v3_v3(position, light->direction);
270                         position[3] = 0.0f;
271                 }
272                 else {
273                         copy_v3_v3(position, light->position);
274                         position[3] = 1.0f;
275                 }
276                 glLightfv(GL_LIGHT0+light_num, GL_POSITION, position);
277
278                 /* energy */
279                 copy_v3_v3(diffuse, light->diffuse);
280                 copy_v3_v3(specular, light->specular);
281                 diffuse[3] = 1.0f;
282                 specular[3] = 1.0f;
283                 glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, diffuse);
284                 glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, specular);
285
286                 /* attenuation */
287                 if (light->type == GPU_LIGHT_SUN) {
288                         glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, 1.0f);
289                         glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, 0.0f);
290                         glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, 0.0f);
291                 }
292                 else {
293                         glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation);
294                         glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation);
295                         glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation);
296                 }
297
298                 /* spot */
299                 glLightfv(GL_LIGHT0+light_num, GL_SPOT_DIRECTION, light->direction);
300                 if (light->type == GPU_LIGHT_SPOT) {
301                         glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, light->spot_cutoff);
302                         glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, light->spot_exponent);
303                 }
304                 else {
305                         glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, 180.0f);
306                         glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, 0.0f);
307                 }
308
309                 GPU_MATERIAL_STATE.lights_enabled |= light_bit;
310                 if (position[3] == 0.0f)
311                         GPU_MATERIAL_STATE.lights_directional |= light_bit;
312         }
313         else {
314                 if (USE_GLSL) {
315                         /* glsl shader needs these zero to skip them */
316                         const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
317
318                         glLightfv(GL_LIGHT0+light_num, GL_POSITION, zero);
319                         glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, zero);
320                         glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, zero);
321                 }
322
323                 glDisable(GL_LIGHT0+light_num);
324         }
325 }
326
327 void GPU_basic_shader_light_set_viewer(bool local)
328 {
329         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local)? GL_TRUE: GL_FALSE);
330 }
331