Merge branch 'blender2.7'
[blender.git] / source / blender / gpu / intern / gpu_matrix.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the ipmlied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2012 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup gpu
22  */
23
24 #include "GPU_shader_interface.h"
25
26 #define SUPPRESS_GENERIC_MATRIX_API
27 #define USE_GPU_PY_MATRIX_API  /* only so values are declared */
28 #include "GPU_matrix.h"
29 #undef USE_GPU_PY_MATRIX_API
30
31 #include "BLI_math_matrix.h"
32 #include "BLI_math_rotation.h"
33 #include "BLI_math_vector.h"
34
35
36 #define DEBUG_MATRIX_BIND 0
37
38 #define MATRIX_STACK_DEPTH 32
39
40 typedef float Mat4[4][4];
41 typedef float Mat3[3][3];
42
43 typedef struct MatrixStack {
44         Mat4 stack[MATRIX_STACK_DEPTH];
45         uint top;
46 } MatrixStack;
47
48 typedef struct {
49         MatrixStack model_view_stack;
50         MatrixStack projection_stack;
51
52         bool dirty;
53
54         /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc)
55          * generate as needed for shaders, invalidate when original matrices change
56          *
57          * TODO: separate Model from View transform? Batches/objects have model,
58          * camera/eye has view & projection
59          */
60 } MatrixState;
61
62 #define MATRIX_4X4_IDENTITY {{1.0f, 0.0f, 0.0f, 0.0f}, \
63                              {0.0f, 1.0f, 0.0f, 0.0f}, \
64                              {0.0f, 0.0f, 1.0f, 0.0f}, \
65                              {0.0f, 0.0f, 0.0f, 1.0f}}
66
67 static MatrixState state = {
68         .model_view_stack = {{MATRIX_4X4_IDENTITY}, 0},
69         .projection_stack = {{MATRIX_4X4_IDENTITY}, 0},
70         .dirty = true,
71 };
72
73 #undef MATRIX_4X4_IDENTITY
74
75 #define ModelViewStack state.model_view_stack
76 #define ModelView ModelViewStack.stack[ModelViewStack.top]
77
78 #define ProjectionStack state.projection_stack
79 #define Projection ProjectionStack.stack[ProjectionStack.top]
80
81 void GPU_matrix_reset(void)
82 {
83         state.model_view_stack.top = 0;
84         state.projection_stack.top = 0;
85         unit_m4(ModelView);
86         unit_m4(Projection);
87         state.dirty = true;
88 }
89
90 #ifdef WITH_GPU_SAFETY
91
92 /* Check if matrix is numerically good */
93 static void checkmat(cosnt float *m)
94 {
95         const int n = 16;
96         for (int i = 0; i < n; i++) {
97 #if _MSC_VER
98                 BLI_assert(_finite(m[i]));
99 #else
100                 BLI_assert(!isinf(m[i]));
101 #endif
102         }
103 }
104
105 #define CHECKMAT(m) checkmat((const float *)m)
106
107 #else
108
109 #define CHECKMAT(m)
110
111 #endif
112
113
114 void GPU_matrix_push(void)
115 {
116         BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH);
117         ModelViewStack.top++;
118         copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]);
119 }
120
121 void GPU_matrix_pop(void)
122 {
123         BLI_assert(ModelViewStack.top > 0);
124         ModelViewStack.top--;
125         state.dirty = true;
126 }
127
128 void GPU_matrix_push_projection(void)
129 {
130         BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH);
131         ProjectionStack.top++;
132         copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]);
133 }
134
135 void GPU_matrix_pop_projection(void)
136 {
137         BLI_assert(ProjectionStack.top > 0);
138         ProjectionStack.top--;
139         state.dirty = true;
140 }
141
142 void GPU_matrix_set(const float m[4][4])
143 {
144         copy_m4_m4(ModelView, m);
145         CHECKMAT(ModelView3D);
146         state.dirty = true;
147 }
148
149 void GPU_matrix_identity_projection_set(void)
150 {
151         unit_m4(Projection);
152         CHECKMAT(Projection3D);
153         state.dirty = true;
154 }
155
156 void GPU_matrix_projection_set(const float m[4][4])
157 {
158         copy_m4_m4(Projection, m);
159         CHECKMAT(Projection3D);
160         state.dirty = true;
161 }
162
163 void GPU_matrix_identity_set(void)
164 {
165         unit_m4(ModelView);
166         state.dirty = true;
167 }
168
169 void GPU_matrix_translate_2f(float x, float y)
170 {
171         Mat4 m;
172         unit_m4(m);
173         m[3][0] = x;
174         m[3][1] = y;
175         GPU_matrix_mul(m);
176 }
177
178 void GPU_matrix_translate_2fv(const float vec[2])
179 {
180         GPU_matrix_translate_2f(vec[0], vec[1]);
181 }
182
183 void GPU_matrix_translate_3f(float x, float y, float z)
184 {
185 #if 1
186         translate_m4(ModelView, x, y, z);
187         CHECKMAT(ModelView);
188 #else /* above works well in early testing, below is generic version */
189         Mat4 m;
190         unit_m4(m);
191         m[3][0] = x;
192         m[3][1] = y;
193         m[3][2] = z;
194         GPU_matrix_mul(m);
195 #endif
196         state.dirty = true;
197 }
198
199 void GPU_matrix_translate_3fv(const float vec[3])
200 {
201         GPU_matrix_translate_3f(vec[0], vec[1], vec[2]);
202 }
203
204 void GPU_matrix_scale_1f(float factor)
205 {
206         Mat4 m;
207         scale_m4_fl(m, factor);
208         GPU_matrix_mul(m);
209 }
210
211 void GPU_matrix_scale_2f(float x, float y)
212 {
213         Mat4 m = {{0.0f}};
214         m[0][0] = x;
215         m[1][1] = y;
216         m[2][2] = 1.0f;
217         m[3][3] = 1.0f;
218         GPU_matrix_mul(m);
219 }
220
221 void GPU_matrix_scale_2fv(const float vec[2])
222 {
223         GPU_matrix_scale_2f(vec[0], vec[1]);
224 }
225
226 void GPU_matrix_scale_3f(float x, float y, float z)
227 {
228         Mat4 m = {{0.0f}};
229         m[0][0] = x;
230         m[1][1] = y;
231         m[2][2] = z;
232         m[3][3] = 1.0f;
233         GPU_matrix_mul(m);
234 }
235
236 void GPU_matrix_scale_3fv(const float vec[3])
237 {
238         GPU_matrix_scale_3f(vec[0], vec[1], vec[2]);
239 }
240
241 void GPU_matrix_mul(const float m[4][4])
242 {
243         mul_m4_m4_post(ModelView, m);
244         CHECKMAT(ModelView);
245         state.dirty = true;
246 }
247
248 void GPU_matrix_rotate_2d(float deg)
249 {
250         /* essentially RotateAxis('Z')
251          * TODO: simpler math for 2D case
252          */
253         rotate_m4(ModelView, 'Z', DEG2RADF(deg));
254 }
255
256 void GPU_matrix_rotate_3f(float deg, float x, float y, float z)
257 {
258         const float axis[3] = {x, y, z};
259         GPU_matrix_rotate_3fv(deg, axis);
260 }
261
262 void GPU_matrix_rotate_3fv(float deg, const float axis[3])
263 {
264         Mat4 m;
265         axis_angle_to_mat4(m, axis, DEG2RADF(deg));
266         GPU_matrix_mul(m);
267 }
268
269 void GPU_matrix_rotate_axis(float deg, char axis)
270 {
271         /* rotate_m4 works in place */
272         rotate_m4(ModelView, axis, DEG2RADF(deg));
273         CHECKMAT(ModelView);
274         state.dirty = true;
275 }
276
277 static void mat4_ortho_set(float m[4][4], float left, float right, float bottom, float top, float near, float far)
278 {
279         m[0][0] = 2.0f / (right - left);
280         m[1][0] = 0.0f;
281         m[2][0] = 0.0f;
282         m[3][0] = -(right + left) / (right - left);
283
284         m[0][1] = 0.0f;
285         m[1][1] = 2.0f / (top - bottom);
286         m[2][1] = 0.0f;
287         m[3][1] = -(top + bottom) / (top - bottom);
288
289         m[0][2] = 0.0f;
290         m[1][2] = 0.0f;
291         m[2][2] = -2.0f / (far - near);
292         m[3][2] = -(far + near) / (far - near);
293
294         m[0][3] = 0.0f;
295         m[1][3] = 0.0f;
296         m[2][3] = 0.0f;
297         m[3][3] = 1.0f;
298
299         state.dirty = true;
300 }
301
302 static void mat4_frustum_set(float m[4][4], float left, float right, float bottom, float top, float near, float far)
303 {
304         m[0][0] = 2.0f * near / (right - left);
305         m[1][0] = 0.0f;
306         m[2][0] = (right + left) / (right - left);
307         m[3][0] = 0.0f;
308
309         m[0][1] = 0.0f;
310         m[1][1] = 2.0f * near / (top - bottom);
311         m[2][1] = (top + bottom) / (top - bottom);
312         m[3][1] = 0.0f;
313
314         m[0][2] = 0.0f;
315         m[1][2] = 0.0f;
316         m[2][2] = -(far + near) / (far - near);
317         m[3][2] = -2.0f * far * near / (far - near);
318
319         m[0][3] = 0.0f;
320         m[1][3] = 0.0f;
321         m[2][3] = -1.0f;
322         m[3][3] = 0.0f;
323
324         state.dirty = true;
325 }
326
327 static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3])
328 {
329 /* This function is loosely based on Mesa implementation.
330  *
331  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
332  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
333  *
334  * Permission is hereby granted, free of charge, to any person obtaining a
335  * copy of this software and associated documentation files (the "Software"),
336  * to deal in the Software without restriction, including without limitation
337  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
338  * and/or sell copies of the Software, and to permit persons to whom the
339  * Software is furnished to do so, subject to the following conditions:
340  *
341  * The above copyright notice including the dates of first publication and
342  * either this permission notice or a reference to
343  * http://oss.sgi.com/projects/FreeB/
344  * shall be included in all copies or substantial portions of the Software.
345  *
346  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
347  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
348  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
349  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
350  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
351  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
352  * SOFTWARE.
353  *
354  * Except as contained in this notice, the name of Silicon Graphics, Inc.
355  * shall not be used in advertising or otherwise to promote the sale, use or
356  * other dealings in this Software without prior written authorization from
357  * Silicon Graphics, Inc.
358  */
359
360         float side[3];
361
362         normalize_v3(lookdir);
363
364         cross_v3_v3v3(side, lookdir, camup);
365
366         normalize_v3(side);
367
368         cross_v3_v3v3(camup, side, lookdir);
369
370         m[0][0] = side[0];
371         m[1][0] = side[1];
372         m[2][0] = side[2];
373         m[3][0] = 0.0f;
374
375         m[0][1] = camup[0];
376         m[1][1] = camup[1];
377         m[2][1] = camup[2];
378         m[3][1] = 0.0f;
379
380         m[0][2] = -lookdir[0];
381         m[1][2] = -lookdir[1];
382         m[2][2] = -lookdir[2];
383         m[3][2] = 0.0f;
384
385         m[0][3] = 0.0f;
386         m[1][3] = 0.0f;
387         m[2][3] = 0.0f;
388         m[3][3] = 1.0f;
389
390         state.dirty = true;
391 }
392
393 void GPU_matrix_ortho_set(float left, float right, float bottom, float top, float near, float far)
394 {
395         mat4_ortho_set(Projection, left, right, bottom, top, near, far);
396         CHECKMAT(Projection);
397         state.dirty = true;
398 }
399
400 void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top)
401 {
402         Mat4 m;
403         mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f);
404         CHECKMAT(Projection2D);
405         state.dirty = true;
406 }
407
408 void GPU_matrix_frustum_set(float left, float right, float bottom, float top, float near, float far)
409 {
410         mat4_frustum_set(Projection, left, right, bottom, top, near, far);
411         CHECKMAT(Projection);
412         state.dirty = true;
413 }
414
415 void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far)
416 {
417         float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near;
418         float half_width = half_height * aspect;
419         GPU_matrix_frustum_set(-half_width, +half_width, -half_height, +half_height, near, far);
420 }
421
422 void GPU_matrix_look_at(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
423 {
424         Mat4 cm;
425         float lookdir[3];
426         float camup[3] = {upX, upY, upZ};
427
428         lookdir[0] = centerX - eyeX;
429         lookdir[1] = centerY - eyeY;
430         lookdir[2] = centerZ - eyeZ;
431
432         mat4_look_from_origin(cm, lookdir, camup);
433
434         GPU_matrix_mul(cm);
435         GPU_matrix_translate_3f(-eyeX, -eyeY, -eyeZ);
436 }
437
438 void GPU_matrix_project(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3])
439 {
440         float v[4];
441
442         mul_v4_m4v3(v, model, world);
443         mul_m4_v4(proj, v);
444
445         if (v[3] != 0.0f) {
446                 mul_v3_fl(v, 1.0f / v[3]);
447         }
448
449         win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f;
450         win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f;
451         win[2] = (v[2] + 1) * 0.5f;
452 }
453
454 bool GPU_matrix_unproject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], float world[3])
455 {
456         float pm[4][4];
457         float in[4];
458         float out[4];
459
460         mul_m4_m4m4(pm, proj, model);
461
462         if (!invert_m4(pm)) {
463                 zero_v3(world);
464                 return false;
465         }
466
467         in[0] = win[0];
468         in[1] = win[1];
469         in[2] = win[2];
470         in[3] = 1;
471
472         /* Map x and y from window coordinates */
473         in[0] = (in[0] - view[0]) / view[2];
474         in[1] = (in[1] - view[1]) / view[3];
475
476         /* Map to range -1 to +1 */
477         in[0] = 2 * in[0] - 1;
478         in[1] = 2 * in[1] - 1;
479         in[2] = 2 * in[2] - 1;
480
481         mul_v4_m4v3(out, pm, in);
482
483         if (out[3] == 0.0f) {
484                 copy_v3_v3(world, out);
485                 return false;
486         }
487
488         mul_v3_v3fl(world, out, 1.0f / out[3]);
489         return true;
490 }
491
492 const float (*GPU_matrix_model_view_get(float m[4][4]))[4]
493 {
494         if (m) {
495                 copy_m4_m4(m, ModelView);
496                 return m;
497         }
498         else {
499                 return ModelView;
500         }
501 }
502
503 const float (*GPU_matrix_projection_get(float m[4][4]))[4]
504 {
505         if (m) {
506                 copy_m4_m4(m, Projection);
507                 return m;
508         }
509         else {
510                 return Projection;
511         }
512 }
513
514 const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4]
515 {
516         if (m == NULL) {
517                 static Mat4 temp;
518                 m = temp;
519         }
520
521         mul_m4_m4m4(m, Projection, ModelView);
522         return m;
523 }
524
525 const float (*GPU_matrix_normal_get(float m[3][3]))[3]
526 {
527         if (m == NULL) {
528                 static Mat3 temp3;
529                 m = temp3;
530         }
531
532         copy_m3_m4(m, (const float (*)[4])GPU_matrix_model_view_get(NULL));
533
534         invert_m3(m);
535         transpose_m3(m);
536
537         return m;
538 }
539
540 const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3]
541 {
542         if (m == NULL) {
543                 static Mat3 temp3;
544                 m = temp3;
545         }
546
547         GPU_matrix_normal_get(m);
548         invert_m3(m);
549
550         return m;
551 }
552
553 void GPU_matrix_bind(const GPUShaderInterface *shaderface)
554 {
555         /* set uniform values to matrix stack values
556          * call this before a draw call if desired matrices are dirty
557          * call glUseProgram before this, as glUniform expects program to be bound
558          */
559
560         const GPUShaderInput *MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW);
561         const GPUShaderInput *P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION);
562         const GPUShaderInput *MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP);
563
564         const GPUShaderInput *N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL);
565         const GPUShaderInput *MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV);
566         const GPUShaderInput *P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV);
567
568         if (MV) {
569 #if DEBUG_MATRIX_BIND
570                 puts("setting MV matrix");
571 #endif
572
573                 glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL));
574         }
575
576         if (P) {
577 #if DEBUG_MATRIX_BIND
578                 puts("setting P matrix");
579 #endif
580
581                 glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL));
582         }
583
584         if (MVP) {
585 #if DEBUG_MATRIX_BIND
586                 puts("setting MVP matrix");
587 #endif
588
589                 glUniformMatrix4fv(MVP->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL));
590         }
591
592         if (N) {
593 #if DEBUG_MATRIX_BIND
594                 puts("setting normal matrix");
595 #endif
596
597                 glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL));
598         }
599
600         if (MV_inv) {
601                 Mat4 m;
602                 GPU_matrix_model_view_get(m);
603                 invert_m4(m);
604                 glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m);
605         }
606
607         if (P_inv) {
608                 Mat4 m;
609                 GPU_matrix_projection_get(m);
610                 invert_m4(m);
611                 glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m);
612         }
613
614         state.dirty = false;
615 }
616
617 bool GPU_matrix_dirty_get(void)
618 {
619         return state.dirty;
620 }
621
622
623 /* -------------------------------------------------------------------- */
624 /** \name Python API Helpers
625  * \{ */
626 BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch");
627
628 /* Return int since caller is may subtract. */
629
630 int GPU_matrix_stack_level_get_model_view(void)
631 {
632         return (int)state.model_view_stack.top;
633 }
634
635 int GPU_matrix_stack_level_get_projection(void)
636 {
637         return (int)state.projection_stack.top;
638 }
639
640 /** \} */