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