Revert "Cleanup: remove image->bindcode, always wrap in GPUTexture."
[blender.git] / source / blender / gpu / intern / gpu_draw.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) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_draw.c
29  *  \ingroup gpu
30  *
31  * Utility functions for dealing with OpenGL texture & material context,
32  * mipmap generation and light objects.
33  *
34  * These are some obscure rendering functions shared between the game engine (not anymore)
35  * and the blender, in this module to avoid duplication
36  * and abstract them away from the rest a bit.
37  */
38
39 #include <string.h>
40
41 #include "BLI_blenlib.h"
42 #include "BLI_hash.h"
43 #include "BLI_linklist.h"
44 #include "BLI_math.h"
45 #include "BLI_threads.h"
46 #include "BLI_utildefines.h"
47
48 #include "DNA_lamp_types.h"
49 #include "DNA_material_types.h"
50 #include "DNA_mesh_types.h"
51 #include "DNA_meshdata_types.h"
52 #include "DNA_modifier_types.h"
53 #include "DNA_node_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_smoke_types.h"
57 #include "DNA_view3d_types.h"
58 #include "DNA_particle_types.h"
59
60 #include "MEM_guardedalloc.h"
61
62 #include "IMB_imbuf.h"
63 #include "IMB_imbuf_types.h"
64
65 #include "BKE_bmfont.h"
66 #include "BKE_global.h"
67 #include "BKE_image.h"
68 #include "BKE_main.h"
69 #include "BKE_material.h"
70 #include "BKE_node.h"
71 #include "BKE_scene.h"
72 #include "BKE_DerivedMesh.h"
73
74 #include "GPU_basic_shader.h"
75 #include "GPU_draw.h"
76 #include "GPU_extensions.h"
77 #include "GPU_material.h"
78 #include "GPU_matrix.h"
79 #include "GPU_shader.h"
80 #include "GPU_texture.h"
81
82 #include "PIL_time.h"
83
84 #ifdef WITH_SMOKE
85 #  include "smoke_API.h"
86 #endif
87
88 #ifdef WITH_OPENSUBDIV
89 #  include "BKE_subsurf.h"
90 #  include "BKE_editmesh.h"
91
92 #  include "gpu_codegen.h"
93 #endif
94
95 extern Material defmaterial; /* from material.c */
96
97 //* Checking powers of two for images since OpenGL ES requires it */
98 #ifdef WITH_DDS
99 static bool is_power_of_2_resolution(int w, int h)
100 {
101         return is_power_of_2_i(w) && is_power_of_2_i(h);
102 }
103 #endif
104
105 static bool is_over_resolution_limit(GLenum textarget, int w, int h)
106 {
107         int size = (textarget == GL_TEXTURE_2D) ?
108                 GPU_max_texture_size() : GPU_max_cube_map_size();
109         int reslimit = (U.glreslimit != 0) ?
110             min_ii(U.glreslimit, size) : size;
111
112         return (w > reslimit || h > reslimit);
113 }
114
115 static int smaller_power_of_2_limit(int num)
116 {
117         int reslimit = (U.glreslimit != 0) ?
118                 min_ii(U.glreslimit, GPU_max_texture_size()) :
119                 GPU_max_texture_size();
120         /* take texture clamping into account */
121         if (num > reslimit)
122                 return reslimit;
123
124         return power_of_2_min_i(num);
125 }
126
127 /* Current OpenGL state caching for GPU_set_tpage */
128
129 static struct GPUTextureState {
130         Image *ima, *curima;
131
132         /* also controls min/mag filtering */
133         bool domipmap;
134         /* only use when 'domipmap' is set */
135         bool linearmipmap;
136         /* store this so that new images created while texture painting won't be set to mipmapped */
137         bool texpaint;
138
139         int alphablend;
140         float anisotropic;
141         int gpu_mipmap;
142 } GTS = {NULL, NULL, 1, 0, 0, -1, 1.0f, 0};
143
144 /* Mipmap settings */
145
146 void GPU_set_gpu_mipmapping(int gpu_mipmap)
147 {
148         int old_value = GTS.gpu_mipmap;
149
150         /* only actually enable if it's supported */
151         GTS.gpu_mipmap = gpu_mipmap;
152
153         if (old_value != GTS.gpu_mipmap) {
154                 GPU_free_images();
155         }
156 }
157
158 void GPU_set_mipmap(bool mipmap)
159 {
160         if (GTS.domipmap != mipmap) {
161                 GPU_free_images();
162                 GTS.domipmap = mipmap;
163         }
164 }
165
166 void GPU_set_linear_mipmap(bool linear)
167 {
168         if (GTS.linearmipmap != linear) {
169                 GTS.linearmipmap = linear;
170         }
171 }
172
173 bool GPU_get_mipmap(void)
174 {
175         return GTS.domipmap && !GTS.texpaint;
176 }
177
178 bool GPU_get_linear_mipmap(void)
179 {
180         return GTS.linearmipmap;
181 }
182
183 static GLenum gpu_get_mipmap_filter(bool mag)
184 {
185         /* linearmipmap is off by default *when mipmapping is off,
186          * use unfiltered display */
187         if (mag) {
188                 if (GTS.domipmap)
189                         return GL_LINEAR;
190                 else
191                         return GL_NEAREST;
192         }
193         else {
194                 if (GTS.domipmap) {
195                         if (GTS.linearmipmap) {
196                                 return GL_LINEAR_MIPMAP_LINEAR;
197                         }
198                         else {
199                                 return GL_LINEAR_MIPMAP_NEAREST;
200                         }
201                 }
202                 else {
203                         return GL_NEAREST;
204                 }
205         }
206 }
207
208 /* Anisotropic filtering settings */
209 void GPU_set_anisotropic(float value)
210 {
211         if (GTS.anisotropic != value) {
212                 GPU_free_images();
213
214                 /* Clamp value to the maximum value the graphics card supports */
215                 const float max = GPU_max_texture_anisotropy();
216                 if (value > max)
217                         value = max;
218
219                 GTS.anisotropic = value;
220         }
221 }
222
223 float GPU_get_anisotropic(void)
224 {
225         return GTS.anisotropic;
226 }
227
228 /* Set OpenGL state for an MTFace */
229
230 static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget)
231 {
232         unsigned int *bind = 0;
233
234         if (textarget == GL_TEXTURE_2D)
235                 bind = &ima->bindcode[TEXTARGET_TEXTURE_2D];
236         else if (textarget == GL_TEXTURE_CUBE_MAP)
237                 bind = &ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP];
238
239         return bind;
240 }
241
242 typedef struct VerifyThreadData {
243         ImBuf *ibuf;
244         float *srgb_frect;
245 } VerifyThreadData;
246
247 static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
248                                                   ImBuf *ibuf,
249                                                   const int start_line,
250                                                   const int height)
251 {
252         size_t offset = ibuf->channels * start_line * ibuf->x;
253         float *current_srgb_frect = srgb_frect + offset;
254         float *current_rect_float = ibuf->rect_float + offset;
255         IMB_buffer_float_from_float(current_srgb_frect,
256                                     current_rect_float,
257                                     ibuf->channels,
258                                     IB_PROFILE_SRGB,
259                                     IB_PROFILE_LINEAR_RGB, true,
260                                     ibuf->x, height,
261                                     ibuf->x, ibuf->x);
262         IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
263 }
264
265 static void verify_thread_do(void *data_v,
266                              int start_scanline,
267                              int num_scanlines)
268 {
269         VerifyThreadData *data = (VerifyThreadData *)data_v;
270         gpu_verify_high_bit_srgb_buffer_slice(data->srgb_frect,
271                                               data->ibuf,
272                                               start_scanline,
273                                               num_scanlines);
274 }
275
276 static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
277                                             ImBuf *ibuf)
278 {
279         if (ibuf->y < 64) {
280                 gpu_verify_high_bit_srgb_buffer_slice(srgb_frect,
281                                                       ibuf,
282                                                       0, ibuf->y);
283         }
284         else {
285                 VerifyThreadData data;
286                 data.ibuf = ibuf;
287                 data.srgb_frect = srgb_frect;
288                 IMB_processor_apply_threaded_scanlines(ibuf->y, verify_thread_do, &data);
289         }
290 }
291
292 int GPU_verify_image(
293         Image *ima, ImageUser *iuser,
294         int textarget, bool compare, bool mipmap, bool is_data)
295 {
296         unsigned int *bind = NULL;
297         int tpx = 0, tpy = 0;
298         unsigned int *rect = NULL;
299         float *frect = NULL;
300         float *srgb_frect = NULL;
301         /* flag to determine whether deep format is used */
302         bool use_high_bit_depth = false, do_color_management = false;
303
304         GTS.ima = ima;
305
306         if (compare && ima == GTS.curima) {
307                 return (ima != NULL);
308         }
309
310         /* check if we have a valid image */
311         if (ima == NULL || ima->ok == 0)
312                 return 0;
313
314         /* check if we have a valid image buffer */
315         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
316
317         if (ibuf == NULL)
318                 return 0;
319
320         if (ibuf->rect_float) {
321                 if (U.use_16bit_textures) {
322                         /* use high precision textures. This is relatively harmless because OpenGL gives us
323                          * a high precision format only if it is available */
324                         use_high_bit_depth = true;
325                 }
326                 else if (ibuf->rect == NULL) {
327                         IMB_rect_from_float(ibuf);
328                 }
329                 /* we may skip this in high precision, but if not, we need to have a valid buffer here */
330                 else if (ibuf->userflags & IB_RECT_INVALID) {
331                         IMB_rect_from_float(ibuf);
332                 }
333
334                 /* TODO unneeded when float images are correctly treated as linear always */
335                 if (!is_data) {
336                         do_color_management = true;
337                 }
338         }
339
340         /* currently, tpage refresh is used by ima sequences */
341         if (ima->tpageflag & IMA_TPAGE_REFRESH) {
342                 GPU_free_image(ima);
343                 ima->tpageflag &= ~IMA_TPAGE_REFRESH;
344         }
345
346         {
347                 /* regular image mode */
348                 bind = gpu_get_image_bindcode(ima, textarget);
349
350                 if (*bind == 0) {
351                         tpx = ibuf->x;
352                         tpy = ibuf->y;
353                         rect = ibuf->rect;
354                         if (use_high_bit_depth) {
355                                 if (do_color_management) {
356                                         frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
357                                         gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
358                                 }
359                                 else
360                                         frect = ibuf->rect_float;
361                         }
362                 }
363         }
364
365         if (*bind != 0) {
366                 /* enable opengl drawing with textures */
367                 glBindTexture(textarget, *bind);
368                 BKE_image_release_ibuf(ima, ibuf, NULL);
369                 return *bind;
370         }
371
372         const int rectw = tpx;
373         const int recth = tpy;
374
375 #ifdef WITH_DDS
376         if (ibuf->ftype == IMB_FTYPE_DDS)
377                 GPU_create_gl_tex_compressed(bind, rect, rectw, recth, textarget, mipmap, ima, ibuf);
378         else
379 #endif
380                 GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
381
382         /* mark as non-color data texture */
383         if (*bind) {
384                 if (is_data)
385                         ima->tpageflag |= IMA_GLBIND_IS_DATA;
386                 else
387                         ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
388         }
389
390         /* clean up */
391         if (srgb_frect)
392                 MEM_freeN(srgb_frect);
393
394         BKE_image_release_ibuf(ima, ibuf, NULL);
395
396         return *bind;
397 }
398
399 static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
400 {
401         size_t block_size = use_high_bit_depth ? sizeof(float) * 4 : sizeof(unsigned char) * 4;
402         void **sides = NULL;
403         int h = recth / 2;
404         int w = rectw / 3;
405
406         if ((use_high_bit_depth && frect == NULL) || (!use_high_bit_depth && rect == NULL) || w != h)
407                 return sides;
408
409         /* PosX, NegX, PosY, NegY, PosZ, NegZ */
410         sides = MEM_mallocN(sizeof(void *) * 6, "");
411         for (int i = 0; i < 6; i++)
412                 sides[i] = MEM_mallocN(block_size * w * h, "");
413
414         /* divide image into six parts */
415         /* ______________________
416          * |      |      |      |
417          * | NegX | NegY | PosX |
418          * |______|______|______|
419          * |      |      |      |
420          * | NegZ | PosZ | PosY |
421          * |______|______|______|
422          */
423         if (use_high_bit_depth) {
424                 float (*frectb)[4] = (float(*)[4])frect;
425                 float (**fsides)[4] = (float(**)[4])sides;
426
427                 for (int y = 0; y < h; y++) {
428                         for (int x = 0; x < w; x++) {
429                                 memcpy(&fsides[0][x * h + y], &frectb[(recth - y - 1) * rectw + 2 * w + x], block_size);
430                                 memcpy(&fsides[1][x * h + y], &frectb[(y + h) * rectw + w - 1 - x], block_size);
431                                 memcpy(&fsides[3][y * w + x], &frectb[(recth - y - 1) * rectw + 2 * w - 1 - x], block_size);
432                                 memcpy(&fsides[5][y * w + x], &frectb[(h - y - 1) * rectw + w - 1 - x], block_size);
433                         }
434                         memcpy(&fsides[2][y * w], frectb[y * rectw + 2 * w], block_size * w);
435                         memcpy(&fsides[4][y * w], frectb[y * rectw + w], block_size * w);
436                 }
437         }
438         else {
439                 unsigned int **isides = (unsigned int **)sides;
440
441                 for (int y = 0; y < h; y++) {
442                         for (int x = 0; x < w; x++) {
443                                 isides[0][x * h + y] = rect[(recth - y - 1) * rectw + 2 * w + x];
444                                 isides[1][x * h + y] = rect[(y + h) * rectw + w - 1 - x];
445                                 isides[3][y * w + x] = rect[(recth - y - 1) * rectw + 2 * w - 1 - x];
446                                 isides[5][y * w + x] = rect[(h - y - 1) * rectw + w - 1 - x];
447                         }
448                         memcpy(&isides[2][y * w], &rect[y * rectw + 2 * w], block_size * w);
449                         memcpy(&isides[4][y * w], &rect[y * rectw + w], block_size * w);
450                 }
451         }
452
453         return sides;
454 }
455
456 static void gpu_del_cube_map(void **cube_map)
457 {
458         int i;
459         if (cube_map == NULL)
460                 return;
461         for (i = 0; i < 6; i++)
462                 MEM_freeN(cube_map[i]);
463         MEM_freeN(cube_map);
464 }
465
466 /* Image *ima can be NULL */
467 void GPU_create_gl_tex(
468         unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
469         int textarget, bool mipmap, bool use_high_bit_depth, Image *ima)
470 {
471         ImBuf *ibuf = NULL;
472
473         int tpx = rectw;
474         int tpy = recth;
475
476         /* create image */
477         glGenTextures(1, (GLuint *)bind);
478         glBindTexture(textarget, *bind);
479
480         if (textarget == GL_TEXTURE_2D) {
481                 if (use_high_bit_depth) {
482                         if (GLEW_ARB_texture_float)
483                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
484                         else
485                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
486                 }
487                 else
488                         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
489
490                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
491
492                 if (GPU_get_mipmap() && mipmap) {
493                         if (GTS.gpu_mipmap) {
494                                 glGenerateMipmap(GL_TEXTURE_2D);
495                         }
496                         else {
497                                 int i;
498                                 if (!ibuf) {
499                                         if (use_high_bit_depth) {
500                                                 ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
501                                         }
502                                         else {
503                                                 ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
504                                         }
505                                 }
506                                 IMB_makemipmap(ibuf, true);
507
508                                 for (i = 1; i < ibuf->miptot; i++) {
509                                         ImBuf *mip = ibuf->mipmap[i - 1];
510                                         if (use_high_bit_depth) {
511                                                 if (GLEW_ARB_texture_float)
512                                                         glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
513                                                 else
514                                                         glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
515                                         }
516                                         else {
517                                                 glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
518                                         }
519                                 }
520                         }
521                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
522                         if (ima)
523                                 ima->tpageflag |= IMA_MIPMAP_COMPLETE;
524                 }
525                 else {
526                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
527                 }
528         }
529         else if (textarget == GL_TEXTURE_CUBE_MAP) {
530                 int w = rectw / 3, h = recth / 2;
531
532                 if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
533                         void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth);
534                         GLenum informat = use_high_bit_depth ? (GLEW_ARB_texture_float ? GL_RGBA16F : GL_RGBA16) : GL_RGBA8;
535                         GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE;
536
537                         if (cube_map)
538                                 for (int i = 0; i < 6; i++)
539                                         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, informat, w, h, 0, GL_RGBA, type, cube_map[i]);
540
541                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
542
543                         if (GPU_get_mipmap() && mipmap) {
544                                 if (GTS.gpu_mipmap) {
545                                         glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
546                                 }
547                                 else {
548                                         if (!ibuf) {
549                                                 if (use_high_bit_depth) {
550                                                         ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
551                                                 }
552                                                 else {
553                                                         ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
554                                                 }
555                                         }
556
557                                         IMB_makemipmap(ibuf, true);
558
559                                         for (int i = 1; i < ibuf->miptot; i++) {
560                                                 ImBuf *mip = ibuf->mipmap[i - 1];
561                                                 void **mip_cube_map = gpu_gen_cube_map(
562                                                         mip->rect, mip->rect_float,
563                                                         mip->x, mip->y, use_high_bit_depth);
564                                                 int mipw = mip->x / 3, miph = mip->y / 2;
565
566                                                 if (mip_cube_map) {
567                                                         for (int j = 0; j < 6; j++) {
568                                                                 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
569                                                                     informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
570                                                         }
571                                                 }
572                                                 gpu_del_cube_map(mip_cube_map);
573                                         }
574                                 }
575                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
576
577                                 if (ima)
578                                         ima->tpageflag |= IMA_MIPMAP_COMPLETE;
579                         }
580                         else {
581                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
582                         }
583                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
584                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
585                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
586
587                         gpu_del_cube_map(cube_map);
588                 }
589                 else {
590                         printf("Incorrect envmap size\n");
591                 }
592         }
593
594         if (GLEW_EXT_texture_filter_anisotropic)
595                 glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
596
597         if (ibuf)
598                 IMB_freeImBuf(ibuf);
599 }
600
601 /**
602  * GPU_upload_dxt_texture() assumes that the texture is already bound and ready to go.
603  * This is so the viewport and the BGE can share some code.
604  * Returns false if the provided ImBuf doesn't have a supported DXT compression format
605  */
606 bool GPU_upload_dxt_texture(ImBuf *ibuf)
607 {
608 #ifdef WITH_DDS
609         GLint format = 0;
610         int blocksize, height, width, i, size, offset = 0;
611
612         width = ibuf->x;
613         height = ibuf->y;
614
615         if (GLEW_EXT_texture_compression_s3tc) {
616                 if (ibuf->dds_data.fourcc == FOURCC_DXT1)
617                         format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
618                 else if (ibuf->dds_data.fourcc == FOURCC_DXT3)
619                         format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
620                 else if (ibuf->dds_data.fourcc == FOURCC_DXT5)
621                         format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
622         }
623
624         if (format == 0) {
625                 fprintf(stderr, "Unable to find a suitable DXT compression, falling back to uncompressed\n");
626                 return false;
627         }
628
629         if (!is_power_of_2_resolution(width, height)) {
630                 fprintf(stderr, "Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n");
631                 return false;
632         }
633
634         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
635         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
636
637         if (GLEW_EXT_texture_filter_anisotropic)
638                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
639
640         blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
641         for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); ++i) {
642                 if (width == 0)
643                         width = 1;
644                 if (height == 0)
645                         height = 1;
646
647                 size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
648
649                 glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
650                     0, size, ibuf->dds_data.data + offset);
651
652                 offset += size;
653                 width >>= 1;
654                 height >>= 1;
655         }
656
657         /* set number of mipmap levels we have, needed in case they don't go down to 1x1 */
658         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
659
660         return true;
661 #else
662         (void)ibuf;
663         return false;
664 #endif
665 }
666
667 void GPU_create_gl_tex_compressed(
668         unsigned int *bind, unsigned int *pix, int x, int y,
669         int textarget, int mipmap, Image *ima, ImBuf *ibuf)
670 {
671 #ifndef WITH_DDS
672         (void)ibuf;
673         /* Fall back to uncompressed if DDS isn't enabled */
674         GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
675 #else
676         glGenTextures(1, (GLuint *)bind);
677         glBindTexture(textarget, *bind);
678
679         if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf) == 0) {
680                 glDeleteTextures(1, (GLuint *)bind);
681                 GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
682         }
683 #endif
684 }
685
686 /* these two functions are called on entering and exiting texture paint mode,
687  * temporary disabling/enabling mipmapping on all images for quick texture
688  * updates with glTexSubImage2D. images that didn't change don't have to be
689  * re-uploaded to OpenGL */
690 void GPU_paint_set_mipmap(bool mipmap)
691 {
692         if (!GTS.domipmap)
693                 return;
694
695         GTS.texpaint = !mipmap;
696
697         if (mipmap) {
698                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
699                         if (BKE_image_has_bindcode(ima)) {
700                                 if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
701                                         if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
702                                                 glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
703                                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
704                                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
705                                         }
706                                         if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
707                                                 glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
708                                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
709                                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
710                                         }
711                                 }
712                                 else
713                                         GPU_free_image(ima);
714                         }
715                         else
716                                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
717                 }
718
719         }
720         else {
721                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
722                         if (BKE_image_has_bindcode(ima)) {
723                                 if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
724                                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
725                                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
726                                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
727                                 }
728                                 if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
729                                         glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
730                                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
731                                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
732                                 }
733                         }
734                         else
735                                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
736                 }
737         }
738 }
739
740
741 /* check if image has been downscaled and do scaled partial update */
742 static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
743 {
744         if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
745                 int x_limit = smaller_power_of_2_limit(ibuf->x);
746                 int y_limit = smaller_power_of_2_limit(ibuf->y);
747
748                 float xratio = x_limit / (float)ibuf->x;
749                 float yratio = y_limit / (float)ibuf->y;
750
751                 /* find new width, height and x,y gpu texture coordinates */
752
753                 /* take ceiling because we will be losing 1 pixel due to rounding errors in x,y... */
754                 int rectw = (int)ceil(xratio * w);
755                 int recth = (int)ceil(yratio * h);
756
757                 x *= xratio;
758                 y *= yratio;
759
760                 /* ...but take back if we are over the limit! */
761                 if (rectw + x > x_limit) rectw--;
762                 if (recth + y > y_limit) recth--;
763
764                 /* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */
765                 if (frect) {
766                         ImBuf *ibuf_scale = IMB_allocFromBuffer(NULL, frect, w, h);
767                         IMB_scaleImBuf(ibuf_scale, rectw, recth);
768
769                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
770                         glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
771                                         GL_FLOAT, ibuf_scale->rect_float);
772
773                         IMB_freeImBuf(ibuf_scale);
774                 }
775                 /* byte images are not continuous in memory so do manual interpolation */
776                 else {
777                         unsigned char *scalerect = MEM_mallocN(rectw * recth * sizeof(*scalerect) * 4, "scalerect");
778                         unsigned int *p = (unsigned int *)scalerect;
779                         int i, j;
780                         float inv_xratio = 1.0f / xratio;
781                         float inv_yratio = 1.0f / yratio;
782                         for (i = 0; i < rectw; i++) {
783                                 float u = (x + i) * inv_xratio;
784                                 for (j = 0; j < recth; j++) {
785                                         float v = (y + j) * inv_yratio;
786                                         bilinear_interpolation_color_wrap(ibuf, (unsigned char *)(p + i + j * (rectw)), NULL, u, v);
787                                 }
788                         }
789                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
790                         glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
791                                         GL_UNSIGNED_BYTE, scalerect);
792
793                         MEM_freeN(scalerect);
794                 }
795
796                 if (GPU_get_mipmap()) {
797                         glGenerateMipmap(GL_TEXTURE_2D);
798                 }
799                 else {
800                         ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
801                 }
802
803                 return true;
804         }
805
806         return false;
807 }
808
809 void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
810 {
811         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
812
813         if ((!GTS.gpu_mipmap && GPU_get_mipmap()) ||
814             (ima->bindcode[TEXTARGET_TEXTURE_2D] == 0) ||
815             (ibuf == NULL) ||
816             (w == 0) || (h == 0))
817         {
818                 /* these cases require full reload still */
819                 GPU_free_image(ima);
820         }
821         else {
822                 /* for the special case, we can do a partial update
823                  * which is much quicker for painting */
824                 GLint row_length, skip_pixels, skip_rows;
825
826                 /* if color correction is needed, we must update the part that needs updating. */
827                 if (ibuf->rect_float) {
828                         float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
829                         bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
830                         IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
831
832                         if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
833                                 MEM_freeN(buffer);
834                                 BKE_image_release_ibuf(ima, ibuf, NULL);
835                                 return;
836                         }
837
838                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
839                         glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
840
841                         MEM_freeN(buffer);
842
843                         /* we have already accounted for the case where GTS.gpu_mipmap is false
844                          * so we will be using GPU mipmap generation here */
845                         if (GPU_get_mipmap()) {
846                                 glGenerateMipmap(GL_TEXTURE_2D);
847                         }
848                         else {
849                                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
850                         }
851
852                         BKE_image_release_ibuf(ima, ibuf, NULL);
853                         return;
854                 }
855
856                 if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
857                         BKE_image_release_ibuf(ima, ibuf, NULL);
858                         return;
859                 }
860
861                 glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
862
863                 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
864                 glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
865                 glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
866
867                 glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
868                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
869                 glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
870
871                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
872                     GL_UNSIGNED_BYTE, ibuf->rect);
873
874                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
875                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
876                 glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
877
878                 /* see comment above as to why we are using gpu mipmap generation here */
879                 if (GPU_get_mipmap()) {
880                         glGenerateMipmap(GL_TEXTURE_2D);
881                 }
882                 else {
883                         ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
884                 }
885         }
886
887         BKE_image_release_ibuf(ima, ibuf, NULL);
888 }
889
890 void GPU_free_smoke(SmokeModifierData *smd)
891 {
892         if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
893                 if (smd->domain->tex)
894                         GPU_texture_free(smd->domain->tex);
895                 smd->domain->tex = NULL;
896
897                 if (smd->domain->tex_shadow)
898                         GPU_texture_free(smd->domain->tex_shadow);
899                 smd->domain->tex_shadow = NULL;
900
901                 if (smd->domain->tex_flame)
902                         GPU_texture_free(smd->domain->tex_flame);
903                 smd->domain->tex_flame = NULL;
904         }
905 }
906
907 void GPU_create_smoke(SmokeModifierData *smd, int highres)
908 {
909 #ifdef WITH_SMOKE
910         if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
911                 SmokeDomainSettings *sds = smd->domain;
912                 if (!sds->tex && !highres) {
913                         /* rgba texture for color + density */
914                         if (smoke_has_colors(sds->fluid)) {
915                                 float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
916                                 smoke_get_rgba(sds->fluid, data, 0);
917                                 sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_RGBA8, data, NULL);
918                                 MEM_freeN(data);
919                         }
920                         /* density only */
921                         else {
922                                 sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2],
923                                                                  GPU_R8, smoke_get_density(sds->fluid), NULL);
924
925                                 /* Swizzle the RGBA components to read the Red channel so
926                                  * that the shader stay the same for colored and non color
927                                  * density textures. */
928                                 GPU_texture_bind(sds->tex, 0);
929                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
930                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
931                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
932                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
933                                 GPU_texture_unbind(sds->tex);
934                         }
935                         sds->tex_flame = (smoke_has_fuel(sds->fluid)) ?
936                                           GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2],
937                                           GPU_R8, smoke_get_flame(sds->fluid), NULL) :
938                                           NULL;
939                 }
940                 else if (!sds->tex && highres) {
941                         /* rgba texture for color + density */
942                         if (smoke_turbulence_has_colors(sds->wt)) {
943                                 float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
944                                 smoke_turbulence_get_rgba(sds->wt, data, 0);
945                                 sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], GPU_RGBA8, data, NULL);
946                                 MEM_freeN(data);
947                         }
948                         /* density only */
949                         else {
950                                 sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2],
951                                                                         GPU_R8, smoke_turbulence_get_density(sds->wt), NULL);
952
953                                 /* Swizzle the RGBA components to read the Red channel so
954                                  * that the shader stay the same for colored and non color
955                                  * density textures. */
956                                 GPU_texture_bind(sds->tex, 0);
957                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
958                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
959                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
960                                 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
961                                 GPU_texture_unbind(sds->tex);
962                         }
963                         sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ?
964                                           GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2],
965                                                                        GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) :
966                                           NULL;
967                 }
968
969                 sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2],
970                                                         GPU_R8, sds->shadow, NULL);
971         }
972 #else // WITH_SMOKE
973         (void)highres;
974         smd->domain->tex = NULL;
975         smd->domain->tex_flame = NULL;
976         smd->domain->tex_shadow = NULL;
977 #endif // WITH_SMOKE
978 }
979
980 static LinkNode *image_free_queue = NULL;
981
982 static void gpu_queue_image_for_free(Image *ima)
983 {
984         BLI_thread_lock(LOCK_OPENGL);
985         BLI_linklist_prepend(&image_free_queue, ima);
986         BLI_thread_unlock(LOCK_OPENGL);
987 }
988
989 void GPU_free_unused_buffers(void)
990 {
991         if (!BLI_thread_is_main())
992                 return;
993
994         BLI_thread_lock(LOCK_OPENGL);
995
996         /* images */
997         for (LinkNode *node = image_free_queue; node; node = node->next) {
998                 Image *ima = node->link;
999
1000                 /* check in case it was freed in the meantime */
1001                 if (G.main && BLI_findindex(&G.main->image, ima) != -1)
1002                         GPU_free_image(ima);
1003         }
1004
1005         BLI_linklist_free(image_free_queue, NULL);
1006         image_free_queue = NULL;
1007
1008         BLI_thread_unlock(LOCK_OPENGL);
1009 }
1010
1011 void GPU_free_image(Image *ima)
1012 {
1013         if (!BLI_thread_is_main()) {
1014                 gpu_queue_image_for_free(ima);
1015                 return;
1016         }
1017
1018         for (int i = 0; i < TEXTARGET_COUNT; i++) {
1019                 /* free regular image binding */
1020                 if (ima->bindcode[i]) {
1021                         glDeleteTextures(1, (GLuint *)&ima->bindcode[i]);
1022                         ima->bindcode[i] = 0;
1023                 }
1024                 /* free glsl image binding */
1025                 if (ima->gputexture[i]) {
1026                         GPU_texture_free(ima->gputexture[i]);
1027                         ima->gputexture[i] = NULL;
1028                 }
1029         }
1030
1031         ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE | IMA_GLBIND_IS_DATA);
1032 }
1033
1034 void GPU_free_images(void)
1035 {
1036         if (G.main)
1037                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next)
1038                         GPU_free_image(ima);
1039 }
1040
1041 /* same as above but only free animated images */
1042 void GPU_free_images_anim(void)
1043 {
1044         if (G.main)
1045                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next)
1046                         if (BKE_image_is_animated(ima))
1047                                 GPU_free_image(ima);
1048 }
1049
1050
1051 void GPU_free_images_old(void)
1052 {
1053         static int lasttime = 0;
1054         int ctime = (int)PIL_check_seconds_timer();
1055
1056         /*
1057          * Run garbage collector once for every collecting period of time
1058          * if textimeout is 0, that's the option to NOT run the collector
1059          */
1060         if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime)
1061                 return;
1062
1063         /* of course not! */
1064         if (G.is_rendering)
1065                 return;
1066
1067         lasttime = ctime;
1068
1069         Image *ima = G.main->image.first;
1070         while (ima) {
1071                 if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
1072                         /* If it's in GL memory, deallocate and set time tag to current time
1073                          * This gives textures a "second chance" to be used before dying. */
1074                         if (BKE_image_has_bindcode(ima)) {
1075                                 GPU_free_image(ima);
1076                                 ima->lastused = ctime;
1077                         }
1078                         /* Otherwise, just kill the buffers */
1079                         else {
1080                                 BKE_image_free_buffers(ima);
1081                         }
1082                 }
1083                 ima = ima->id.next;
1084         }
1085 }
1086
1087 static void gpu_disable_multisample(void)
1088 {
1089 #ifdef __linux__
1090         /* changing multisample from the default (enabled) causes problems on some
1091          * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */
1092         bool toggle_ok = true;
1093
1094         if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
1095                 int samples = 0;
1096                 glGetIntegerv(GL_SAMPLES, &samples);
1097
1098                 if (samples == 0)
1099                         toggle_ok = false;
1100         }
1101
1102         if (toggle_ok) {
1103                 glDisable(GL_MULTISAMPLE);
1104         }
1105 #else
1106         glDisable(GL_MULTISAMPLE);
1107 #endif
1108 }
1109
1110 /* Default OpenGL State
1111  *
1112  * This is called on startup, for opengl offscreen render.
1113  * Generally we should always return to this state when
1114  * temporarily modifying the state for drawing, though that are (undocumented)
1115  * exceptions that we should try to get rid of. */
1116
1117 void GPU_state_init(void)
1118 {
1119         GPU_disable_program_point_size();
1120
1121         glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
1122
1123         glDepthFunc(GL_LEQUAL);
1124
1125         glDisable(GL_BLEND);
1126         glDisable(GL_DEPTH_TEST);
1127         glDisable(GL_COLOR_LOGIC_OP);
1128         glDisable(GL_STENCIL_TEST);
1129
1130         glDepthRange(0.0, 1.0);
1131
1132         glFrontFace(GL_CCW);
1133         glCullFace(GL_BACK);
1134         glDisable(GL_CULL_FACE);
1135
1136         gpu_disable_multisample();
1137 }
1138
1139 void GPU_enable_program_point_size(void)
1140 {
1141         glEnable(GL_PROGRAM_POINT_SIZE);
1142 }
1143
1144 void GPU_disable_program_point_size(void)
1145 {
1146         glDisable(GL_PROGRAM_POINT_SIZE);
1147 }
1148
1149 /** \name Framebuffer color depth, for selection codes
1150  * \{ */
1151
1152 #ifdef __APPLE__
1153
1154 /* apple seems to round colors to below and up on some configs */
1155
1156 static unsigned int index_to_framebuffer(int index)
1157 {
1158         unsigned int i = index;
1159
1160         switch (GPU_color_depth()) {
1161                 case 12:
1162                         i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
1163                         /* sometimes dithering subtracts! */
1164                         i |= 0x070707;
1165                         break;
1166                 case 15:
1167                 case 16:
1168                         i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
1169                         i |= 0x030303;
1170                         break;
1171                 case 24:
1172                         break;
1173                 default: /* 18 bits... */
1174                         i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
1175                         i |= 0x010101;
1176                         break;
1177         }
1178
1179         return i;
1180 }
1181
1182 #else
1183
1184 /* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
1185
1186 static unsigned int index_to_framebuffer(int index)
1187 {
1188         unsigned int i = index;
1189
1190         switch (GPU_color_depth()) {
1191                 case 8:
1192                         i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
1193                         i |= 0x3F3F3F;
1194                         break;
1195                 case 12:
1196                         i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
1197                         /* sometimes dithering subtracts! */
1198                         i |= 0x0F0F0F;
1199                         break;
1200                 case 15:
1201                 case 16:
1202                         i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
1203                         i |= 0x070707;
1204                         break;
1205                 case 24:
1206                         break;
1207                 default:    /* 18 bits... */
1208                         i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
1209                         i |= 0x030303;
1210                         break;
1211         }
1212
1213         return i;
1214 }
1215
1216 #endif
1217
1218
1219 void GPU_select_index_set(int index)
1220 {
1221         const int col = index_to_framebuffer(index);
1222         glColor3ub(( (col)        & 0xFF),
1223                    (((col) >>  8) & 0xFF),
1224                    (((col) >> 16) & 0xFF));
1225 }
1226
1227 void GPU_select_index_get(int index, int *r_col)
1228 {
1229         const int col = index_to_framebuffer(index);
1230         char *c_col = (char *)r_col;
1231         c_col[0] = (col & 0xFF); /* red */
1232         c_col[1] = ((col >>  8) & 0xFF); /* green */
1233         c_col[2] = ((col >> 16) & 0xFF); /* blue */
1234         c_col[3] = 0xFF; /* alpha */
1235 }
1236
1237
1238 #define INDEX_FROM_BUF_8(col)     ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6))
1239 #define INDEX_FROM_BUF_12(col)    ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8)  + (((col) & 0xF0) >> 4))
1240 #define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9)  + (((col) & 0xF800) >> 6)  + (((col) & 0xF8) >> 3))
1241 #define INDEX_FROM_BUF_18(col)    ((((col) & 0xFC0000) >> 6)  + (((col) & 0xFC00) >> 4)  + (((col) & 0xFC) >> 2))
1242 #define INDEX_FROM_BUF_24(col)      ((col) & 0xFFFFFF)
1243
1244 int GPU_select_to_index(unsigned int col)
1245 {
1246         if (col == 0) {
1247                 return 0;
1248         }
1249
1250         switch (GPU_color_depth()) {
1251                 case  8: return INDEX_FROM_BUF_8(col);
1252                 case 12: return INDEX_FROM_BUF_12(col);
1253                 case 15:
1254                 case 16: return INDEX_FROM_BUF_15_16(col);
1255                 case 24: return INDEX_FROM_BUF_24(col);
1256                 default: return INDEX_FROM_BUF_18(col);
1257         }
1258 }
1259
1260 void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
1261 {
1262 #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
1263         for (i = size; i--; col++) { \
1264             if ((c = *col)) { \
1265                 *col = INDEX_FROM_BUF_BITS(c); \
1266         } \
1267     } ((void)0)
1268
1269         if (size > 0) {
1270                 unsigned int i, c;
1271
1272                 switch (GPU_color_depth()) {
1273                         case  8:
1274                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
1275                                 break;
1276                         case 12:
1277                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
1278                                 break;
1279                         case 15:
1280                         case 16:
1281                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
1282                                 break;
1283                         case 24:
1284                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
1285                                 break;
1286                         default:
1287                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
1288                                 break;
1289                 }
1290         }
1291
1292 #undef INDEX_BUF_ARRAY
1293 }
1294
1295 #define STATE_STACK_DEPTH 16
1296
1297 typedef struct {
1298         eGPUAttribMask mask;
1299
1300         /* GL_ENABLE_BIT */
1301         unsigned int is_blend : 1;
1302         unsigned int is_cull_face : 1;
1303         unsigned int is_depth_test : 1;
1304         unsigned int is_dither : 1;
1305         unsigned int is_lighting : 1;
1306         unsigned int is_line_smooth : 1;
1307         unsigned int is_color_logic_op : 1;
1308         unsigned int is_multisample : 1;
1309         unsigned int is_polygon_offset_line : 1;
1310         unsigned int is_polygon_offset_fill : 1;
1311         unsigned int is_polygon_smooth : 1;
1312         unsigned int is_sample_alpha_to_coverage : 1;
1313         unsigned int is_scissor_test : 1;
1314         unsigned int is_stencil_test : 1;
1315
1316         bool is_clip_plane[6];
1317
1318         /* GL_DEPTH_BUFFER_BIT */
1319         /* unsigned int is_depth_test : 1; */
1320         int depth_func;
1321         double depth_clear_value;
1322         bool depth_write_mask;
1323
1324         /* GL_SCISSOR_BIT */
1325         int scissor_box[4];
1326         /* unsigned int is_scissor_test : 1; */
1327
1328         /* GL_VIEWPORT_BIT */
1329         int viewport[4];
1330         double near_far[2];
1331 }  GPUAttribValues;
1332
1333 typedef struct {
1334         GPUAttribValues attrib_stack[STATE_STACK_DEPTH];
1335         unsigned int top;
1336 } GPUAttribStack;
1337
1338 static GPUAttribStack state = {
1339         .top = 0
1340 };
1341
1342 #define AttribStack state
1343 #define Attrib state.attrib_stack[state.top]
1344
1345 /**
1346  * Replacement for glPush/PopAttributes
1347  *
1348  * We don't need to cover all the options of legacy OpenGL
1349  * but simply the ones used by Blender.
1350  */
1351 void gpuPushAttrib(eGPUAttribMask mask)
1352 {
1353         Attrib.mask = mask;
1354
1355         if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
1356                 Attrib.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
1357                 glGetIntegerv(GL_DEPTH_FUNC, &Attrib.depth_func);
1358                 glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attrib.depth_clear_value);
1359                 glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attrib.depth_write_mask);
1360         }
1361
1362         if ((mask & GPU_ENABLE_BIT) != 0) {
1363                 Attrib.is_blend = glIsEnabled(GL_BLEND);
1364
1365                 for (int i = 0; i < 6; i++) {
1366                         Attrib.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
1367                 }
1368
1369                 Attrib.is_cull_face = glIsEnabled(GL_CULL_FACE);
1370                 Attrib.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
1371                 Attrib.is_dither = glIsEnabled(GL_DITHER);
1372                 Attrib.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
1373                 Attrib.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
1374                 Attrib.is_multisample = glIsEnabled(GL_MULTISAMPLE);
1375                 Attrib.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
1376                 Attrib.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
1377                 Attrib.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
1378                 Attrib.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
1379                 Attrib.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
1380                 Attrib.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
1381         }
1382
1383         if ((mask & GPU_SCISSOR_BIT) != 0) {
1384                 Attrib.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
1385                 glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attrib.scissor_box);
1386         }
1387
1388         if ((mask & GPU_VIEWPORT_BIT) != 0) {
1389                 glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attrib.near_far);
1390                 glGetIntegerv(GL_VIEWPORT, (GLint *)&Attrib.viewport);
1391         }
1392
1393         if ((mask & GPU_BLEND_BIT) != 0) {
1394                 Attrib.is_blend = glIsEnabled(GL_BLEND);
1395         }
1396
1397         BLI_assert(AttribStack.top < STATE_STACK_DEPTH);
1398         AttribStack.top++;
1399 }
1400
1401 static void restore_mask(GLenum cap, const bool value)
1402 {
1403         if (value) {
1404                 glEnable(cap);
1405         }
1406         else {
1407                 glDisable(cap);
1408         }
1409 }
1410
1411 void gpuPopAttrib(void)
1412 {
1413         BLI_assert(AttribStack.top > 0);
1414         AttribStack.top--;
1415
1416         GLint mask = Attrib.mask;
1417
1418         if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
1419                 restore_mask(GL_DEPTH_TEST, Attrib.is_depth_test);
1420                 glDepthFunc(Attrib.depth_func);
1421                 glClearDepth(Attrib.depth_clear_value);
1422                 glDepthMask(Attrib.depth_write_mask);
1423         }
1424
1425         if ((mask & GPU_ENABLE_BIT) != 0) {
1426                 restore_mask(GL_BLEND, Attrib.is_blend);
1427
1428                 for (int i = 0; i < 6; i++) {
1429                         restore_mask(GL_CLIP_PLANE0 + i, Attrib.is_clip_plane[i]);
1430                 }
1431
1432                 restore_mask(GL_CULL_FACE, Attrib.is_cull_face);
1433                 restore_mask(GL_DEPTH_TEST, Attrib.is_depth_test);
1434                 restore_mask(GL_DITHER, Attrib.is_dither);
1435                 restore_mask(GL_LINE_SMOOTH, Attrib.is_line_smooth);
1436                 restore_mask(GL_COLOR_LOGIC_OP, Attrib.is_color_logic_op);
1437                 restore_mask(GL_MULTISAMPLE, Attrib.is_multisample);
1438                 restore_mask(GL_POLYGON_OFFSET_LINE, Attrib.is_polygon_offset_line);
1439                 restore_mask(GL_POLYGON_OFFSET_FILL, Attrib.is_polygon_offset_fill);
1440                 restore_mask(GL_POLYGON_SMOOTH, Attrib.is_polygon_smooth);
1441                 restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attrib.is_sample_alpha_to_coverage);
1442                 restore_mask(GL_SCISSOR_TEST, Attrib.is_scissor_test);
1443                 restore_mask(GL_STENCIL_TEST, Attrib.is_stencil_test);
1444         }
1445
1446         if ((mask & GPU_VIEWPORT_BIT) != 0) {
1447                 glViewport(Attrib.viewport[0], Attrib.viewport[1], Attrib.viewport[2], Attrib.viewport[3]);
1448                 glDepthRange(Attrib.near_far[0], Attrib.near_far[1]);
1449         }
1450
1451         if ((mask & GPU_SCISSOR_BIT) != 0) {
1452                 restore_mask(GL_SCISSOR_TEST, Attrib.is_scissor_test);
1453                 glScissor(Attrib.scissor_box[0], Attrib.scissor_box[1], Attrib.scissor_box[2], Attrib.scissor_box[3]);
1454         }
1455
1456         if ((mask & GPU_BLEND_BIT) != 0) {
1457                 restore_mask(GL_BLEND, Attrib.is_blend);
1458         }
1459 }
1460
1461 #undef Attrib
1462 #undef AttribStack
1463
1464 /** \} */