83287c574415e249b94d7f89b7d860801e77982d
[blender.git] / source / blender / gpu / intern / gpu_batch_presets.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) 2016 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Mike Erwin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_batch_presets.c
29  *  \ingroup gpu
30  */
31
32 #include "BLI_utildefines.h"
33 #include "BLI_math.h"
34 #include "BLI_threads.h"
35 #include "BLI_listbase.h"
36 #include "MEM_guardedalloc.h"
37
38 #include "UI_interface.h"
39
40 #include "GPU_batch.h"
41 #include "GPU_batch_utils.h"
42 #include "GPU_batch_presets.h"  /* own include */
43 #include "gpu_shader_private.h"
44
45 /* Struct to store 3D Batches and their format */
46 static struct {
47         struct {
48                 GPUBatch *sphere_high;
49                 GPUBatch *sphere_med;
50                 GPUBatch *sphere_low;
51                 GPUBatch *sphere_wire_low;
52                 GPUBatch *sphere_wire_med;
53         } batch;
54
55         GPUVertFormat format;
56
57         struct {
58                 uint pos, nor;
59         } attr_id;
60 } g_presets_3d = {{0}};
61
62 static ListBase presets_list = {NULL, NULL};
63
64
65 /* -------------------------------------------------------------------- */
66 /** \name 3D Primitives
67  * \{ */
68
69 static GPUVertFormat *preset_3d_format(void)
70 {
71         if (g_presets_3d.format.attr_len == 0) {
72                 GPUVertFormat *format = &g_presets_3d.format;
73                 g_presets_3d.attr_id.pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
74                 g_presets_3d.attr_id.nor = GPU_vertformat_attr_add(format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
75         }
76         return &g_presets_3d.format;
77 }
78
79 static void batch_sphere_lat_lon_vert(
80         GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step,
81         float lat, float lon)
82 {
83         float pos[3];
84         pos[0] = sinf(lat) * cosf(lon);
85         pos[1] = cosf(lat);
86         pos[2] = sinf(lat) * sinf(lon);
87         copy_v3_v3(GPU_vertbuf_raw_step(pos_step), pos);
88         copy_v3_v3(GPU_vertbuf_raw_step(nor_step), pos);
89 }
90 GPUBatch *GPU_batch_preset_sphere(int lod)
91 {
92         BLI_assert(lod >= 0 && lod <= 2);
93         BLI_assert(BLI_thread_is_main());
94
95         if (lod == 0) {
96                 return g_presets_3d.batch.sphere_low;
97         }
98         else if (lod == 1) {
99                 return g_presets_3d.batch.sphere_med;
100         }
101         else {
102                 return g_presets_3d.batch.sphere_high;
103         }
104 }
105
106 GPUBatch *GPU_batch_preset_sphere_wire(int lod)
107 {
108         BLI_assert(lod >= 0 && lod <= 1);
109         BLI_assert(BLI_thread_is_main());
110
111         if (lod == 0) {
112                 return g_presets_3d.batch.sphere_wire_low;
113         }
114         else {
115                 return g_presets_3d.batch.sphere_wire_med;
116         }
117 }
118
119 /** \} */
120
121 /* -------------------------------------------------------------------- */
122 /** \name Create Sphere (3D)
123  * \{ */
124
125 /* Replacement for gluSphere */
126 GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
127 {
128         const float lon_inc = 2 * M_PI / lon_res;
129         const float lat_inc = M_PI / lat_res;
130         float lon, lat;
131
132         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_3d_format());
133         const uint vbo_len = (lat_res - 1) * lon_res * 6;
134         GPU_vertbuf_data_alloc(vbo, vbo_len);
135
136         GPUVertBufRaw pos_step, nor_step;
137         GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step);
138         GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step);
139
140         lon = 0.0f;
141         for (int i = 0; i < lon_res; i++, lon += lon_inc) {
142                 lat = 0.0f;
143                 for (int j = 0; j < lat_res; j++, lat += lat_inc) {
144                         if (j != lat_res - 1) { /* Pole */
145                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
146                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
147                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat,           lon);
148                         }
149
150                         if (j != 0) { /* Pole */
151                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat,           lon + lon_inc);
152                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
153                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat,           lon);
154                         }
155                 }
156         }
157
158         BLI_assert(vbo_len == GPU_vertbuf_raw_used(&pos_step));
159         BLI_assert(vbo_len == GPU_vertbuf_raw_used(&nor_step));
160
161         return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
162 }
163
164 static GPUBatch *batch_sphere_wire(int lat_res, int lon_res)
165 {
166         const float lon_inc = 2 * M_PI / lon_res;
167         const float lat_inc = M_PI / lat_res;
168         float lon, lat;
169
170         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_3d_format());
171         const uint vbo_len = (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2);
172         GPU_vertbuf_data_alloc(vbo, vbo_len);
173
174         GPUVertBufRaw pos_step, nor_step;
175         GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step);
176         GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step);
177
178         lon = 0.0f;
179         for (int i = 0; i < lon_res; i++, lon += lon_inc) {
180                 lat = 0.0f;
181                 for (int j = 0; j < lat_res; j++, lat += lat_inc) {
182                         batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
183                         batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat,           lon);
184
185                         if (j != lat_res - 1) { /* Pole */
186                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
187                                 batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
188                         }
189                 }
190         }
191
192         BLI_assert(vbo_len == GPU_vertbuf_raw_used(&pos_step));
193         BLI_assert(vbo_len == GPU_vertbuf_raw_used(&nor_step));
194
195         return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
196 }
197
198 /** \} */
199
200 void gpu_batch_presets_init(void)
201 {
202         /* Hard coded resolution */
203         g_presets_3d.batch.sphere_low = gpu_batch_sphere(8, 16);
204         gpu_batch_presets_register(g_presets_3d.batch.sphere_low);
205
206         g_presets_3d.batch.sphere_med = gpu_batch_sphere(16, 10);
207         gpu_batch_presets_register(g_presets_3d.batch.sphere_med);
208
209         g_presets_3d.batch.sphere_high = gpu_batch_sphere(32, 24);
210         gpu_batch_presets_register(g_presets_3d.batch.sphere_high);
211
212         g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8);
213         gpu_batch_presets_register(g_presets_3d.batch.sphere_wire_low);
214
215         g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16);
216         gpu_batch_presets_register(g_presets_3d.batch.sphere_wire_med);
217 }
218
219 void gpu_batch_presets_register(GPUBatch *preset_batch)
220 {
221         BLI_addtail(&presets_list, BLI_genericNodeN(preset_batch));
222 }
223
224 void gpu_batch_presets_reset(void)
225 {
226         /* Reset vao caches for these every time we switch opengl context.
227          * This way they will draw correctly for each window. */
228         LinkData *link = presets_list.first;
229         for (link = presets_list.first; link; link = link->next) {
230                 GPUBatch *preset = link->data;
231                 GPU_batch_vao_cache_clear(preset);
232         }
233 }
234
235 void gpu_batch_presets_exit(void)
236 {
237         LinkData *link;
238         while ((link = BLI_pophead(&presets_list))) {
239                 GPUBatch *preset = link->data;
240                 GPU_batch_discard(preset);
241                 MEM_freeN(link);
242         }
243 }