Merge branch 'master' into blender2.8
[blender.git] / source / blender / draw / intern / draw_debug.c
1 /*
2  * Copyright 2018, Blender Foundation.
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  * Contributor(s): Blender Institute
19  *
20  */
21
22 /** \file blender/draw/intern/draw_debug.c
23  *  \ingroup draw
24  *
25  * \brief Simple API to draw debug shapes in the viewport.
26  */
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_object_types.h"
31
32 #include "BKE_object.h"
33
34 #include "BLI_link_utils.h"
35
36 #include "GPU_immediate.h"
37
38 #include "draw_debug.h"
39 #include "draw_manager.h"
40
41 /* --------- Register --------- */
42
43 /* Matrix applied to all points before drawing. Could be a stack if needed. */
44 static float g_modelmat[4][4];
45
46 void DRW_debug_modelmat_reset(void)
47 {
48         unit_m4(g_modelmat);
49 }
50
51 void DRW_debug_modelmat(const float modelmat[4][4])
52 {
53         copy_m4_m4(g_modelmat, modelmat);
54 }
55
56 void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4])
57 {
58         DRWDebugLine *line = MEM_mallocN(sizeof(DRWDebugLine), "DRWDebugLine");
59         mul_v3_m4v3(line->pos[0], g_modelmat, v1);
60         mul_v3_m4v3(line->pos[1], g_modelmat, v2);
61         copy_v4_v4(line->color, color);
62         BLI_LINKS_PREPEND(DST.debug.lines, line);
63 }
64
65 void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4])
66 {
67         BLI_assert(vert_len > 1);
68
69         for (int i = 0; i < vert_len; ++i) {
70                 DRW_debug_line_v3v3(v[i], v[(i + 1) % vert_len], color);
71         }
72 }
73
74 /* NOTE: g_modelmat is still applied on top. */
75 void DRW_debug_m4(const float m[4][4])
76 {
77         float v0[3] = {0.0f, 0.0f, 0.0f};
78         float v1[3] = {1.0f, 0.0f, 0.0f};
79         float v2[3] = {0.0f, 1.0f, 0.0f};
80         float v3[3] = {0.0f, 0.0f, 1.0f};
81
82         mul_m4_v3(m, v0);
83         mul_m4_v3(m, v1);
84         mul_m4_v3(m, v2);
85         mul_m4_v3(m, v3);
86
87         DRW_debug_line_v3v3(v0, v1, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
88         DRW_debug_line_v3v3(v0, v2, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
89         DRW_debug_line_v3v3(v0, v3, (float[4]){0.0f, 0.0f, 1.0f, 1.0f});
90 }
91
92 void DRW_debug_bbox(const BoundBox *bbox, const float color[4])
93 {
94         DRW_debug_line_v3v3(bbox->vec[0], bbox->vec[1], color);
95         DRW_debug_line_v3v3(bbox->vec[1], bbox->vec[2], color);
96         DRW_debug_line_v3v3(bbox->vec[2], bbox->vec[3], color);
97         DRW_debug_line_v3v3(bbox->vec[3], bbox->vec[0], color);
98
99         DRW_debug_line_v3v3(bbox->vec[4], bbox->vec[5], color);
100         DRW_debug_line_v3v3(bbox->vec[5], bbox->vec[6], color);
101         DRW_debug_line_v3v3(bbox->vec[6], bbox->vec[7], color);
102         DRW_debug_line_v3v3(bbox->vec[7], bbox->vec[4], color);
103
104         DRW_debug_line_v3v3(bbox->vec[0], bbox->vec[4], color);
105         DRW_debug_line_v3v3(bbox->vec[1], bbox->vec[5], color);
106         DRW_debug_line_v3v3(bbox->vec[2], bbox->vec[6], color);
107         DRW_debug_line_v3v3(bbox->vec[3], bbox->vec[7], color);
108 }
109
110 void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert)
111 {
112         BoundBox bb;
113         const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
114         float project_matrix[4][4];
115         if (invert) {
116                 invert_m4_m4(project_matrix, m);
117         }
118         else {
119                 copy_m4_m4(project_matrix, m);
120         }
121
122         BKE_boundbox_init_from_minmax(&bb, min, max);
123         for (int i = 0; i < 8; ++i) {
124                 mul_project_m4_v3(project_matrix, bb.vec[i]);
125         }
126         DRW_debug_bbox(&bb, color);
127 }
128
129 void DRW_debug_sphere(const float center[3], const float radius, const float color[4])
130 {
131         float size_mat[4][4];
132         DRWDebugSphere *sphere = MEM_mallocN(sizeof(DRWDebugSphere), "DRWDebugSphere");
133         /* Bake all transform into a Matrix4 */
134         scale_m4_fl(size_mat, radius);
135         copy_m4_m4(sphere->mat, g_modelmat);
136         translate_m4(sphere->mat, center[0], center[1], center[2]);
137         mul_m4_m4m4(sphere->mat, sphere->mat, size_mat);
138
139         copy_v4_v4(sphere->color, color);
140         BLI_LINKS_PREPEND(DST.debug.spheres, sphere);
141 }
142
143 /* --------- Render --------- */
144
145 static void drw_debug_draw_lines(void)
146 {
147         int count = BLI_linklist_count((LinkNode *)DST.debug.lines);
148
149         if (count == 0) {
150                 return;
151         }
152
153         GPUVertFormat *vert_format = immVertexFormat();
154         uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
155         uint col = GPU_vertformat_attr_add(vert_format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
156
157         immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
158
159         immBegin(GPU_PRIM_LINES, count * 2);
160
161         while (DST.debug.lines) {
162                 void *next = DST.debug.lines->next;
163
164                 immAttr4fv(col, DST.debug.lines->color);
165                 immVertex3fv(pos, DST.debug.lines->pos[0]);
166
167                 immAttr4fv(col, DST.debug.lines->color);
168                 immVertex3fv(pos, DST.debug.lines->pos[1]);
169
170                 MEM_freeN(DST.debug.lines);
171                 DST.debug.lines = next;
172         }
173         immEnd();
174
175         immUnbindProgram();
176 }
177
178 static void drw_debug_draw_spheres(void)
179 {
180         int count = BLI_linklist_count((LinkNode *)DST.debug.spheres);
181
182         if (count == 0) {
183                 return;
184         }
185
186         float one = 1.0f;
187         GPUVertFormat vert_format = {0};
188         uint mat = GPU_vertformat_attr_add(&vert_format, "InstanceModelMatrix", GPU_COMP_F32, 16, GPU_FETCH_FLOAT);
189         uint col = GPU_vertformat_attr_add(&vert_format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
190         uint siz = GPU_vertformat_attr_add(&vert_format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
191
192         GPUVertBuf *inst_vbo = GPU_vertbuf_create_with_format(&vert_format);
193
194         GPU_vertbuf_data_alloc(inst_vbo, count);
195
196         int v = 0;
197         while (DST.debug.spheres) {
198                 void *next = DST.debug.spheres->next;
199
200                 GPU_vertbuf_attr_set(inst_vbo, mat, v, DST.debug.spheres->mat[0]);
201                 GPU_vertbuf_attr_set(inst_vbo, col, v, DST.debug.spheres->color);
202                 GPU_vertbuf_attr_set(inst_vbo, siz, v, &one);
203                 v++;
204
205                 MEM_freeN(DST.debug.spheres);
206                 DST.debug.spheres = next;
207         }
208
209         GPUBatch *empty_sphere = DRW_cache_empty_sphere_get();
210
211         GPUBatch *draw_batch = GPU_batch_create(GPU_PRIM_LINES, empty_sphere->verts[0], NULL);
212         GPU_batch_instbuf_set(draw_batch, inst_vbo, true);
213         GPU_batch_program_set_builtin(draw_batch, GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
214         GPU_batch_uniform_1f(draw_batch, "alpha", 1.0f);
215
216         GPU_batch_draw(draw_batch);
217         GPU_batch_discard(draw_batch);
218 }
219
220 void drw_debug_draw(void)
221 {
222         drw_debug_draw_lines();
223         drw_debug_draw_spheres();
224 }
225
226 void drw_debug_init(void)
227 {
228         DRW_debug_modelmat_reset();
229 }