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