Draw Engine: remove hard coded limit on array sizes
[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
35  * game engine 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_linklist.h"
43 #include "BLI_math.h"
44 #include "BLI_threads.h"
45 #include "BLI_utildefines.h"
46
47 #include "DNA_lamp_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_mesh_types.h"
50 #include "DNA_meshdata_types.h"
51 #include "DNA_modifier_types.h"
52 #include "DNA_node_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_scene_types.h"
55 #include "DNA_smoke_types.h"
56 #include "DNA_view3d_types.h"
57 #include "DNA_particle_types.h"
58
59 #include "MEM_guardedalloc.h"
60
61 #include "IMB_imbuf.h"
62 #include "IMB_imbuf_types.h"
63
64 #include "BKE_bmfont.h"
65 #include "BKE_global.h"
66 #include "BKE_image.h"
67 #include "BKE_main.h"
68 #include "BKE_material.h"
69 #include "BKE_node.h"
70 #include "BKE_scene.h"
71 #include "BKE_DerivedMesh.h"
72 #ifdef WITH_GAMEENGINE
73 #  include "BKE_object.h"
74 #endif
75
76 #include "GPU_basic_shader.h"
77 #include "GPU_buffers.h"
78 #include "GPU_draw.h"
79 #include "GPU_extensions.h"
80 #include "GPU_material.h"
81 #include "GPU_matrix.h"
82 #include "GPU_shader.h"
83 #include "GPU_texture.h"
84
85 #include "PIL_time.h"
86
87 #ifdef WITH_SMOKE
88 #  include "smoke_API.h"
89 #endif
90
91 #ifdef WITH_OPENSUBDIV
92 #  include "BKE_subsurf.h"
93 #  include "BKE_editmesh.h"
94
95 #  include "gpu_codegen.h"
96 #endif
97
98 extern Material defmaterial; /* from material.c */
99
100 /* Text Rendering */
101
102 static void gpu_mcol(unsigned int ucol)
103 {
104         /* mcol order is swapped */
105         const char *cp = (char *)&ucol;
106         glColor3ub(cp[3], cp[2], cp[1]);
107 }
108
109 void GPU_render_text(
110         MTexPoly *mtexpoly, int mode,
111         const char *textstr, int textlen, unsigned int *col,
112         const float *v_quad[4], const float *uv_quad[4],
113         int glattrib)
114 {
115         if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) {
116                 const float *v1 = v_quad[0];
117                 const float *v2 = v_quad[1];
118                 const float *v3 = v_quad[2];
119                 const float *v4 = v_quad[3];
120                 Image *ima = (Image *)mtexpoly->tpage;
121                 const size_t textlen_st = textlen;
122                 float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
123
124                 /* multiline */
125                 float line_start = 0.0f, line_height;
126
127                 if (v4)
128                         line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]);
129                 else
130                         line_height = max_fff(v1[1], v2[1], v3[1]) - min_fff(v1[1], v2[1], v3[1]);
131                 line_height *= 1.2f; /* could be an option? */
132                 /* end multiline */
133
134
135                 /* color has been set */
136                 if (mtexpoly->mode & TF_OBCOL)
137                         col = NULL;
138                 else if (!col)
139                         glColor3f(1.0f, 1.0f, 1.0f);
140
141                 gpuPushMatrix();
142
143                 /* get the tab width */
144                 ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima);
145                 matrixGlyph(first_ibuf, ' ', &centerx, &centery,
146                     &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
147
148                 float advance_tab = advance * 4; /* tab width could also be an option */
149
150
151                 for (size_t index = 0; index < textlen_st; ) {
152                         unsigned int character;
153                         float uv[4][2];
154
155                         /* lets calculate offset stuff */
156                         character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index);
157
158                         if (character == '\n') {
159                                 gpuTranslate2f(line_start, -line_height);
160                                 line_start = 0.0f;
161                                 continue;
162                         }
163                         else if (character == '\t') {
164                                 gpuTranslate2f(advance_tab, 0.0f);
165                                 line_start -= advance_tab; /* so we can go back to the start of the line */
166                                 continue;
167
168                         }
169                         else if (character > USHRT_MAX) {
170                                 /* not much we can do here bmfonts take ushort */
171                                 character = '?';
172                         }
173
174                         /* space starts at offset 1 */
175                         /* character = character - ' ' + 1; */
176                         matrixGlyph(first_ibuf, character, & centerx, &centery,
177                             &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
178
179                         uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx;
180                         uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy;
181                         uv[1][0] = (uv_quad[1][0] - centerx) * sizex + transx;
182                         uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy;
183                         uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx;
184                         uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy;
185
186                         glBegin(GL_POLYGON);
187                         if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]);
188                         else glTexCoord2fv(uv[0]);
189                         if (col) gpu_mcol(col[0]);
190                         glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
191
192                         if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]);
193                         else glTexCoord2fv(uv[1]);
194                         if (col) gpu_mcol(col[1]);
195                         glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
196
197                         if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[2]);
198                         else glTexCoord2fv(uv[2]);
199                         if (col) gpu_mcol(col[2]);
200                         glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
201
202                         if (v4) {
203                                 uv[3][0] = (uv_quad[3][0] - centerx) * sizex + transx;
204                                 uv[3][1] = (uv_quad[3][1] - centery) * sizey + transy;
205
206                                 if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[3]);
207                                 else glTexCoord2fv(uv[3]);
208                                 if (col) gpu_mcol(col[3]);
209                                 glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
210                         }
211                         glEnd();
212
213                         gpuTranslate2f(advance, 0.0f);
214                         line_start -= advance; /* so we can go back to the start of the line */
215                 }
216                 gpuPopMatrix();
217
218                 BKE_image_release_ibuf(ima, first_ibuf, NULL);
219         }
220 }
221
222 /* Checking powers of two for images since OpenGL ES requires it */
223 #ifdef WITH_DDS
224 static bool is_power_of_2_resolution(int w, int h)
225 {
226         return is_power_of_2_i(w) && is_power_of_2_i(h);
227 }
228 #endif
229
230 static bool is_over_resolution_limit(GLenum textarget, int w, int h)
231 {
232         int size = (textarget == GL_TEXTURE_2D) ?
233                 GPU_max_texture_size() : GPU_max_cube_map_size();
234         int reslimit = (U.glreslimit != 0) ?
235             min_ii(U.glreslimit, size) : size;
236
237         return (w > reslimit || h > reslimit);
238 }
239
240 static int smaller_power_of_2_limit(int num)
241 {
242         int reslimit = (U.glreslimit != 0) ?
243                 min_ii(U.glreslimit, GPU_max_texture_size()) :
244                 GPU_max_texture_size();
245         /* take texture clamping into account */
246         if (num > reslimit)
247                 return reslimit;
248
249         return power_of_2_min_i(num);
250 }
251
252 /* Current OpenGL state caching for GPU_set_tpage */
253
254 static struct GPUTextureState {
255         int curtile, tile;
256         int curtilemode, tilemode;
257         int curtileXRep, tileXRep;
258         int curtileYRep, tileYRep;
259         Image *ima, *curima;
260
261         /* also controls min/mag filtering */
262         bool domipmap;
263         /* only use when 'domipmap' is set */
264         bool linearmipmap;
265         /* store this so that new images created while texture painting won't be set to mipmapped */
266         bool texpaint;
267
268         int alphablend;
269         float anisotropic;
270         int gpu_mipmap;
271         MTexPoly *lasttface;
272 } GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL};
273
274 /* Mipmap settings */
275
276 void GPU_set_gpu_mipmapping(int gpu_mipmap)
277 {
278         int old_value = GTS.gpu_mipmap;
279
280         /* only actually enable if it's supported */
281         GTS.gpu_mipmap = gpu_mipmap;
282
283         if (old_value != GTS.gpu_mipmap) {
284                 GPU_free_images();
285         }
286 }
287
288 static void gpu_generate_mipmap(GLenum target)
289 {
290         const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY);
291         int target_enabled = 0;
292
293         /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled
294          * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */
295         if (is_ati) {
296                 target_enabled = glIsEnabled(target);
297                 if (!target_enabled)
298                         glEnable(target);
299         }
300
301         glGenerateMipmap(target);
302
303         if (is_ati && !target_enabled)
304                 glDisable(target);
305 }
306
307 void GPU_set_mipmap(bool mipmap)
308 {
309         if (GTS.domipmap != mipmap) {
310                 GPU_free_images();
311                 GTS.domipmap = mipmap;
312         }
313 }
314
315 void GPU_set_linear_mipmap(bool linear)
316 {
317         if (GTS.linearmipmap != linear) {
318                 GTS.linearmipmap = linear;
319         }
320 }
321
322 bool GPU_get_mipmap(void)
323 {
324         return GTS.domipmap && !GTS.texpaint;
325 }
326
327 bool GPU_get_linear_mipmap(void)
328 {
329         return GTS.linearmipmap;
330 }
331
332 static GLenum gpu_get_mipmap_filter(bool mag)
333 {
334         /* linearmipmap is off by default *when mipmapping is off,
335          * use unfiltered display */
336         if (mag) {
337                 if (GTS.domipmap)
338                         return GL_LINEAR;
339                 else
340                         return GL_NEAREST;
341         }
342         else {
343                 if (GTS.domipmap) {
344                         if (GTS.linearmipmap) {
345                                 return GL_LINEAR_MIPMAP_LINEAR;
346                         }
347                         else {
348                                 return GL_LINEAR_MIPMAP_NEAREST;
349                         }
350                 }
351                 else {
352                         return GL_NEAREST;
353                 }
354         }
355 }
356
357 /* Anisotropic filtering settings */
358 void GPU_set_anisotropic(float value)
359 {
360         if (GTS.anisotropic != value) {
361                 GPU_free_images();
362
363                 /* Clamp value to the maximum value the graphics card supports */
364                 const float max = GPU_max_texture_anisotropy();
365                 if (value > max)
366                         value = max;
367
368                 GTS.anisotropic = value;
369         }
370 }
371
372 float GPU_get_anisotropic(void)
373 {
374         return GTS.anisotropic;
375 }
376
377 /* Set OpenGL state for an MTFace */
378
379 static void gpu_make_repbind(Image *ima)
380 {
381         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
382         if (ibuf == NULL)
383                 return;
384
385         if (ima->repbind) {
386                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
387                 MEM_freeN(ima->repbind);
388                 ima->repbind = NULL;
389                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
390         }
391
392         ima->totbind = ima->xrep * ima->yrep;
393
394         if (ima->totbind > 1) {
395                 ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind");
396         }
397
398         BKE_image_release_ibuf(ima, ibuf, NULL);
399 }
400
401 static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget)
402 {
403         unsigned int *bind = 0;
404
405         if (textarget == GL_TEXTURE_2D)
406                 bind = &ima->bindcode[TEXTARGET_TEXTURE_2D];
407         else if (textarget == GL_TEXTURE_CUBE_MAP)
408                 bind = &ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP];
409
410         return bind;
411 }
412
413 void GPU_clear_tpage(bool force)
414 {
415         if (GTS.lasttface == NULL && !force)
416                 return;
417
418         GTS.lasttface = NULL;
419         GTS.curtile = 0;
420         GTS.curima = NULL;
421         if (GTS.curtilemode != 0) {
422                 glMatrixMode(GL_TEXTURE);
423                 glLoadIdentity(); /* TEXTURE */
424                 glMatrixMode(GL_MODELVIEW);
425         }
426         GTS.curtilemode = 0;
427         GTS.curtileXRep = 0;
428         GTS.curtileYRep = 0;
429         GTS.alphablend = -1;
430
431         glDisable(GL_BLEND);
432         glDisable(GL_TEXTURE_2D);
433         glDisable(GL_TEXTURE_GEN_S);
434         glDisable(GL_TEXTURE_GEN_T);
435         glDisable(GL_ALPHA_TEST);
436 }
437
438 static void gpu_set_alpha_blend(GPUBlendMode alphablend)
439 {
440         if (alphablend == GPU_BLEND_SOLID) {
441                 glDisable(GL_BLEND);
442                 glDisable(GL_ALPHA_TEST);
443                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
444                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
445         }
446         else if (alphablend == GPU_BLEND_ADD) {
447                 glEnable(GL_BLEND);
448                 glBlendFunc(GL_ONE, GL_ONE);
449                 glDisable(GL_ALPHA_TEST);
450                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
451         }
452         else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) {
453                 glEnable(GL_BLEND);
454                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
455
456                 /* for OpenGL render we use the alpha channel, this makes alpha blend correct */
457                 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
458
459                 /* if U.glalphaclip == 1.0, some cards go bonkers...
460                  * turn off alpha test in this case */
461
462                 /* added after 2.45 to clip alpha */
463                 if (U.glalphaclip == 1.0f) {
464                         glDisable(GL_ALPHA_TEST);
465                 }
466                 else {
467                         glEnable(GL_ALPHA_TEST);
468                         glAlphaFunc(GL_GREATER, U.glalphaclip);
469                 }
470         }
471         else if (alphablend == GPU_BLEND_CLIP) {
472                 glDisable(GL_BLEND);
473                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
474                 glEnable(GL_ALPHA_TEST);
475                 glAlphaFunc(GL_GREATER, 0.5f);
476         }
477         else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) {
478                 glEnable(GL_ALPHA_TEST);
479                 glAlphaFunc(GL_GREATER, U.glalphaclip);
480                 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
481         }
482 }
483
484 static void gpu_verify_alpha_blend(int alphablend)
485 {
486         /* verify alpha blending modes */
487         if (GTS.alphablend == alphablend)
488                 return;
489
490         gpu_set_alpha_blend(alphablend);
491         GTS.alphablend = alphablend;
492 }
493
494 static void gpu_verify_reflection(Image *ima)
495 {
496         if (ima && (ima->flag & IMA_REFLECT)) {
497                 /* enable reflection mapping */
498                 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
499                 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
500
501                 glEnable(GL_TEXTURE_GEN_S);
502                 glEnable(GL_TEXTURE_GEN_T);
503         }
504         else {
505                 /* disable reflection mapping */
506                 glDisable(GL_TEXTURE_GEN_S);
507                 glDisable(GL_TEXTURE_GEN_T);
508         }
509 }
510
511 typedef struct VerifyThreadData {
512         ImBuf *ibuf;
513         float *srgb_frect;
514 } VerifyThreadData;
515
516 static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
517                                                   ImBuf *ibuf,
518                                                   const int start_line,
519                                                   const int height)
520 {
521         size_t offset = ibuf->channels * start_line * ibuf->x;
522         float *current_srgb_frect = srgb_frect + offset;
523         float *current_rect_float = ibuf->rect_float + offset;
524         IMB_buffer_float_from_float(current_srgb_frect,
525                                     current_rect_float,
526                                     ibuf->channels,
527                                     IB_PROFILE_SRGB,
528                                     IB_PROFILE_LINEAR_RGB, true,
529                                     ibuf->x, height,
530                                     ibuf->x, ibuf->x);
531         IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
532         /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */
533         IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height);
534 }
535
536 static void verify_thread_do(void *data_v,
537                              int start_scanline,
538                              int num_scanlines)
539 {
540         VerifyThreadData *data = (VerifyThreadData *)data_v;
541         gpu_verify_high_bit_srgb_buffer_slice(data->srgb_frect,
542                                               data->ibuf,
543                                               start_scanline,
544                                               num_scanlines);
545 }
546
547 static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
548                                             ImBuf *ibuf)
549 {
550         if (ibuf->y < 64) {
551                 gpu_verify_high_bit_srgb_buffer_slice(srgb_frect,
552                                                       ibuf,
553                                                       0, ibuf->y);
554         }
555         else {
556                 VerifyThreadData data;
557                 data.ibuf = ibuf;
558                 data.srgb_frect = srgb_frect;
559                 IMB_processor_apply_threaded_scanlines(ibuf->y, verify_thread_do, &data);
560         }
561 }
562
563 int GPU_verify_image(
564         Image *ima, ImageUser *iuser,
565         int textarget, int tftile, bool compare, bool mipmap, bool is_data)
566 {
567         unsigned int *bind = NULL;
568         int tpx = 0, tpy = 0;
569         unsigned int *rect = NULL;
570         float *frect = NULL;
571         float *srgb_frect = NULL;
572         /* flag to determine whether deep format is used */
573         bool use_high_bit_depth = false, do_color_management = false;
574
575         /* initialize tile mode and number of repeats */
576         GTS.ima = ima;
577         GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES | IMA_TWINANIM)));
578         GTS.tileXRep = 0;
579         GTS.tileYRep = 0;
580
581         /* setting current tile according to frame */
582         if (ima && (ima->tpageflag & IMA_TWINANIM))
583                 GTS.tile = ima->lastframe;
584         else
585                 GTS.tile = tftile;
586
587         GTS.tile = MAX2(0, GTS.tile);
588
589         if (ima) {
590                 GTS.tileXRep = ima->xrep;
591                 GTS.tileYRep = ima->yrep;
592         }
593
594         /* if same image & tile, we're done */
595         if (compare && ima == GTS.curima && GTS.curtile == GTS.tile &&
596             GTS.tilemode == GTS.curtilemode && GTS.curtileXRep == GTS.tileXRep &&
597             GTS.curtileYRep == GTS.tileYRep)
598         {
599                 return (ima != NULL);
600         }
601
602         /* if tiling mode or repeat changed, change texture matrix to fit */
603         if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep ||
604             GTS.curtileYRep != GTS.tileYRep)
605         {
606                 glMatrixMode(GL_TEXTURE);
607                 glLoadIdentity(); /* TEXTURE */
608
609                 if (ima && (ima->tpageflag & IMA_TILES))
610                         glScalef(ima->xrep, ima->yrep, 0); /* TEXTURE */
611
612                 glMatrixMode(GL_MODELVIEW);
613         }
614
615         /* check if we have a valid image */
616         if (ima == NULL || ima->ok == 0)
617                 return 0;
618
619         /* check if we have a valid image buffer */
620         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
621
622         if (ibuf == NULL)
623                 return 0;
624
625         if (ibuf->rect_float) {
626                 if (U.use_16bit_textures) {
627                         /* use high precision textures. This is relatively harmless because OpenGL gives us
628                          * a high precision format only if it is available */
629                         use_high_bit_depth = true;
630                 }
631                 else if (ibuf->rect == NULL) {
632                         IMB_rect_from_float(ibuf);
633                 }
634                 /* we may skip this in high precision, but if not, we need to have a valid buffer here */
635                 else if (ibuf->userflags & IB_RECT_INVALID) {
636                         IMB_rect_from_float(ibuf);
637                 }
638
639                 /* TODO unneeded when float images are correctly treated as linear always */
640                 if (!is_data) {
641                         do_color_management = true;
642                 }
643         }
644
645         /* currently, tpage refresh is used by ima sequences */
646         if (ima->tpageflag & IMA_TPAGE_REFRESH) {
647                 GPU_free_image(ima);
648                 ima->tpageflag &= ~IMA_TPAGE_REFRESH;
649         }
650
651         if (GTS.tilemode) {
652                 /* tiled mode */
653                 if (ima->repbind == NULL) gpu_make_repbind(ima);
654                 if (GTS.tile >= ima->totbind) GTS.tile = 0;
655
656                 /* this happens when you change repeat buttons */
657                 if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile];
658                 else bind = gpu_get_image_bindcode(ima, textarget);
659
660                 if (*bind == 0) {
661                         short texwindx = ibuf->x / ima->xrep;
662                         short texwindy = ibuf->y / ima->yrep;
663
664                         if (GTS.tile >= ima->xrep * ima->yrep)
665                                 GTS.tile = ima->xrep * ima->yrep - 1;
666
667                         short texwinsy = GTS.tile / ima->xrep;
668                         short texwinsx = GTS.tile - texwinsy * ima->xrep;
669
670                         texwinsx *= texwindx;
671                         texwinsy *= texwindy;
672
673                         tpx = texwindx;
674                         tpy = texwindy;
675
676                         if (use_high_bit_depth) {
677                                 if (do_color_management) {
678                                         srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor");
679                                         gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
680                                         frect = srgb_frect + texwinsy * ibuf->x + texwinsx;
681                                 }
682                                 else {
683                                         frect = ibuf->rect_float + texwinsy * ibuf->x + texwinsx;
684                                 }
685                         }
686                         else {
687                                 rect = ibuf->rect + texwinsy * ibuf->x + texwinsx;
688                         }
689                 }
690         }
691         else {
692                 /* regular image mode */
693                 bind = gpu_get_image_bindcode(ima, textarget);
694
695                 if (*bind == 0) {
696                         tpx = ibuf->x;
697                         tpy = ibuf->y;
698                         rect = ibuf->rect;
699                         if (use_high_bit_depth) {
700                                 if (do_color_management) {
701                                         frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
702                                         gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
703                                 }
704                                 else
705                                         frect = ibuf->rect_float;
706                         }
707                 }
708         }
709
710         if (*bind != 0) {
711                 /* enable opengl drawing with textures */
712                 glBindTexture(textarget, *bind);
713                 BKE_image_release_ibuf(ima, ibuf, NULL);
714                 return *bind;
715         }
716
717         const int rectw = tpx;
718         const int recth = tpy;
719
720         unsigned *tilerect = NULL;
721         float *ftilerect = NULL;
722
723         /* for tiles, copy only part of image into buffer */
724         if (GTS.tilemode) {
725                 if (use_high_bit_depth) {
726                         ftilerect = MEM_mallocN(rectw * recth * sizeof(*ftilerect), "tilerect");
727
728                         for (int y = 0; y < recth; y++) {
729                                 const float *frectrow = &frect[y * ibuf->x];
730                                 float *ftilerectrow = &ftilerect[y * rectw];
731
732                                 memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow));
733                         }
734
735                         frect = ftilerect;
736                 }
737                 else {
738                         tilerect = MEM_mallocN(rectw * recth * sizeof(*tilerect), "tilerect");
739
740                         for (int y = 0; y < recth; y++) {
741                                 const unsigned *rectrow = &rect[y * ibuf->x];
742                                 unsigned *tilerectrow = &tilerect[y * rectw];
743
744                                 memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
745                         }
746
747                         rect = tilerect;
748                 }
749         }
750
751 #ifdef WITH_DDS
752         if (ibuf->ftype == IMB_FTYPE_DDS)
753                 GPU_create_gl_tex_compressed(bind, rect, rectw, recth, textarget, mipmap, ima, ibuf);
754         else
755 #endif
756                 GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
757
758         /* mark as non-color data texture */
759         if (*bind) {
760                 if (is_data)
761                         ima->tpageflag |= IMA_GLBIND_IS_DATA;
762                 else
763                         ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
764         }
765
766         /* clean up */
767         if (tilerect)
768                 MEM_freeN(tilerect);
769         if (ftilerect)
770                 MEM_freeN(ftilerect);
771         if (srgb_frect)
772                 MEM_freeN(srgb_frect);
773
774         BKE_image_release_ibuf(ima, ibuf, NULL);
775
776         return *bind;
777 }
778
779 static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
780 {
781         size_t block_size = use_high_bit_depth ? sizeof(float) * 4 : sizeof(unsigned char) * 4;
782         void **sides = NULL;
783         int h = recth / 2;
784         int w = rectw / 3;
785
786         if ((use_high_bit_depth && frect == NULL) || (!use_high_bit_depth && rect == NULL) || w != h)
787                 return sides;
788
789         /* PosX, NegX, PosY, NegY, PosZ, NegZ */
790         sides = MEM_mallocN(sizeof(void *) * 6, "");
791         for (int i = 0; i < 6; i++)
792                 sides[i] = MEM_mallocN(block_size * w * h, "");
793
794         /* divide image into six parts */
795         /* ______________________
796          * |      |      |      |
797          * | NegX | NegY | PosX |
798          * |______|______|______|
799          * |      |      |      |
800          * | NegZ | PosZ | PosY |
801          * |______|______|______|
802          */
803         if (use_high_bit_depth) {
804                 float (*frectb)[4] = (float(*)[4])frect;
805                 float (**fsides)[4] = (float(**)[4])sides;
806
807                 for (int y = 0; y < h; y++) {
808                         for (int x = 0; x < w; x++) {
809                                 memcpy(&fsides[0][x * h + y], &frectb[(recth - y - 1) * rectw + 2 * w + x], block_size);
810                                 memcpy(&fsides[1][x * h + y], &frectb[(y + h) * rectw + w - 1 - x], block_size);
811                                 memcpy(&fsides[3][y * w + x], &frectb[(recth - y - 1) * rectw + 2 * w - 1 - x], block_size);
812                                 memcpy(&fsides[5][y * w + x], &frectb[(h - y - 1) * rectw + w - 1 - x], block_size);
813                         }
814                         memcpy(&fsides[2][y * w], frectb[y * rectw + 2 * w], block_size * w);
815                         memcpy(&fsides[4][y * w], frectb[y * rectw + w], block_size * w);
816                 }
817         }
818         else {
819                 unsigned int **isides = (unsigned int **)sides;
820
821                 for (int y = 0; y < h; y++) {
822                         for (int x = 0; x < w; x++) {
823                                 isides[0][x * h + y] = rect[(recth - y - 1) * rectw + 2 * w + x];
824                                 isides[1][x * h + y] = rect[(y + h) * rectw + w - 1 - x];
825                                 isides[3][y * w + x] = rect[(recth - y - 1) * rectw + 2 * w - 1 - x];
826                                 isides[5][y * w + x] = rect[(h - y - 1) * rectw + w - 1 - x];
827                         }
828                         memcpy(&isides[2][y * w], &rect[y * rectw + 2 * w], block_size * w);
829                         memcpy(&isides[4][y * w], &rect[y * rectw + w], block_size * w);
830                 }
831         }
832
833         return sides;
834 }
835
836 static void gpu_del_cube_map(void **cube_map)
837 {
838         int i;
839         if (cube_map == NULL)
840                 return;
841         for (i = 0; i < 6; i++)
842                 MEM_freeN(cube_map[i]);
843         MEM_freeN(cube_map);
844 }
845
846 /* Image *ima can be NULL */
847 void GPU_create_gl_tex(
848         unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
849         int textarget, bool mipmap, bool use_high_bit_depth, Image *ima)
850 {
851         ImBuf *ibuf = NULL;
852
853         int tpx = rectw;
854         int tpy = recth;
855
856         /* create image */
857         glGenTextures(1, (GLuint *)bind);
858         glBindTexture(textarget, *bind);
859
860         if (textarget == GL_TEXTURE_2D) {
861                 if (use_high_bit_depth) {
862                         if (GLEW_ARB_texture_float)
863                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
864                         else
865                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
866                 }
867                 else
868                         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
869
870                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
871
872                 if (GPU_get_mipmap() && mipmap) {
873                         if (GTS.gpu_mipmap) {
874                                 gpu_generate_mipmap(GL_TEXTURE_2D);
875                         }
876                         else {
877                                 int i;
878                                 if (!ibuf) {
879                                         if (use_high_bit_depth) {
880                                                 ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
881                                         }
882                                         else {
883                                                 ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
884                                         }
885                                 }
886                                 IMB_makemipmap(ibuf, true);
887
888                                 for (i = 1; i < ibuf->miptot; i++) {
889                                         ImBuf *mip = ibuf->mipmap[i - 1];
890                                         if (use_high_bit_depth) {
891                                                 if (GLEW_ARB_texture_float)
892                                                         glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F_ARB, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
893                                                 else
894                                                         glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
895                                         }
896                                         else {
897                                                 glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
898                                         }
899                                 }
900                         }
901                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
902                         if (ima)
903                                 ima->tpageflag |= IMA_MIPMAP_COMPLETE;
904                 }
905                 else {
906                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
907                 }
908         }
909         else if (textarget == GL_TEXTURE_CUBE_MAP) {
910                 int w = rectw / 3, h = recth / 2;
911
912                 if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
913                         void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth);
914                         GLenum informat = use_high_bit_depth ? (GLEW_ARB_texture_float ? GL_RGBA16F_ARB : GL_RGBA16) : GL_RGBA8;
915                         GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE;
916
917                         if (cube_map)
918                                 for (int i = 0; i < 6; i++)
919                                         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, informat, w, h, 0, GL_RGBA, type, cube_map[i]);
920
921                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
922
923                         if (GPU_get_mipmap() && mipmap) {
924                                 if (GTS.gpu_mipmap) {
925                                         gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP);
926                                 }
927                                 else {
928                                         if (!ibuf) {
929                                                 if (use_high_bit_depth) {
930                                                         ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
931                                                 }
932                                                 else {
933                                                         ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
934                                                 }
935                                         }
936
937                                         IMB_makemipmap(ibuf, true);
938
939                                         for (int i = 1; i < ibuf->miptot; i++) {
940                                                 ImBuf *mip = ibuf->mipmap[i - 1];
941                                                 void **mip_cube_map = gpu_gen_cube_map(
942                                                         mip->rect, mip->rect_float,
943                                                         mip->x, mip->y, use_high_bit_depth);
944                                                 int mipw = mip->x / 3, miph = mip->y / 2;
945
946                                                 if (mip_cube_map) {
947                                                         for (int j = 0; j < 6; j++) {
948                                                                 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
949                                                                     informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
950                                                         }
951                                                 }
952                                                 gpu_del_cube_map(mip_cube_map);
953                                         }
954                                 }
955                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
956
957                                 if (ima)
958                                         ima->tpageflag |= IMA_MIPMAP_COMPLETE;
959                         }
960                         else {
961                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
962                         }
963                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
964                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
965                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
966
967                         gpu_del_cube_map(cube_map);
968                 }
969                 else {
970                         printf("Incorrect envmap size\n");
971                 }
972         }
973
974         if (GLEW_EXT_texture_filter_anisotropic)
975                 glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
976
977         if (ibuf)
978                 IMB_freeImBuf(ibuf);
979 }
980
981 /**
982  * GPU_upload_dxt_texture() assumes that the texture is already bound and ready to go.
983  * This is so the viewport and the BGE can share some code.
984  * Returns false if the provided ImBuf doesn't have a supported DXT compression format
985  */
986 bool GPU_upload_dxt_texture(ImBuf *ibuf)
987 {
988 #ifdef WITH_DDS
989         GLint format = 0;
990         int blocksize, height, width, i, size, offset = 0;
991
992         width = ibuf->x;
993         height = ibuf->y;
994
995         if (GLEW_EXT_texture_compression_s3tc) {
996                 if (ibuf->dds_data.fourcc == FOURCC_DXT1)
997                         format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
998                 else if (ibuf->dds_data.fourcc == FOURCC_DXT3)
999                         format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
1000                 else if (ibuf->dds_data.fourcc == FOURCC_DXT5)
1001                         format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
1002         }
1003
1004         if (format == 0) {
1005                 fprintf(stderr, "Unable to find a suitable DXT compression, falling back to uncompressed\n");
1006                 return false;
1007         }
1008
1009         if (!is_power_of_2_resolution(width, height)) {
1010                 fprintf(stderr, "Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n");
1011                 return false;
1012         }
1013
1014         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
1015         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
1016
1017         if (GLEW_EXT_texture_filter_anisotropic)
1018                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
1019
1020         blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
1021         for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); ++i) {
1022                 if (width == 0)
1023                         width = 1;
1024                 if (height == 0)
1025                         height = 1;
1026
1027                 size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
1028
1029                 glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
1030                     0, size, ibuf->dds_data.data + offset);
1031
1032                 offset += size;
1033                 width >>= 1;
1034                 height >>= 1;
1035         }
1036
1037         /* set number of mipmap levels we have, needed in case they don't go down to 1x1 */
1038         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
1039
1040         return true;
1041 #else
1042         (void)ibuf;
1043         return false;
1044 #endif
1045 }
1046
1047 void GPU_create_gl_tex_compressed(
1048         unsigned int *bind, unsigned int *pix, int x, int y,
1049         int textarget, int mipmap, Image *ima, ImBuf *ibuf)
1050 {
1051 #ifndef WITH_DDS
1052         (void)ibuf;
1053         /* Fall back to uncompressed if DDS isn't enabled */
1054         GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
1055 #else
1056         glGenTextures(1, (GLuint *)bind);
1057         glBindTexture(textarget, *bind);
1058
1059         if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf) == 0) {
1060                 glDeleteTextures(1, (GLuint *)bind);
1061                 GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
1062         }
1063 #endif
1064 }
1065 static void gpu_verify_repeat(Image *ima)
1066 {
1067         /* set either clamp or repeat in X/Y */
1068         if (ima->tpageflag & IMA_CLAMP_U)
1069                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1070         else
1071                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1072
1073         if (ima->tpageflag & IMA_CLAMP_V)
1074                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1075         else
1076                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1077 }
1078
1079 int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend)
1080 {
1081         /* check if we need to clear the state */
1082         if (mtexpoly == NULL) {
1083                 GPU_clear_tpage(false);
1084                 return 0;
1085         }
1086
1087         Image *ima = mtexpoly->tpage;
1088         GTS.lasttface = mtexpoly;
1089
1090         gpu_verify_alpha_blend(alphablend);
1091         gpu_verify_reflection(ima);
1092
1093         if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) {
1094                 GTS.curtile = GTS.tile;
1095                 GTS.curima = GTS.ima;
1096                 GTS.curtilemode = GTS.tilemode;
1097                 GTS.curtileXRep = GTS.tileXRep;
1098                 GTS.curtileYRep = GTS.tileYRep;
1099
1100                 glEnable(GL_TEXTURE_2D);
1101         }
1102         else {
1103                 glDisable(GL_TEXTURE_2D);
1104
1105                 GTS.curtile = 0;
1106                 GTS.curima = NULL;
1107                 GTS.curtilemode = 0;
1108                 GTS.curtileXRep = 0;
1109                 GTS.curtileYRep = 0;
1110
1111                 return 0;
1112         }
1113
1114         gpu_verify_repeat(ima);
1115
1116         /* Did this get lost in the image recode? */
1117         /* BKE_image_tag_time(ima);*/
1118
1119         return 1;
1120 }
1121
1122 /* these two functions are called on entering and exiting texture paint mode,
1123  * temporary disabling/enabling mipmapping on all images for quick texture
1124  * updates with glTexSubImage2D. images that didn't change don't have to be
1125  * re-uploaded to OpenGL */
1126 void GPU_paint_set_mipmap(bool mipmap)
1127 {
1128         if (!GTS.domipmap)
1129                 return;
1130
1131         GTS.texpaint = !mipmap;
1132
1133         if (mipmap) {
1134                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
1135                         if (BKE_image_has_bindcode(ima)) {
1136                                 if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
1137                                         if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
1138                                                 glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
1139                                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
1140                                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
1141                                         }
1142                                         if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
1143                                                 glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
1144                                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
1145                                                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
1146                                         }
1147                                 }
1148                                 else
1149                                         GPU_free_image(ima);
1150                         }
1151                         else
1152                                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
1153                 }
1154
1155         }
1156         else {
1157                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
1158                         if (BKE_image_has_bindcode(ima)) {
1159                                 if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
1160                                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
1161                                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1162                                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
1163                                 }
1164                                 if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
1165                                         glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
1166                                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1167                                         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
1168                                 }
1169                         }
1170                         else
1171                                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
1172                 }
1173         }
1174 }
1175
1176
1177 /* check if image has been downscaled and do scaled partial update */
1178 static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
1179 {
1180         if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
1181                 int x_limit = smaller_power_of_2_limit(ibuf->x);
1182                 int y_limit = smaller_power_of_2_limit(ibuf->y);
1183
1184                 float xratio = x_limit / (float)ibuf->x;
1185                 float yratio = y_limit / (float)ibuf->y;
1186
1187                 /* find new width, height and x,y gpu texture coordinates */
1188
1189                 /* take ceiling because we will be losing 1 pixel due to rounding errors in x,y... */
1190                 int rectw = (int)ceil(xratio * w);
1191                 int recth = (int)ceil(yratio * h);
1192
1193                 x *= xratio;
1194                 y *= yratio;
1195
1196                 /* ...but take back if we are over the limit! */
1197                 if (rectw + x > x_limit) rectw--;
1198                 if (recth + y > y_limit) recth--;
1199
1200                 /* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */
1201                 if (frect) {
1202                         ImBuf *ibuf_scale = IMB_allocFromBuffer(NULL, frect, w, h);
1203                         IMB_scaleImBuf(ibuf_scale, rectw, recth);
1204
1205                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
1206                         glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
1207                                         GL_FLOAT, ibuf_scale->rect_float);
1208
1209                         IMB_freeImBuf(ibuf_scale);
1210                 }
1211                 /* byte images are not continuous in memory so do manual interpolation */
1212                 else {
1213                         unsigned char *scalerect = MEM_mallocN(rectw * recth * sizeof(*scalerect) * 4, "scalerect");
1214                         unsigned int *p = (unsigned int *)scalerect;
1215                         int i, j;
1216                         float inv_xratio = 1.0f / xratio;
1217                         float inv_yratio = 1.0f / yratio;
1218                         for (i = 0; i < rectw; i++) {
1219                                 float u = (x + i) * inv_xratio;
1220                                 for (j = 0; j < recth; j++) {
1221                                         float v = (y + j) * inv_yratio;
1222                                         bilinear_interpolation_color_wrap(ibuf, (unsigned char *)(p + i + j * (rectw)), NULL, u, v);
1223                                 }
1224                         }
1225                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
1226                         glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
1227                                         GL_UNSIGNED_BYTE, scalerect);
1228
1229                         MEM_freeN(scalerect);
1230                 }
1231
1232                 if (GPU_get_mipmap()) {
1233                         gpu_generate_mipmap(GL_TEXTURE_2D);
1234                 }
1235                 else {
1236                         ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
1237                 }
1238
1239                 return true;
1240         }
1241
1242         return false;
1243 }
1244
1245 void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
1246 {
1247         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
1248
1249         if (ima->repbind ||
1250             (!GTS.gpu_mipmap && GPU_get_mipmap()) ||
1251             (ima->bindcode[TEXTARGET_TEXTURE_2D] == 0) ||
1252             (ibuf == NULL) ||
1253             (w == 0) || (h == 0))
1254         {
1255                 /* these cases require full reload still */
1256                 GPU_free_image(ima);
1257         }
1258         else {
1259                 /* for the special case, we can do a partial update
1260                  * which is much quicker for painting */
1261                 GLint row_length, skip_pixels, skip_rows;
1262
1263                 /* if color correction is needed, we must update the part that needs updating. */
1264                 if (ibuf->rect_float) {
1265                         float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
1266                         bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
1267                         IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
1268
1269                         if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
1270                                 MEM_freeN(buffer);
1271                                 BKE_image_release_ibuf(ima, ibuf, NULL);
1272                                 return;
1273                         }
1274
1275                         glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
1276                         glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
1277
1278                         MEM_freeN(buffer);
1279
1280                         /* we have already accounted for the case where GTS.gpu_mipmap is false
1281                          * so we will be using GPU mipmap generation here */
1282                         if (GPU_get_mipmap()) {
1283                                 gpu_generate_mipmap(GL_TEXTURE_2D);
1284                         }
1285                         else {
1286                                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
1287                         }
1288
1289                         BKE_image_release_ibuf(ima, ibuf, NULL);
1290                         return;
1291                 }
1292
1293                 if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
1294                         BKE_image_release_ibuf(ima, ibuf, NULL);
1295                         return;
1296                 }
1297
1298                 glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
1299
1300                 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
1301                 glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
1302                 glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
1303
1304                 glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
1305                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
1306                 glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
1307
1308                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
1309                     GL_UNSIGNED_BYTE, ibuf->rect);
1310
1311                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
1312                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
1313                 glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
1314
1315                 /* see comment above as to why we are using gpu mipmap generation here */
1316                 if (GPU_get_mipmap()) {
1317                         gpu_generate_mipmap(GL_TEXTURE_2D);
1318                 }
1319                 else {
1320                         ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
1321                 }
1322         }
1323
1324         BKE_image_release_ibuf(ima, ibuf, NULL);
1325 }
1326
1327 void GPU_update_images_framechange(void)
1328 {
1329         for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
1330                 if (ima->tpageflag & IMA_TWINANIM) {
1331                         if (ima->twend >= ima->xrep * ima->yrep)
1332                                 ima->twend = ima->xrep * ima->yrep - 1;
1333
1334                         /* check: is bindcode not in the array? free. (to do) */
1335
1336                         ima->lastframe++;
1337                         if (ima->lastframe > ima->twend)
1338                                 ima->lastframe = ima->twsta;
1339                 }
1340         }
1341 }
1342
1343 int GPU_update_image_time(Image *ima, double time)
1344 {
1345         if (!ima)
1346                 return 0;
1347
1348         if (ima->lastupdate < 0)
1349                 ima->lastupdate = 0;
1350
1351         if (ima->lastupdate > (float)time)
1352                 ima->lastupdate = (float)time;
1353
1354         int inc = 0;
1355
1356         if (ima->tpageflag & IMA_TWINANIM) {
1357                 if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
1358
1359                 /* check: is the bindcode not in the array? Then free. (still to do) */
1360
1361                 float diff = (float)((float)time - ima->lastupdate);
1362                 inc = (int)(diff * (float)ima->animspeed);
1363
1364                 ima->lastupdate += ((float)inc / (float)ima->animspeed);
1365
1366                 int newframe = ima->lastframe + inc;
1367
1368                 if (newframe > (int)ima->twend) {
1369                         if (ima->twend - ima->twsta != 0)
1370                                 newframe = (int)ima->twsta - 1 + (newframe - ima->twend) % (ima->twend - ima->twsta);
1371                         else
1372                                 newframe = ima->twsta;
1373                 }
1374
1375                 ima->lastframe = newframe;
1376         }
1377
1378         return inc;
1379 }
1380
1381
1382 void GPU_free_smoke(SmokeModifierData *smd)
1383 {
1384         if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
1385                 if (smd->domain->tex)
1386                         GPU_texture_free(smd->domain->tex);
1387                 smd->domain->tex = NULL;
1388
1389                 if (smd->domain->tex_shadow)
1390                         GPU_texture_free(smd->domain->tex_shadow);
1391                 smd->domain->tex_shadow = NULL;
1392
1393                 if (smd->domain->tex_flame)
1394                         GPU_texture_free(smd->domain->tex_flame);
1395                 smd->domain->tex_flame = NULL;
1396         }
1397 }
1398
1399 void GPU_create_smoke(SmokeModifierData *smd, int highres)
1400 {
1401 #ifdef WITH_SMOKE
1402         if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
1403                 SmokeDomainSettings *sds = smd->domain;
1404                 if (!sds->tex && !highres) {
1405                         /* rgba texture for color + density */
1406                         if (smoke_has_colors(sds->fluid)) {
1407                                 float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
1408                                 smoke_get_rgba(sds->fluid, data, 0);
1409                                 sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL);
1410                                 MEM_freeN(data);
1411                         }
1412                         /* density only */
1413                         else {
1414                                 sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
1415                                                                  GPU_R8, smoke_get_density(sds->fluid), NULL);
1416                         }
1417                         sds->tex_flame = (smoke_has_fuel(sds->fluid)) ?
1418                                           GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
1419                                           GPU_R8, smoke_get_flame(sds->fluid), NULL) :
1420                                           NULL;
1421                 }
1422                 else if (!sds->tex && highres) {
1423                         /* rgba texture for color + density */
1424                         if (smoke_turbulence_has_colors(sds->wt)) {
1425                                 float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
1426                                 smoke_turbulence_get_rgba(sds->wt, data, 0);
1427                                 sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL);
1428                                 MEM_freeN(data);
1429                         }
1430                         /* density only */
1431                         else {
1432                                 sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
1433                                                                         GPU_R8, smoke_turbulence_get_density(sds->wt), NULL);
1434                         }
1435                         sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ?
1436                                           GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
1437                                                                        GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL):
1438                                           NULL;
1439                 }
1440
1441                 sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
1442                                                         GPU_R8, sds->shadow, NULL);
1443         }
1444 #else // WITH_SMOKE
1445         (void)highres;
1446         smd->domain->tex = NULL;
1447         smd->domain->tex_flame = NULL;
1448         smd->domain->tex_shadow = NULL;
1449 #endif // WITH_SMOKE
1450 }
1451
1452 static LinkNode *image_free_queue = NULL;
1453
1454 static void gpu_queue_image_for_free(Image *ima)
1455 {
1456         BLI_lock_thread(LOCK_OPENGL);
1457         BLI_linklist_prepend(&image_free_queue, ima);
1458         BLI_unlock_thread(LOCK_OPENGL);
1459 }
1460
1461 void GPU_free_unused_buffers(void)
1462 {
1463         if (!BLI_thread_is_main())
1464                 return;
1465
1466         BLI_lock_thread(LOCK_OPENGL);
1467
1468         /* images */
1469         for (LinkNode *node = image_free_queue; node; node = node->next) {
1470                 Image *ima = node->link;
1471
1472                 /* check in case it was freed in the meantime */
1473                 if (G.main && BLI_findindex(&G.main->image, ima) != -1)
1474                         GPU_free_image(ima);
1475         }
1476
1477         BLI_linklist_free(image_free_queue, NULL);
1478         image_free_queue = NULL;
1479
1480         /* vbo buffers */
1481         GPU_global_buffer_pool_free_unused();
1482
1483         BLI_unlock_thread(LOCK_OPENGL);
1484 }
1485
1486 void GPU_free_image(Image *ima)
1487 {
1488         if (!BLI_thread_is_main()) {
1489                 gpu_queue_image_for_free(ima);
1490                 return;
1491         }
1492
1493         for (int i = 0; i < TEXTARGET_COUNT; i++) {
1494                 /* free regular image binding */
1495                 if (ima->bindcode[i]) {
1496                         glDeleteTextures(1, (GLuint *)&ima->bindcode[i]);
1497                         ima->bindcode[i] = 0;
1498                 }
1499                 /* free glsl image binding */
1500                 if (ima->gputexture[i]) {
1501                         GPU_texture_free(ima->gputexture[i]);
1502                         ima->gputexture[i] = NULL;
1503                 }
1504         }
1505
1506         /* free repeated image binding */
1507         if (ima->repbind) {
1508                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
1509
1510                 MEM_freeN(ima->repbind);
1511                 ima->repbind = NULL;
1512         }
1513
1514         ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE | IMA_GLBIND_IS_DATA);
1515 }
1516
1517 void GPU_free_images(void)
1518 {
1519         if (G.main)
1520                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next)
1521                         GPU_free_image(ima);
1522 }
1523
1524 /* same as above but only free animated images */
1525 void GPU_free_images_anim(void)
1526 {
1527         if (G.main)
1528                 for (Image *ima = G.main->image.first; ima; ima = ima->id.next)
1529                         if (BKE_image_is_animated(ima))
1530                                 GPU_free_image(ima);
1531 }
1532
1533
1534 void GPU_free_images_old(void)
1535 {
1536         static int lasttime = 0;
1537         int ctime = (int)PIL_check_seconds_timer();
1538
1539         /*
1540          * Run garbage collector once for every collecting period of time
1541          * if textimeout is 0, that's the option to NOT run the collector
1542          */
1543         if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime)
1544                 return;
1545
1546         /* of course not! */
1547         if (G.is_rendering)
1548                 return;
1549
1550         lasttime = ctime;
1551
1552         Image *ima = G.main->image.first;
1553         while (ima) {
1554                 if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
1555                         /* If it's in GL memory, deallocate and set time tag to current time
1556                          * This gives textures a "second chance" to be used before dying. */
1557                         if (BKE_image_has_bindcode(ima) || ima->repbind) {
1558                                 GPU_free_image(ima);
1559                                 ima->lastused = ctime;
1560                         }
1561                         /* Otherwise, just kill the buffers */
1562                         else {
1563                                 BKE_image_free_buffers(ima);
1564                         }
1565                 }
1566                 ima = ima->id.next;
1567         }
1568 }
1569
1570
1571 /* OpenGL Materials */
1572
1573 #define FIXEDMAT 8
1574
1575 /* OpenGL state caching for materials */
1576
1577 typedef struct GPUMaterialFixed {
1578         float diff[3];
1579         float spec[3];
1580         int hard;
1581         float alpha;
1582 } GPUMaterialFixed;
1583
1584 static struct GPUMaterialState {
1585         GPUMaterialFixed (*matbuf);
1586         GPUMaterialFixed matbuf_fixed[FIXEDMAT];
1587         int totmat;
1588
1589         /* set when called inside GPU_begin_object_materials / GPU_end_object_materials
1590          * otherwise calling GPU_object_material_bind returns zero */
1591         bool is_enabled;
1592
1593         Material **gmatbuf;
1594         Material *gmatbuf_fixed[FIXEDMAT];
1595         Material *gboundmat;
1596         Object *gob;
1597         DupliObject *dob;
1598         Scene *gscene;
1599         int glay;
1600         bool gscenelock;
1601         float (*gviewmat)[4];
1602         float (*gviewinv)[4];
1603         float (*gviewcamtexcofac);
1604
1605         bool backface_culling;
1606         bool two_sided_lighting;
1607
1608         GPUBlendMode *alphablend;
1609         GPUBlendMode alphablend_fixed[FIXEDMAT];
1610         bool use_alpha_pass, is_alpha_pass;
1611         bool use_matcaps;
1612
1613         int lastmatnr, lastretval;
1614         GPUBlendMode lastalphablend;
1615         bool is_opensubdiv;
1616 } GMS = {NULL};
1617
1618 /* fixed function material, alpha handed by caller */
1619 static void gpu_material_to_fixed(
1620         GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob,
1621         const int new_shading_nodes, const bool dimdown)
1622 {
1623         if (bmat->mode & MA_SHLESS) {
1624                 copy_v3_v3(smat->diff, &bmat->r);
1625
1626                 if (gamma)
1627                         linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
1628
1629                 zero_v3(smat->spec);
1630                 smat->alpha = 1.0f;
1631                 smat->hard = 0;
1632         }
1633         else if (new_shading_nodes) {
1634                 copy_v3_v3(smat->diff, &bmat->r);
1635                 copy_v3_v3(smat->spec, &bmat->specr);
1636                 smat->alpha = 1.0f;
1637                 smat->hard = CLAMPIS(bmat->har, 0, 128);
1638
1639                 if (dimdown) {
1640                         mul_v3_fl(smat->diff, 0.8f);
1641                         mul_v3_fl(smat->spec, 0.5f);
1642                 }
1643
1644                 if (gamma) {
1645                         linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
1646                         linearrgb_to_srgb_v3_v3(smat->spec, smat->spec);
1647                 }
1648         }
1649         else {
1650                 mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit);
1651
1652                 if (bmat->shade_flag & MA_OBCOLOR)
1653                         mul_v3_v3(smat->diff, ob->col);
1654
1655                 mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
1656                 smat->hard = CLAMPIS(bmat->har, 1, 128);
1657                 smat->alpha = 1.0f;
1658
1659                 if (gamma) {
1660                         linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
1661                         linearrgb_to_srgb_v3_v3(smat->spec, smat->spec);
1662                 }
1663         }
1664 }
1665
1666 static Material *gpu_active_node_material(Material *ma)
1667 {
1668         if (ma && ma->use_nodes && ma->nodetree) {
1669                 bNode *node = nodeGetActiveID(ma->nodetree, ID_MA);
1670
1671                 if (node)
1672                         return (Material *)node->id;
1673                 else
1674                         return NULL;
1675         }
1676
1677         return ma;
1678 }
1679
1680 void GPU_begin_dupli_object(DupliObject *dob)
1681 {
1682         GMS.dob = dob;
1683 }
1684
1685 void GPU_end_dupli_object(void)
1686 {
1687         GMS.dob = NULL;
1688 }
1689
1690 void GPU_begin_object_materials(
1691         View3D *v3d, RegionView3D *rv3d, Scene *scene, SceneLayer *sl, Object *ob,
1692         bool glsl, bool *do_alpha_after)
1693 {
1694         Material *ma;
1695         GPUMaterial *gpumat;
1696         GPUBlendMode alphablend;
1697         DupliObject *dob;
1698         int a;
1699         const bool gamma = BKE_scene_check_color_management_enabled(scene);
1700         const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
1701         const bool use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) != 0;  /* assumes v3d->defmaterial->preview is set */
1702         bool use_opensubdiv = false;
1703
1704 #ifdef WITH_OPENSUBDIV
1705         {
1706                 DerivedMesh *derivedFinal = NULL;
1707                 if (ob->type == OB_MESH) {
1708                         Mesh *me = ob->data;
1709                         BMEditMesh *em = me->edit_btmesh;
1710                         if (em != NULL) {
1711                                 derivedFinal = em->derivedFinal;
1712                         }
1713                         else {
1714                                 derivedFinal = ob->derivedFinal;
1715                         }
1716                 }
1717                 else {
1718                         derivedFinal = ob->derivedFinal;
1719                 }
1720
1721                 if (derivedFinal != NULL && derivedFinal->type == DM_TYPE_CCGDM) {
1722                         CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) derivedFinal;
1723                         use_opensubdiv = ccgdm->useGpuBackend;
1724                 }
1725         }
1726 #endif
1727
1728 #ifdef WITH_GAMEENGINE
1729         if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
1730                 ob = BKE_object_lod_matob_get(ob, sl);
1731         }
1732 #else
1733         UNUSED_VARS(sl);
1734 #endif
1735
1736         /* initialize state */
1737         /* DupliObject must be restored */
1738         dob = GMS.dob;
1739         memset(&GMS, 0, sizeof(GMS));
1740         GMS.is_enabled = true;
1741         GMS.dob = dob;
1742         GMS.lastmatnr = -1;
1743         GMS.lastretval = -1;
1744         GMS.lastalphablend = GPU_BLEND_SOLID;
1745         GMS.use_matcaps = use_matcap;
1746
1747         GMS.backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
1748
1749         GMS.two_sided_lighting = false;
1750         if (ob && ob->type == OB_MESH)
1751                 GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0;
1752
1753         GMS.gob = ob;
1754         GMS.gscene = scene;
1755         GMS.is_opensubdiv = use_opensubdiv;
1756         GMS.totmat = use_matcap ? 1 : ob->totcol + 1;  /* materials start from 1, default material is 0 */
1757         GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */
1758         GMS.gscenelock = (v3d->scenelock != 0);
1759         GMS.gviewmat = rv3d->viewmat;
1760         GMS.gviewinv = rv3d->viewinv;
1761         GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
1762
1763         /* alpha pass setup. there's various cases to handle here:
1764          * - object transparency on: only solid materials draw in the first pass,
1765          * and only transparent in the second 'alpha' pass.
1766          * - object transparency off: for glsl we draw both in a single pass, and
1767          * for solid we don't use transparency at all. */
1768         GMS.use_alpha_pass = (do_alpha_after != NULL);
1769         GMS.is_alpha_pass = (v3d->transp != false);
1770         if (GMS.use_alpha_pass)
1771                 *do_alpha_after = false;
1772
1773         if (GMS.totmat > FIXEDMAT) {
1774                 GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf");
1775                 GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf");
1776                 GMS.alphablend = MEM_callocN(sizeof(*GMS.alphablend) * GMS.totmat, "GMS.matbuf");
1777         }
1778         else {
1779                 GMS.matbuf = GMS.matbuf_fixed;
1780                 GMS.gmatbuf = GMS.gmatbuf_fixed;
1781                 GMS.alphablend = GMS.alphablend_fixed;
1782         }
1783
1784         /* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */
1785         if (use_matcap) {
1786                 GMS.gmatbuf[0] = v3d->defmaterial;
1787                 GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv);
1788
1789                 /* do material 1 too, for displists! */
1790                 memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
1791
1792                 GMS.alphablend[0] = GPU_BLEND_SOLID;
1793         }
1794         else {
1795
1796                 /* no materials assigned? */
1797                 if (ob->totcol == 0) {
1798                         gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true);
1799
1800                         /* do material 1 too, for displists! */
1801                         memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
1802
1803                         if (glsl) {
1804                                 GMS.gmatbuf[0] = &defmaterial;
1805                                 GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv);
1806                         }
1807
1808                         GMS.alphablend[0] = GPU_BLEND_SOLID;
1809                 }
1810
1811                 /* setup materials */
1812                 for (a = 1; a <= ob->totcol; a++) {
1813                         /* find a suitable material */
1814                         ma = give_current_material(ob, a);
1815                         if (!glsl && !new_shading_nodes) ma = gpu_active_node_material(ma);
1816                         if (ma == NULL) ma = &defmaterial;
1817
1818                         /* create glsl material if requested */
1819                         gpumat = glsl ? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv) : NULL;
1820
1821                         if (gpumat) {
1822                                 /* do glsl only if creating it succeed, else fallback */
1823                                 GMS.gmatbuf[a] = ma;
1824                                 alphablend = GPU_material_alpha_blend(gpumat, ob->col);
1825                         }
1826                         else {
1827                                 /* fixed function opengl materials */
1828                                 gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false);
1829
1830                                 if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) {
1831                                         GMS.matbuf[a].alpha = ma->alpha;
1832                                         alphablend = (ma->alpha == 1.0f) ? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
1833                                 }
1834                                 else {
1835                                         GMS.matbuf[a].alpha = 1.0f;
1836                                         alphablend = GPU_BLEND_SOLID;
1837                                 }
1838                         }
1839
1840                         /* setting 'do_alpha_after = true' indicates this object needs to be
1841                          * drawn in a second alpha pass for improved blending */
1842                         if (do_alpha_after && !GMS.is_alpha_pass)
1843                                 if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT))
1844                                         *do_alpha_after = true;
1845
1846                         GMS.alphablend[a] = alphablend;
1847                 }
1848         }
1849
1850         /* let's start with a clean state */
1851         GPU_object_material_unbind();
1852 }
1853
1854 static int GPU_get_particle_info(GPUParticleInfo *pi)
1855 {
1856         DupliObject *dob = GMS.dob;
1857         if (dob->particle_system) {
1858                 int ind;
1859                 if (dob->persistent_id[0] < dob->particle_system->totpart)
1860                         ind = dob->persistent_id[0];
1861                 else {
1862                         ind = dob->particle_system->child[dob->persistent_id[0] - dob->particle_system->totpart].parent;
1863                 }
1864                 if (ind >= 0) {
1865                         ParticleData *p = &dob->particle_system->particles[ind];
1866
1867                         pi->scalprops[0] = ind;
1868                         pi->scalprops[1] = GMS.gscene->r.cfra - p->time;
1869                         pi->scalprops[2] = p->lifetime;
1870                         pi->scalprops[3] = p->size;
1871
1872                         copy_v3_v3(pi->location, p->state.co);
1873                         copy_v3_v3(pi->velocity, p->state.vel);
1874                         copy_v3_v3(pi->angular_velocity, p->state.ave);
1875                         return 1;
1876                 }
1877                 else return 0;
1878         }
1879         else
1880                 return 0;
1881 }
1882
1883 int GPU_object_material_bind(int nr, void *attribs)
1884 {
1885         GPUVertexAttribs *gattribs = attribs;
1886
1887         /* no GPU_begin_object_materials, use default material */
1888         if (!GMS.matbuf) {
1889                 memset(&GMS, 0, sizeof(GMS));
1890
1891                 float diffuse[3], specular[3];
1892                 mul_v3_v3fl(diffuse, &defmaterial.r, defmaterial.ref + defmaterial.emit);
1893                 mul_v3_v3fl(specular, &defmaterial.specr, defmaterial.spec);
1894                 GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
1895
1896                 if (GMS.two_sided_lighting)
1897                         GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
1898                 else
1899                         GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
1900
1901                 return 0;
1902         }
1903
1904         /* prevent index to use un-initialized array items */
1905         if (nr >= GMS.totmat)
1906                 nr = 0;
1907
1908         if (gattribs)
1909                 memset(gattribs, 0, sizeof(*gattribs));
1910
1911         /* keep current material */
1912         if (nr == GMS.lastmatnr)
1913                 return GMS.lastretval;
1914
1915         /* unbind glsl material */
1916         if (GMS.gboundmat) {
1917                 if (GMS.is_alpha_pass) glDepthMask(0);
1918                 GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
1919                 GMS.gboundmat = NULL;
1920         }
1921
1922         /* draw materials with alpha in alpha pass */
1923         GMS.lastmatnr = nr;
1924         GMS.lastretval = 1;
1925
1926         if (GMS.use_alpha_pass) {
1927                 GMS.lastretval = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP);
1928                 if (GMS.is_alpha_pass)
1929                         GMS.lastretval = !GMS.lastretval;
1930         }
1931         else
1932                 GMS.lastretval = !GMS.is_alpha_pass;
1933
1934         if (GMS.lastretval) {
1935                 /* for alpha pass, use alpha blend */
1936                 GPUBlendMode alphablend = GMS.alphablend[nr];
1937
1938                 if (gattribs && GMS.gmatbuf[nr]) {
1939                         /* bind glsl material and get attributes */
1940                         Material *mat = GMS.gmatbuf[nr];
1941                         GPUParticleInfo partile_info;
1942
1943                         float auto_bump_scale;
1944
1945                         GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
1946                         GPU_material_vertex_attributes(gpumat, gattribs);
1947
1948                         if (GMS.dob)
1949                                 GPU_get_particle_info(&partile_info);
1950
1951                         GPU_material_bind(
1952                                 gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
1953                                 GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
1954
1955                         auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
1956                         GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info);
1957                         GMS.gboundmat = mat;
1958
1959                         /* for glsl use alpha blend mode, unless it's set to solid and
1960                          * we are already drawing in an alpha pass */
1961                         if (mat->game.alpha_blend != GPU_BLEND_SOLID)
1962                                 alphablend = mat->game.alpha_blend;
1963
1964                         if (GMS.is_alpha_pass) glDepthMask(1);
1965
1966                         if (GMS.backface_culling) {
1967                                 if (mat->game.flag)
1968                                         glEnable(GL_CULL_FACE);
1969                                 else
1970                                         glDisable(GL_CULL_FACE);
1971                         }
1972
1973                         if (GMS.use_matcaps)
1974                                 glColor3f(1.0f, 1.0f, 1.0f);
1975                 }
1976                 else {
1977                         /* or do fixed function opengl material */
1978                         GPU_basic_shader_colors(
1979                                 GMS.matbuf[nr].diff,
1980                                 GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
1981
1982                         if (GMS.two_sided_lighting)
1983                                 GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
1984                         else
1985                                 GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
1986                 }
1987
1988                 /* set (alpha) blending mode */
1989                 GPU_set_material_alpha_blend(alphablend);
1990         }
1991
1992         return GMS.lastretval;
1993 }
1994
1995 int GPU_object_material_visible(int nr, void *attribs)
1996 {
1997         GPUVertexAttribs *gattribs = attribs;
1998         int visible;
1999
2000         if (!GMS.matbuf)
2001                 return 0;
2002
2003         if (gattribs)
2004                 memset(gattribs, 0, sizeof(*gattribs));
2005
2006         if (nr >= GMS.totmat)
2007                 nr = 0;
2008
2009         if (GMS.use_alpha_pass) {
2010                 visible = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP);
2011                 if (GMS.is_alpha_pass)
2012                         visible = !visible;
2013         }
2014         else
2015                 visible = !GMS.is_alpha_pass;
2016
2017         return visible;
2018 }
2019
2020 void GPU_set_material_alpha_blend(int alphablend)
2021 {
2022         if (GMS.lastalphablend == alphablend)
2023                 return;
2024
2025         gpu_set_alpha_blend(alphablend);
2026         GMS.lastalphablend = alphablend;
2027 }
2028
2029 int GPU_get_material_alpha_blend(void)
2030 {
2031         return GMS.lastalphablend;
2032 }
2033
2034 void GPU_object_material_unbind(void)
2035 {
2036         GMS.lastmatnr = -1;
2037         GMS.lastretval = 1;
2038
2039         if (GMS.gboundmat) {
2040                 if (GMS.backface_culling)
2041                         glDisable(GL_CULL_FACE);
2042
2043                 if (GMS.is_alpha_pass) glDepthMask(0);
2044                 GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
2045                 GMS.gboundmat = NULL;
2046         }
2047         else
2048                 GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
2049
2050         GPU_set_material_alpha_blend(GPU_BLEND_SOLID);
2051 }
2052
2053 void GPU_material_diffuse_get(int nr, float diff[4])
2054 {
2055         /* prevent index to use un-initialized array items */
2056         if (nr >= GMS.totmat)
2057                 nr = 0;
2058
2059         /* no GPU_begin_object_materials, use default material */
2060         if (!GMS.matbuf) {
2061                 mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit);
2062         }
2063         else {
2064                 copy_v3_v3(diff, GMS.matbuf[nr].diff);
2065                 diff[3] = GMS.matbuf[nr].alpha;
2066         }
2067 }
2068
2069 bool GPU_material_use_matcaps_get(void)
2070 {
2071         return GMS.use_matcaps;
2072 }
2073
2074 bool GPU_object_materials_check(void)
2075 {
2076         return GMS.is_enabled;
2077 }
2078
2079 void GPU_end_object_materials(void)
2080 {
2081         GPU_object_material_unbind();
2082
2083         GMS.is_enabled = false;
2084
2085         if (GMS.matbuf && GMS.matbuf != GMS.matbuf_fixed) {
2086                 MEM_freeN(GMS.matbuf);
2087                 MEM_freeN(GMS.gmatbuf);
2088                 MEM_freeN(GMS.alphablend);
2089         }
2090
2091         GMS.matbuf = NULL;
2092         GMS.gmatbuf = NULL;
2093         GMS.alphablend = NULL;
2094         GMS.two_sided_lighting = false;
2095
2096         /* resetting the texture matrix after the scaling needed for tiled textures */
2097         if (GTS.tilemode) {
2098                 glMatrixMode(GL_TEXTURE);
2099                 glLoadIdentity(); /* TEXTURE */
2100                 glMatrixMode(GL_MODELVIEW);
2101         }
2102 }
2103
2104 /* Lights */
2105
2106 int GPU_default_lights(void)
2107 {
2108         /* initialize */
2109         if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) {
2110                 U.light[0].flag = 1;
2111                 U.light[0].vec[0] = -0.3; U.light[0].vec[1] = 0.3; U.light[0].vec[2] = 0.9;
2112                 U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8;
2113                 U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5;
2114                 U.light[0].spec[3] = 1.0;
2115
2116                 U.light[1].flag = 0;
2117                 U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1;
2118                 U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8;
2119                 U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5;
2120                 U.light[1].spec[3] = 1.0;
2121
2122                 U.light[2].flag = 0;
2123                 U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2;
2124                 U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4;
2125                 U.light[2].spec[0] = 0.5; U.light[2].spec[1] = 0.4; U.light[2].spec[2] = 0.3;
2126                 U.light[2].spec[3] = 1.0;
2127         }
2128
2129         GPU_basic_shader_light_set_viewer(false);
2130
2131         int count = 0;
2132
2133         for (int a = 0; a < 8; a++) {
2134                 if (a < 3 && U.light[a].flag) {
2135                         GPULightData light = {0};
2136
2137                         light.type = GPU_LIGHT_SUN;
2138
2139                         normalize_v3_v3(light.direction, U.light[a].vec);
2140                         copy_v3_v3(light.diffuse, U.light[a].col);
2141                         copy_v3_v3(light.specular, U.light[a].spec);
2142
2143                         GPU_basic_shader_light_set(a, &light);
2144
2145                         count++;
2146                 }
2147                 else
2148                         GPU_basic_shader_light_set(a, NULL);
2149         }
2150
2151         return count;
2152 }
2153
2154 int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho)
2155 {
2156         /* disable all lights */
2157         for (int count = 0; count < 8; count++)
2158                 GPU_basic_shader_light_set(count, NULL);
2159
2160         /* view direction for specular is not computed correct by default in
2161          * opengl, so we set the settings ourselfs */
2162         GPU_basic_shader_light_set_viewer(!ortho);
2163
2164         int count = 0;
2165
2166         for (BaseLegacy *base = scene->base.first; base; base = base->next) {
2167                 if (base->object->type != OB_LAMP)
2168                         continue;
2169
2170                 if (!(base->lay & lay) || !(base->lay & ob->lay))
2171                         continue;
2172
2173                 Lamp *la = base->object->data;
2174
2175                 /* setup lamp transform */
2176                 gpuPushMatrix();
2177                 gpuLoadMatrix3D(viewmat);
2178
2179                 /* setup light */
2180                 GPULightData light = {0};
2181
2182                 mul_v3_v3fl(light.diffuse, &la->r, la->energy);
2183                 mul_v3_v3fl(light.specular, &la->r, la->energy);
2184
2185                 if (la->type == LA_SUN) {
2186                         /* directional sun light */
2187                         light.type = GPU_LIGHT_SUN;
2188                         normalize_v3_v3(light.direction, base->object->obmat[2]);
2189                 }
2190                 else {
2191                         /* other lamps with position attenuation */
2192                         copy_v3_v3(light.position, base->object->obmat[3]);
2193
2194                         light.constant_attenuation = 1.0f;
2195                         light.linear_attenuation = la->att1 / la->dist;
2196                         light.quadratic_attenuation = la->att2 / (la->dist * la->dist);
2197
2198                         if (la->type == LA_SPOT) {
2199                                 light.type = GPU_LIGHT_SPOT;
2200                                 negate_v3_v3(light.direction, base->object->obmat[2]);
2201                                 normalize_v3(light.direction);
2202                                 light.spot_cutoff = RAD2DEGF(la->spotsize * 0.5f);
2203                                 light.spot_exponent = 128.0f * la->spotblend;
2204                         }
2205                         else
2206                                 light.type = GPU_LIGHT_POINT;
2207                 }
2208
2209                 GPU_basic_shader_light_set(count, &light);
2210
2211                 gpuPopMatrix();
2212
2213                 count++;
2214                 if (count == 8)
2215                         break;
2216         }
2217
2218         return count;
2219 }
2220
2221 static void gpu_multisample(bool enable)
2222 {
2223 #ifdef __linux__
2224         /* changing multisample from the default (enabled) causes problems on some
2225          * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */
2226         bool toggle_ok = true;
2227
2228         if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
2229                 int samples = 0;
2230                 glGetIntegerv(GL_SAMPLES, &samples);
2231
2232                 if (samples == 0)
2233                         toggle_ok = false;
2234         }
2235
2236         if (toggle_ok) {
2237                 if (enable)
2238                         glEnable(GL_MULTISAMPLE);
2239                 else
2240                         glDisable(GL_MULTISAMPLE);
2241         }
2242 #else
2243         if (enable)
2244                 glEnable(GL_MULTISAMPLE);
2245         else
2246                 glDisable(GL_MULTISAMPLE);
2247 #endif
2248 }
2249
2250 /* Default OpenGL State
2251  *
2252  * This is called on startup, for opengl offscreen render and to restore state
2253  * for the game engine. Generally we should always return to this state when
2254  * temporarily modifying the state for drawing, though that are (undocumented)
2255  * exceptions that we should try to get rid of. */
2256
2257 void GPU_state_init(void)
2258 {
2259         GPU_default_lights();
2260
2261         GPU_disable_program_point_size();
2262
2263         /* TODO: remove this when we switch to core profile */
2264         glEnable(GL_POINT_SPRITE);
2265
2266
2267         glDepthFunc(GL_LEQUAL);
2268         /* scaling matrices */
2269         glEnable(GL_NORMALIZE);
2270
2271         glDisable(GL_ALPHA_TEST);
2272         glDisable(GL_BLEND);
2273         glDisable(GL_DEPTH_TEST);
2274         glDisable(GL_LOGIC_OP);
2275         glDisable(GL_STENCIL_TEST);
2276         glDisable(GL_TEXTURE_1D);
2277         glDisable(GL_TEXTURE_2D);
2278         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2279
2280         glDepthRange(0.0, 1.0);
2281
2282         glMatrixMode(GL_TEXTURE);
2283         glLoadIdentity(); /* TEXTURE */
2284         glMatrixMode(GL_MODELVIEW);
2285
2286         glFrontFace(GL_CCW);
2287         glCullFace(GL_BACK);
2288         glDisable(GL_CULL_FACE);
2289
2290         gpu_multisample(false);
2291 }
2292
2293 void GPU_enable_program_point_size(void)
2294 {
2295 #ifdef __APPLE__
2296         /* TODO: remove this when we switch to core profile */
2297         glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
2298 #else
2299         glEnable(GL_PROGRAM_POINT_SIZE);
2300 #endif
2301 }
2302
2303 void GPU_disable_program_point_size(void)
2304 {
2305 #ifdef __APPLE__
2306         /* TODO: remove this when we switch to core profile */
2307         glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
2308 #else
2309         glDisable(GL_PROGRAM_POINT_SIZE);
2310 #endif
2311 }
2312
2313 #ifdef WITH_OPENSUBDIV
2314 /* Update face-varying variables offset which might be
2315  * different from mesh to mesh sharing the same material.
2316  */
2317 void GPU_draw_update_fvar_offset(DerivedMesh *dm)
2318 {
2319         /* Sanity check to be sure we only do this for OpenSubdiv draw. */
2320         BLI_assert(dm->type == DM_TYPE_CCGDM);
2321         BLI_assert(GMS.is_opensubdiv);
2322
2323         for (int i = 0; i < GMS.totmat; ++i) {
2324                 Material *material = GMS.gmatbuf[i];
2325                 GPUMaterial *gpu_material;
2326
2327                 if (material == NULL) {
2328                         continue;
2329                 }
2330
2331                 gpu_material = GPU_material_from_blender(GMS.gscene,
2332                                                          material,
2333                                                          GMS.is_opensubdiv);
2334
2335                 GPU_material_update_fvar_offset(gpu_material, dm);
2336         }
2337 }
2338 #endif
2339
2340
2341 /** \name Framebuffer color depth, for selection codes
2342  * \{ */
2343
2344 #ifdef __APPLE__
2345
2346 /* apple seems to round colors to below and up on some configs */
2347
2348 static unsigned int index_to_framebuffer(int index)
2349 {
2350         unsigned int i = index;
2351
2352         switch (GPU_color_depth()) {
2353                 case 12:
2354                         i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
2355                         /* sometimes dithering subtracts! */
2356                         i |= 0x070707;
2357                         break;
2358                 case 15:
2359                 case 16:
2360                         i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
2361                         i |= 0x030303;
2362                         break;
2363                 case 24:
2364                         break;
2365                 default: /* 18 bits... */
2366                         i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
2367                         i |= 0x010101;
2368                         break;
2369         }
2370
2371         return i;
2372 }
2373
2374 #else
2375
2376 /* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
2377
2378 static unsigned int index_to_framebuffer(int index)
2379 {
2380         unsigned int i = index;
2381
2382         switch (GPU_color_depth()) {
2383                 case 8:
2384                         i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6);
2385                         i |= 0x3F3F3F;
2386                         break;
2387                 case 12:
2388                         i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4);
2389                         /* sometimes dithering subtracts! */
2390                         i |= 0x0F0F0F;
2391                         break;
2392                 case 15:
2393                 case 16:
2394                         i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3);
2395                         i |= 0x070707;
2396                         break;
2397                 case 24:
2398                         break;
2399                 default:    /* 18 bits... */
2400                         i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2);
2401                         i |= 0x030303;
2402                         break;
2403         }
2404
2405         return i;
2406 }
2407
2408 #endif
2409
2410
2411 void GPU_select_index_set(int index)
2412 {
2413         const int col = index_to_framebuffer(index);
2414         glColor3ub(( (col)        & 0xFF),
2415                    (((col) >>  8) & 0xFF),
2416                    (((col) >> 16) & 0xFF));
2417 }
2418
2419 void GPU_select_index_get(int index, int *r_col)
2420 {
2421         const int col = index_to_framebuffer(index);
2422         char *c_col = (char *)r_col;
2423         c_col[0] = (col & 0xFF); /* red */
2424         c_col[1] = ((col >>  8) & 0xFF); /* green */
2425         c_col[2] = ((col >> 16) & 0xFF); /* blue */
2426         c_col[3] = 0xFF; /* alpha */
2427 }
2428
2429
2430 #define INDEX_FROM_BUF_8(col)     ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6))
2431 #define INDEX_FROM_BUF_12(col)    ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8)  + (((col) & 0xF0) >> 4))
2432 #define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9)  + (((col) & 0xF800) >> 6)  + (((col) & 0xF8) >> 3))
2433 #define INDEX_FROM_BUF_18(col)    ((((col) & 0xFC0000) >> 6)  + (((col) & 0xFC00) >> 4)  + (((col) & 0xFC) >> 2))
2434 #define INDEX_FROM_BUF_24(col)      ((col) & 0xFFFFFF)
2435
2436 int GPU_select_to_index(unsigned int col)
2437 {
2438         if (col == 0) {
2439                 return 0;
2440         }
2441
2442         switch (GPU_color_depth()) {
2443                 case  8: return INDEX_FROM_BUF_8(col);
2444                 case 12: return INDEX_FROM_BUF_12(col);
2445                 case 15:
2446                 case 16: return INDEX_FROM_BUF_15_16(col);
2447                 case 24: return INDEX_FROM_BUF_24(col);
2448                 default: return INDEX_FROM_BUF_18(col);
2449         }
2450 }
2451
2452 void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
2453 {
2454 #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
2455         for (i = size; i--; col++) { \
2456             if ((c = *col)) { \
2457                 *col = INDEX_FROM_BUF_BITS(c); \
2458         } \
2459     } ((void)0)
2460
2461         if (size > 0) {
2462                 unsigned int i, c;
2463
2464                 switch (GPU_color_depth()) {
2465                         case  8:
2466                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_8);
2467                                 break;
2468                         case 12:
2469                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_12);
2470                                 break;
2471                         case 15:
2472                         case 16:
2473                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16);
2474                                 break;
2475                         case 24:
2476                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_24);
2477                                 break;
2478                         default:
2479                                 INDEX_BUF_ARRAY(INDEX_FROM_BUF_18);
2480                                 break;
2481                 }
2482         }
2483
2484 #undef INDEX_BUF_ARRAY
2485 }
2486
2487 /**
2488  * Replacement for glPush/PopAttributes
2489  *
2490  * We don't need to cover all the options of legacy OpenGL
2491  * but simply the ones used by Blender.
2492  */
2493 void gpuSaveState(GPUStateValues *values, eGPUStateMask mask)
2494 {
2495         values->mask = mask;
2496
2497         if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
2498                 values->is_depth_test = glIsEnabled(GL_DEPTH_TEST);
2499                 glGetIntegerv(GL_DEPTH_FUNC, &values->depth_func);
2500                 glGetDoublev(GL_DEPTH_CLEAR_VALUE, &values->depth_clear_value);
2501                 glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&values->depth_write_mask);
2502         }
2503
2504         if ((mask & GPU_ENABLE_BIT) != 0) {
2505                 values->is_alpha_test = glIsEnabled(GL_ALPHA_TEST);
2506                 values->is_blend = glIsEnabled(GL_BLEND);
2507
2508                 for (int i = 0; i < 6; i++) {
2509                         values->is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
2510                 }
2511
2512                 values->is_cull_face = glIsEnabled(GL_CULL_FACE);
2513                 values->is_depth_test = glIsEnabled(GL_DEPTH_TEST);
2514                 values->is_dither = glIsEnabled(GL_DITHER);
2515
2516                 for (int i = 0; i < 8; i++) {
2517                         values->is_light[i] = glIsEnabled(GL_LIGHT0 + i);
2518                 }
2519
2520                 values->is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
2521                 values->is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
2522                 values->is_map1_vertex3 = glIsEnabled(GL_MAP1_VERTEX_3);
2523                 values->is_multisample = glIsEnabled(GL_MULTISAMPLE);
2524                 values->is_normalize = glIsEnabled(GL_NORMALIZE);
2525                 values->is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
2526                 values->is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
2527                 values->is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
2528                 values->is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
2529                 values->is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
2530                 values->is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
2531                 values->is_texture_2d = glIsEnabled(GL_TEXTURE_2D);
2532         }
2533
2534         if ((mask & GPU_SCISSOR_BIT) != 0) {
2535                 values->is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
2536                 glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&values->scissor_box);
2537         }
2538
2539         if ((mask & GPU_VIEWPORT_BIT) != 0) {
2540                 glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&values->near_far);
2541                 glGetIntegerv(GL_VIEWPORT, (GLint *)&values->viewport);
2542         }
2543
2544         if ((mask & GPU_BLEND_BIT) != 0) {
2545                 values->is_blend = glIsEnabled(GL_BLEND);
2546         }
2547 }
2548
2549 static void restore_mask(GLenum cap, const bool value) {
2550         if (value) {
2551                 glEnable(cap);
2552         }
2553         else {
2554                 glDisable(cap);
2555         }
2556 }
2557
2558 void gpuRestoreState(GPUStateValues *values)
2559 {
2560         GLint mask = values->mask;
2561
2562         if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
2563                 restore_mask(GL_DEPTH_TEST, values->is_depth_test);
2564                 glDepthFunc(values->depth_func);
2565                 glClearDepth(values->depth_clear_value);
2566                 glDepthMask(values->depth_write_mask);
2567         }
2568
2569         if ((mask & GPU_ENABLE_BIT) != 0) {
2570                 restore_mask(GL_ALPHA_TEST, values->is_alpha_test);
2571                 restore_mask(GL_BLEND, values->is_blend);
2572
2573                 for (int i = 0; i < 6; i++) {
2574                         restore_mask(GL_CLIP_PLANE0 + i, values->is_clip_plane[i]);
2575                 }
2576
2577                 restore_mask(GL_CULL_FACE, values->is_cull_face);
2578                 restore_mask(GL_DEPTH_TEST, values->is_depth_test);
2579                 restore_mask(GL_DITHER, values->is_dither);
2580
2581                 for (int i = 0; i < 6; i++) {
2582                         restore_mask(GL_LIGHT0 + i, values->is_light[i]);
2583                 }
2584
2585                 restore_mask(GL_LINE_SMOOTH, values->is_line_smooth);
2586                 restore_mask(GL_COLOR_LOGIC_OP, values->is_color_logic_op);
2587                 restore_mask(GL_MAP1_VERTEX_3, values->is_map1_vertex3);
2588                 restore_mask(GL_MULTISAMPLE, values->is_multisample);
2589                 restore_mask(GL_NORMALIZE, values->is_normalize);
2590                 restore_mask(GL_POLYGON_OFFSET_LINE, values->is_polygon_offset_line);
2591                 restore_mask(GL_POLYGON_OFFSET_FILL, values->is_polygon_offset_fill);
2592                 restore_mask(GL_POLYGON_SMOOTH, values->is_polygon_smooth);
2593                 restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, values->is_sample_alpha_to_coverage);
2594                 restore_mask(GL_SCISSOR_TEST, values->is_scissor_test);
2595                 restore_mask(GL_STENCIL_TEST, values->is_stencil_test);
2596                 restore_mask(GL_TEXTURE_2D, values->is_texture_2d);
2597         }
2598
2599         if ((mask & GPU_VIEWPORT_BIT) != 0) {
2600                 glViewport(values->viewport[0], values->viewport[1], values->viewport[2], values->viewport[3]);
2601                 glDepthRange(values->near_far[0], values->near_far[1]);
2602         }
2603
2604         if ((mask & GPU_SCISSOR_BIT) != 0) {
2605                 restore_mask(GL_SCISSOR_TEST, values->is_scissor_test);
2606                 glScissor(values->scissor_box[0], values->scissor_box[1], values->scissor_box[2], values->scissor_box[3]);
2607         }
2608
2609         if ((mask & GPU_BLEND_BIT) != 0) {
2610                 restore_mask(GL_BLEND, values->is_blend);
2611         }
2612 }
2613
2614 /** \} */