2nd try to merge sim_physics with trunk rev 19825
[blender.git] / source / blender / gpu / intern / gpu_draw.c
1 /**
2  * $Id: gpu_draw.c 19616 2009-04-09 10:05:17Z campbellbarton $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2005 Blender Foundation.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): Brecht Van Lommel.
29  *
30  * ***** END GPL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34
35 #include "GL/glew.h"
36
37 #include "DNA_image_types.h"
38 #include "DNA_lamp_types.h"
39 #include "DNA_material_types.h"
40 #include "DNA_meshdata_types.h"
41 #include "DNA_node_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_userdef_types.h"
45 #include "DNA_view3d_types.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include "IMB_imbuf.h"
50 #include "IMB_imbuf_types.h"
51
52 #include "BKE_bmfont.h"
53 #include "BKE_global.h"
54 #include "BKE_image.h"
55 #include "BKE_main.h"
56 #include "BKE_material.h"
57 #include "BKE_node.h"
58 #include "BKE_object.h"
59 #include "BKE_utildefines.h"
60
61 #include "GPU_extensions.h"
62 #include "GPU_material.h"
63 #include "GPU_draw.h"
64
65 /* These are some obscure rendering functions shared between the
66  * game engine and the blender, in this module to avoid duplicaten
67  * and abstract them away from the rest a bit */
68
69 /* Text Rendering */
70
71 static void gpu_mcol(unsigned int ucol)
72 {
73         /* mcol order is swapped */
74         char *cp= (char *)&ucol;
75         glColor3ub(cp[3], cp[2], cp[1]);
76 }
77
78 void GPU_render_text(MTFace *tface, int mode,
79         const char *textstr, int textlen, unsigned int *col,
80         float *v1, float *v2, float *v3, float *v4, int glattrib)
81 {
82         if (mode & TF_BMFONT) {
83                 Image* ima;
84                 int characters, index, character;
85                 float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
86                 float advance_tab;
87                 
88                 
89                 /* multiline */
90                 float line_start= 0.0f, line_height; 
91                 if (v4)
92                         line_height= MAX4(v1[1], v2[1], v3[1], v4[2]) - MIN4(v1[1], v2[1], v3[1], v4[2]);
93                 else
94                         line_height= MAX3(v1[1], v2[1], v3[1]) - MIN3(v1[1], v2[1], v3[1]);
95                 line_height *= 1.2; /* could be an option? */
96                 /* end multiline */
97                 
98                 characters = textlen;
99
100                 ima = (Image*)tface->tpage;
101                 if (ima == NULL)
102                         characters = 0;
103
104                 // color has been set
105                 if (tface->mode & TF_OBCOL)
106                         col= NULL;
107                 else if (!col)
108                         glColor3f(1.0f, 1.0f, 1.0f);
109
110                 glPushMatrix();
111                 
112                 /* get the tab width */
113                 matrixGlyph((ImBuf *)ima->ibufs.first, ' ', & centerx, &centery,
114                         &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
115                 
116                 advance_tab= advance * 4; /* tab width could also be an option */
117                 
118                 
119                 for (index = 0; index < characters; index++) {
120                         float uv[4][2];
121
122                         // lets calculate offset stuff
123                         character = textstr[index];
124                         
125                         if (character=='\n') {
126                                 glTranslatef(line_start, -line_height, 0.0);
127                                 line_start = 0.0f;
128                                 continue;
129                         }
130                         else if (character=='\t') {
131                                 glTranslatef(advance_tab, 0.0, 0.0);
132                                 line_start -= advance_tab; /* so we can go back to the start of the line */
133                                 continue;
134                                 
135                         }
136                         
137                         // space starts at offset 1
138                         // character = character - ' ' + 1;
139                         matrixGlyph((ImBuf *)ima->ibufs.first, character, & centerx, &centery,
140                                 &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
141
142                         uv[0][0] = (tface->uv[0][0] - centerx) * sizex + transx;
143                         uv[0][1] = (tface->uv[0][1] - centery) * sizey + transy;
144                         uv[1][0] = (tface->uv[1][0] - centerx) * sizex + transx;
145                         uv[1][1] = (tface->uv[1][1] - centery) * sizey + transy;
146                         uv[2][0] = (tface->uv[2][0] - centerx) * sizex + transx;
147                         uv[2][1] = (tface->uv[2][1] - centery) * sizey + transy;
148                         
149                         glBegin(GL_POLYGON);
150                         if(glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[0]);
151                         else glTexCoord2fv(uv[0]);
152                         if(col) gpu_mcol(col[0]);
153                         glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
154                         
155                         if(glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[1]);
156                         else glTexCoord2fv(uv[1]);
157                         if(col) gpu_mcol(col[1]);
158                         glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
159
160                         if(glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[2]);
161                         else glTexCoord2fv(uv[2]);
162                         if(col) gpu_mcol(col[2]);
163                         glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
164
165                         if(v4) {
166                                 uv[3][0] = (tface->uv[3][0] - centerx) * sizex + transx;
167                                 uv[3][1] = (tface->uv[3][1] - centery) * sizey + transy;
168
169                                 if(glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[3]);
170                                 else glTexCoord2fv(uv[3]);
171                                 if(col) gpu_mcol(col[3]);
172                                 glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
173                         }
174                         glEnd();
175
176                         glTranslatef(advance, 0.0, 0.0);
177                         line_start -= advance; /* so we can go back to the start of the line */
178                 }
179                 glPopMatrix();
180         }
181 }
182
183 /* Checking powers of two for images since opengl 1.x requires it */
184
185 static int is_pow2(int num)
186 {
187         /* (n&(n-1)) zeros the least significant bit of n */
188         return ((num)&(num-1))==0;
189 }
190
191 static int smaller_pow2(int num)
192 {
193         while (!is_pow2(num))
194                 num= num&(num-1);
195
196         return num;     
197 }
198
199 static int is_pow2_limit(int num)
200 {
201         /* take texture clamping into account */
202         if (G.f & G_TEXTUREPAINT)
203                 return 1;
204         if (U.glreslimit != 0 && num > U.glreslimit)
205                 return 0;
206
207         return ((num)&(num-1))==0;
208 }
209
210 static int smaller_pow2_limit(int num)
211 {
212         if (G.f & G_TEXTUREPAINT)
213                 return 1;
214         
215         /* take texture clamping into account */
216         if (U.glreslimit != 0 && num > U.glreslimit)
217                 return U.glreslimit;
218
219         return smaller_pow2(num);
220 }
221
222 /* Current OpenGL state caching for GPU_set_tpage */
223
224 static struct GPUTextureState {
225         int curtile, tile;
226         int curtilemode, tilemode;
227         int curtileXRep, tileXRep;
228         int curtileYRep, tileYRep;
229         Image *ima, *curima;
230
231         int domipmap, linearmipmap;
232
233         int alphamode;
234         MTFace *lasttface;
235 } GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, -1, NULL};
236
237 /* Mipmap settings */
238
239 void GPU_set_mipmap(int mipmap)
240 {
241         if (GTS.domipmap != (mipmap != 0)) {
242                 GPU_free_images();
243                 GTS.domipmap = mipmap != 0;
244         }
245 }
246
247 void GPU_set_linear_mipmap(int linear)
248 {
249         if (GTS.linearmipmap != (linear != 0)) {
250                 GPU_free_images();
251                 GTS.linearmipmap = linear != 0;
252         }
253 }
254
255 static int gpu_get_mipmap(void)
256 {
257         return GTS.domipmap && (!(G.f & G_TEXTUREPAINT));
258 }
259
260 static GLenum gpu_get_mipmap_filter(int mag)
261 {
262         /* linearmipmap is off by default *when mipmapping is off,
263          * use unfiltered display */
264         if(mag) {
265                 if(GTS.linearmipmap || GTS.domipmap)
266                         return GL_LINEAR;
267                 else
268                         return GL_NEAREST;
269         }
270         else {
271                 if(GTS.linearmipmap)
272                         return GL_LINEAR_MIPMAP_LINEAR;
273                 else if(GTS.domipmap)
274                         return GL_LINEAR_MIPMAP_NEAREST;
275                 else
276                         return GL_NEAREST;
277         }
278 }
279
280 /* Set OpenGL state for an MTFace */
281
282 static void gpu_make_repbind(Image *ima)
283 {
284         ImBuf *ibuf;
285         
286         ibuf = BKE_image_get_ibuf(ima, NULL);
287         if(ibuf==NULL)
288                 return;
289
290         if(ima->repbind) {
291                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
292                 MEM_freeN(ima->repbind);
293                 ima->repbind= 0;
294                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
295         }
296
297         ima->totbind= ima->xrep*ima->yrep;
298
299         if(ima->totbind>1)
300                 ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
301 }
302
303 static void gpu_clear_tpage()
304 {
305         if(GTS.lasttface==0)
306                 return;
307         
308         GTS.lasttface= 0;
309         GTS.curtile= 0;
310         GTS.curima= 0;
311         if(GTS.curtilemode!=0) {
312                 glMatrixMode(GL_TEXTURE);
313                 glLoadIdentity();
314                 glMatrixMode(GL_MODELVIEW);
315         }
316         GTS.curtilemode= 0;
317         GTS.curtileXRep=0;
318         GTS.curtileYRep=0;
319         GTS.alphamode= -1;
320         
321         glDisable(GL_BLEND);
322         glDisable(GL_TEXTURE_2D);
323         glDisable(GL_TEXTURE_GEN_S);
324         glDisable(GL_TEXTURE_GEN_T);
325         glDisable(GL_ALPHA_TEST);
326 }
327
328 static void gpu_set_blend_mode(GPUBlendMode blendmode)
329 {
330         if(blendmode == GPU_BLEND_SOLID) {
331                 glDisable(GL_BLEND);
332                 glDisable(GL_ALPHA_TEST);
333                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
334         }
335         else if(blendmode==GPU_BLEND_ADD) {
336                 glEnable(GL_BLEND);
337                 glBlendFunc(GL_ONE, GL_ONE);
338                 glDisable(GL_ALPHA_TEST);
339         }
340         else if(blendmode==GPU_BLEND_ALPHA) {
341                 glEnable(GL_BLEND);
342                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
343                 
344                 /* if U.glalphaclip == 1.0, some cards go bonkers...
345                  * turn off alpha test in this case */
346
347                 /* added after 2.45 to clip alpha */
348                 if(U.glalphaclip == 1.0) {
349                         glDisable(GL_ALPHA_TEST);
350                 }
351                 else {
352                         glEnable(GL_ALPHA_TEST);
353                         glAlphaFunc(GL_GREATER, U.glalphaclip);
354                 }
355         }
356         else if(blendmode==GPU_BLEND_CLIP) {
357                 glDisable(GL_BLEND); 
358                 glEnable(GL_ALPHA_TEST);
359                 glAlphaFunc(GL_GREATER, 0.5f);
360         }
361 }
362
363 static void gpu_verify_alpha_mode(MTFace *tface)
364 {
365         /* verify alpha blending modes */
366         if(GTS.alphamode == tface->transp)
367                 return;
368
369         gpu_set_blend_mode(tface->transp);
370         GTS.alphamode= tface->transp;
371 }
372
373 static void gpu_verify_reflection(Image *ima)
374 {
375         if (ima && (ima->flag & IMA_REFLECT)) {
376                 /* enable reflection mapping */
377                 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
378                 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
379
380                 glEnable(GL_TEXTURE_GEN_S);
381                 glEnable(GL_TEXTURE_GEN_T);
382         }
383         else {
384                 /* disable reflection mapping */
385                 glDisable(GL_TEXTURE_GEN_S);
386                 glDisable(GL_TEXTURE_GEN_T);
387         }
388 }
389
390 int GPU_verify_image(Image *ima, int tftile, int tfmode, int compare)
391 {
392         ImBuf *ibuf = NULL;
393         unsigned int *bind = NULL;
394         int rectw, recth, tpx=0, tpy=0, y;
395         unsigned int *rectrow, *tilerectrow;
396         unsigned int *tilerect= NULL, *scalerect= NULL, *rect= NULL;
397         short texwindx, texwindy, texwinsx, texwinsy;
398
399         /* initialize tile mode and number of repeats */
400         GTS.ima = ima;
401         GTS.tilemode= (tfmode & TF_TILES) || (ima && (ima->tpageflag & IMA_TWINANIM));
402         GTS.tileXRep = 0;
403         GTS.tileYRep = 0;
404
405         /* setting current tile according to frame */
406         if(ima && (ima->tpageflag & IMA_TWINANIM))
407                 GTS.tile= ima->lastframe;
408         else
409                 GTS.tile= tftile;
410
411         GTS.tile = MAX2(0, GTS.tile);
412
413         if(ima) {
414                 GTS.tileXRep = ima->xrep;
415                 GTS.tileYRep = ima->yrep;
416         }
417
418         /* if same image & tile, we're done */
419         if(compare && ima == GTS.curima && GTS.curtile == GTS.tile &&
420            GTS.tilemode == GTS.curtilemode && GTS.curtileXRep == GTS.tileXRep &&
421            GTS.curtileYRep == GTS.tileYRep)
422                 return (ima!=0);
423
424         /* if tiling mode or repeat changed, change texture matrix to fit */
425         if(GTS.tilemode!=GTS.curtilemode || GTS.curtileXRep!=GTS.tileXRep ||
426            GTS.curtileYRep != GTS.tileYRep) {
427
428                 glMatrixMode(GL_TEXTURE);
429                 glLoadIdentity();
430
431                 if((tfmode & TF_TILES) && ima!=NULL)
432                         glScalef(ima->xrep, ima->yrep, 1.0);
433
434                 glMatrixMode(GL_MODELVIEW);
435         }
436
437         /* check if we have a valid image */
438         if(ima==NULL || ima->ok==0)
439                 return 0;
440
441         /* check if we have a valid image buffer */
442         ibuf= BKE_image_get_ibuf(ima, NULL);
443
444         if(ibuf==NULL)
445                 return 0;
446
447         /* ensure we have a char buffer and not only float */
448         if ((ibuf->rect==NULL) && ibuf->rect_float)
449                 IMB_rect_from_float(ibuf);
450
451         if(GTS.tilemode) {
452                 /* tiled mode */
453                 if(ima->repbind==0) gpu_make_repbind(ima);
454                 if(GTS.tile>=ima->totbind) GTS.tile= 0;
455                 
456                 /* this happens when you change repeat buttons */
457                 if(ima->repbind) bind= &ima->repbind[GTS.tile];
458                 else bind= &ima->bindcode;
459                 
460                 if(*bind==0) {
461                         
462                         texwindx= ibuf->x/ima->xrep;
463                         texwindy= ibuf->y/ima->yrep;
464                         
465                         if(GTS.tile>=ima->xrep*ima->yrep)
466                                 GTS.tile= ima->xrep*ima->yrep-1;
467         
468                         texwinsy= GTS.tile / ima->xrep;
469                         texwinsx= GTS.tile - texwinsy*ima->xrep;
470         
471                         texwinsx*= texwindx;
472                         texwinsy*= texwindy;
473         
474                         tpx= texwindx;
475                         tpy= texwindy;
476
477                         rect= ibuf->rect + texwinsy*ibuf->x + texwinsx;
478                 }
479         }
480         else {
481                 /* regular image mode */
482                 bind= &ima->bindcode;
483                 
484                 if(*bind==0) {
485                         tpx= ibuf->x;
486                         tpy= ibuf->y;
487                         rect= ibuf->rect;
488                 }
489         }
490
491         if(*bind != 0) {
492                 /* enable opengl drawing with textures */
493                 glBindTexture(GL_TEXTURE_2D, *bind);
494                 return *bind;
495         }
496
497         rectw = tpx;
498         recth = tpy;
499
500         /* for tiles, copy only part of image into buffer */
501         if (GTS.tilemode) {
502                 tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
503
504                 for (y=0; y<recth; y++) {
505                         rectrow= &rect[y*ibuf->x];
506                         tilerectrow= &tilerect[y*rectw];
507                                 
508                         memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
509                 }
510                         
511                 rect= tilerect;
512         }
513
514         /* scale if not a power of two */
515         if (!is_pow2_limit(rectw) || !is_pow2_limit(recth)) {
516                 rectw= smaller_pow2_limit(rectw);
517                 recth= smaller_pow2_limit(recth);
518                 
519                 scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
520                 gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
521                 rect= scalerect;
522         }
523
524         /* create image */
525         glGenTextures(1, (GLuint *)bind);
526         glBindTexture( GL_TEXTURE_2D, *bind);
527
528         if (!gpu_get_mipmap()) {
529                 glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA,  rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
530                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
531                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
532         }
533         else {
534                 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
535                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
536                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
537
538                 ima->tpageflag |= IMA_MIPMAP_COMPLETE;
539         }
540
541         /* set to modulate with vertex color */
542         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
543                 
544         /* clean up */
545         if (tilerect)
546                 MEM_freeN(tilerect);
547         if (scalerect)
548                 MEM_freeN(scalerect);
549
550         return *bind;
551 }
552
553 static void gpu_verify_repeat(Image *ima)
554 {
555         /* set either clamp or repeat in X/Y */
556         if (ima->tpageflag & IMA_CLAMP_U)
557            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
558         else
559                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
560
561         if (ima->tpageflag & IMA_CLAMP_V)
562                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
563         else
564                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
565 }
566
567 int GPU_set_tpage(MTFace *tface)
568 {
569         Image *ima;
570         
571         /* check if we need to clear the state */
572         if(tface==0) {
573                 gpu_clear_tpage();
574                 return 0;
575         }
576
577         ima= tface->tpage;
578         GTS.lasttface= tface;
579
580         gpu_verify_alpha_mode(tface);
581         gpu_verify_reflection(ima);
582
583         if(GPU_verify_image(ima, tface->tile, tface->mode, 1)) {
584                 GTS.curtile= GTS.tile;
585                 GTS.curima= GTS.ima;
586                 GTS.curtilemode= GTS.tilemode;
587                 GTS.curtileXRep = GTS.tileXRep;
588                 GTS.curtileYRep = GTS.tileYRep;
589
590                 glEnable(GL_TEXTURE_2D);
591         }
592         else {
593                 glDisable(GL_TEXTURE_2D);
594                 
595                 GTS.curtile= 0;
596                 GTS.curima= 0;
597                 GTS.curtilemode= 0;
598                 GTS.curtileXRep = 0;
599                 GTS.curtileYRep = 0;
600
601                 return 0;
602         }
603         
604         gpu_verify_repeat(ima);
605         
606         /* Did this get lost in the image recode? */
607         /* tag_image_time(ima);*/
608
609         return 1;
610 }
611
612 /* these two functions are called on entering and exiting texture paint mode,
613    temporary disabling/enabling mipmapping on all images for quick texture
614    updates with glTexSubImage2D. images that didn't change don't have to be
615    re-uploaded to OpenGL */
616 void GPU_paint_set_mipmap(int mipmap)
617 {
618         Image* ima;
619         
620         if(!GTS.domipmap)
621                 return;
622
623         if(mipmap) {
624                 for(ima=G.main->image.first; ima; ima=ima->id.next) {
625                         if(ima->bindcode) {
626                                 if(ima->tpageflag & IMA_MIPMAP_COMPLETE) {
627                                         glBindTexture(GL_TEXTURE_2D, ima->bindcode);
628                                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
629                                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
630                                 }
631                                 else
632                                         GPU_free_image(ima);
633                         }
634                 }
635
636         }
637         else {
638                 for(ima=G.main->image.first; ima; ima=ima->id.next) {
639                         if(ima->bindcode) {
640                                 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
641                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
642                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
643                         }
644                 }
645         }
646 }
647
648 void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
649 {
650         ImBuf *ibuf;
651         
652         ibuf = BKE_image_get_ibuf(ima, NULL);
653         
654         if (ima->repbind || gpu_get_mipmap() || !ima->bindcode || !ibuf ||
655                 (!is_pow2(ibuf->x) || !is_pow2(ibuf->y)) ||
656                 (w == 0) || (h == 0)) {
657                 /* these cases require full reload still */
658                 GPU_free_image(ima);
659         }
660         else {
661                 /* for the special case, we can do a partial update
662                  * which is much quicker for painting */
663                 GLint row_length, skip_pixels, skip_rows;
664
665                 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
666                 glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
667                 glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
668
669                 if ((ibuf->rect==NULL) && ibuf->rect_float)
670                         IMB_rect_from_float(ibuf);
671
672                 glBindTexture(GL_TEXTURE_2D, ima->bindcode);
673
674                 glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
675                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
676                 glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
677
678                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
679                         GL_UNSIGNED_BYTE, ibuf->rect);
680
681                 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
682                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
683                 glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
684
685                 if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
686                         ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
687         }
688 }
689
690 void GPU_update_images_framechange(void)
691 {
692         Image *ima;
693         
694         for(ima=G.main->image.first; ima; ima=ima->id.next) {
695                 if(ima->tpageflag & IMA_TWINANIM) {
696                         if(ima->twend >= ima->xrep*ima->yrep)
697                                 ima->twend= ima->xrep*ima->yrep-1;
698                 
699                         /* check: is bindcode not in the array? free. (to do) */
700                         
701                         ima->lastframe++;
702                         if(ima->lastframe > ima->twend)
703                                 ima->lastframe= ima->twsta;
704                 }
705         }
706 }
707
708 int GPU_update_image_time(Image *ima, double time)
709 {
710         int     inc = 0;
711         float   diff;
712         int     newframe;
713
714         if (!ima)
715                 return 0;
716
717         if (ima->lastupdate<0)
718                 ima->lastupdate = 0;
719
720         if (ima->lastupdate>time)
721                 ima->lastupdate=(float)time;
722
723         if(ima->tpageflag & IMA_TWINANIM) {
724                 if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
725                 
726                 /* check: is the bindcode not in the array? Then free. (still to do) */
727                 
728                 diff = (float)(time-ima->lastupdate);
729                 inc = (int)(diff*(float)ima->animspeed);
730
731                 ima->lastupdate+=((float)inc/(float)ima->animspeed);
732
733                 newframe = ima->lastframe+inc;
734
735                 if(newframe > (int)ima->twend) {
736                         if(ima->twend-ima->twsta != 0)
737                                 newframe = (int)ima->twsta-1 + (newframe-ima->twend)%(ima->twend-ima->twsta);
738                         else
739                                 newframe = ima->twsta;
740                 }
741
742                 ima->lastframe = newframe;
743         }
744
745         return inc;
746 }
747
748 void GPU_free_image(Image *ima)
749 {
750         /* free regular image binding */
751         if(ima->bindcode) {
752                 glDeleteTextures(1, (GLuint *)&ima->bindcode);
753                 ima->bindcode= 0;
754                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
755         }
756
757         /* free glsl image binding */
758         if(ima->gputexture) {
759                 GPU_texture_free(ima->gputexture);
760                 ima->gputexture= NULL;
761         }
762
763         /* free repeated image binding */
764         if(ima->repbind) {
765                 glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
766         
767                 MEM_freeN(ima->repbind);
768                 ima->repbind= NULL;
769                 ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
770         }
771 }
772
773 void GPU_free_images(void)
774 {
775         Image* ima;
776
777         if(G.main)
778                 for(ima=G.main->image.first; ima; ima=ima->id.next)
779                         GPU_free_image(ima);
780 }
781
782 /* OpenGL Materials */
783
784 /* materials start counting at # one.... */
785 #define MAXMATBUF (MAXMAT+1)
786
787 /* OpenGL state caching for materials */
788
789 static struct GPUMaterialState {
790         float matbuf[MAXMATBUF][2][4];
791         int totmat;
792
793         Material *gmatbuf[MAXMATBUF];
794         Material *gboundmat;
795         Object *gob;
796         Scene *gscene;
797
798         GPUBlendMode blendmode[MAXMATBUF];
799         int alphapass;
800
801         int lastmatnr, lastretval;
802         GPUBlendMode lastblendmode;
803 } GMS;
804
805 Material *gpu_active_node_material(Material *ma)
806 {
807         if(ma && ma->use_nodes && ma->nodetree) {
808                 bNode *node= nodeGetActiveID(ma->nodetree, ID_MA);
809
810                 if(node)
811                         return (Material *)node->id;
812                 else
813                         return NULL;
814         }
815
816         return ma;
817 }
818
819 void GPU_set_object_materials(Scene *scene, Object *ob, int glsl, int *do_alpha_pass)
820 {
821         extern Material defmaterial; /* from material.c */
822         Material *ma;
823         GPUMaterial *gpumat;
824         GPUBlendMode blendmode;
825         int a;
826         
827         /* initialize state */
828         memset(&GMS, 0, sizeof(GMS));
829         GMS.lastmatnr = -1;
830         GMS.lastretval = -1;
831         GMS.lastblendmode = GPU_BLEND_SOLID;
832
833         GMS.gob = ob;
834         GMS.gscene = scene;
835         GMS.totmat= ob->totcol;
836
837         GMS.alphapass = (G.vd && G.vd->transp);
838         if(do_alpha_pass)
839                 *do_alpha_pass = 0;
840
841         /* no materials assigned? */
842         if(ob->totcol==0) {
843                 GMS.matbuf[0][0][0]= defmaterial.r;
844                 GMS.matbuf[0][0][1]= defmaterial.g;
845                 GMS.matbuf[0][0][2]= defmaterial.b;
846                 GMS.matbuf[0][0][3]= 1.0;
847
848                 GMS.matbuf[0][1][0]= defmaterial.specr;
849                 GMS.matbuf[0][1][1]= defmaterial.specg;
850                 GMS.matbuf[0][1][2]= defmaterial.specb;
851                 GMS.matbuf[0][1][3]= 1.0;
852                 
853                 /* do material 1 too, for displists! */
854                 QUATCOPY(GMS.matbuf[1][0], GMS.matbuf[0][0]);
855                 QUATCOPY(GMS.matbuf[1][1], GMS.matbuf[0][1]);
856
857                 if(glsl) {
858                         GMS.gmatbuf[0]= &defmaterial;
859                         GPU_material_from_blender(GMS.gscene, &defmaterial);
860                 }
861
862                 GMS.blendmode[0]= GPU_BLEND_SOLID;
863         }
864         
865         /* setup materials */
866         for(a=1; a<=ob->totcol; a++) {
867                 /* find a suitable material */
868                 ma= give_current_material(ob, a);
869                 if(!glsl) ma= gpu_active_node_material(ma);
870                 if(ma==NULL) ma= &defmaterial;
871
872                 /* this shouldn't happen .. */
873                 if(a>=MAXMATBUF)
874                         continue;
875
876                 /* create glsl material if requested */
877                 gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL;
878
879                 if(gpumat) {
880                         /* do glsl only if creating it succeed, else fallback */
881                         GMS.gmatbuf[a]= ma;
882                         blendmode = GPU_material_blend_mode(gpumat, ob->col);
883                 }
884                 else {
885                         /* fixed function opengl materials */
886                         if (ma->mode & MA_SHLESS) {
887                                 GMS.matbuf[a][0][0]= ma->r;
888                                 GMS.matbuf[a][0][1]= ma->g;
889                                 GMS.matbuf[a][0][2]= ma->b;
890                         } else {
891                                 GMS.matbuf[a][0][0]= (ma->ref+ma->emit)*ma->r;
892                                 GMS.matbuf[a][0][1]= (ma->ref+ma->emit)*ma->g;
893                                 GMS.matbuf[a][0][2]= (ma->ref+ma->emit)*ma->b;
894
895                                 GMS.matbuf[a][1][0]= ma->spec*ma->specr;
896                                 GMS.matbuf[a][1][1]= ma->spec*ma->specg;
897                                 GMS.matbuf[a][1][2]= ma->spec*ma->specb;
898                                 GMS.matbuf[a][1][3]= 1.0;
899                         }
900
901                         blendmode = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
902                         if(do_alpha_pass && GMS.alphapass)
903                                 GMS.matbuf[a][0][3]= ma->alpha;
904                         else
905                                 GMS.matbuf[a][0][3]= 1.0f;
906                 }
907
908                 /* setting do_alpha_pass = 1 indicates this object needs to be
909                  * drawn in a second alpha pass for improved blending */
910                 if(do_alpha_pass) {
911                         GMS.blendmode[a]= blendmode;
912                         if(ELEM(blendmode, GPU_BLEND_ALPHA, GPU_BLEND_ADD) && !GMS.alphapass)
913                                 *do_alpha_pass= 1;
914                 }
915         }
916
917         /* let's start with a clean state */
918         GPU_disable_material();
919 }
920
921 int GPU_enable_material(int nr, void *attribs)
922 {
923         GPUVertexAttribs *gattribs = attribs;
924         GPUMaterial *gpumat;
925         GPUBlendMode blendmode;
926
927         /* prevent index to use un-initialized array items */
928         if(nr>GMS.totmat)
929                 nr= GMS.totmat;
930
931         if(gattribs)
932                 memset(gattribs, 0, sizeof(*gattribs));
933
934         /* keep current material */
935         if(nr>=MAXMATBUF || nr==GMS.lastmatnr)
936                 return GMS.lastretval;
937
938         /* unbind glsl material */
939         if(GMS.gboundmat) {
940                 if(GMS.alphapass) glDepthMask(0);
941                 GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
942                 GMS.gboundmat= NULL;
943         }
944
945         /* draw materials with alpha in alpha pass */
946         GMS.lastmatnr = nr;
947         GMS.lastretval = ELEM(GMS.blendmode[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP);
948         if(GMS.alphapass)
949                 GMS.lastretval = !GMS.lastretval;
950
951         if(GMS.lastretval) {
952                 if(gattribs && GMS.gmatbuf[nr]) {
953                         /* bind glsl material and get attributes */
954                         Material *mat = GMS.gmatbuf[nr];
955
956                         gpumat = GPU_material_from_blender(GMS.gscene, mat);
957                         GPU_material_vertex_attributes(gpumat, gattribs);
958                         GPU_material_bind(gpumat, GMS.gob->lay, G.vd->lay, 1.0);
959                         GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, G.vd->viewmat, G.vd->viewinv, GMS.gob->col);
960                         GMS.gboundmat= mat;
961
962                         if(GMS.alphapass) glDepthMask(1);
963                 }
964                 else {
965                         /* or do fixed function opengl material */
966                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, GMS.matbuf[nr][0]);
967                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, GMS.matbuf[nr][1]);
968                 }
969
970                 /* set (alpha) blending mode */
971                 blendmode = (GMS.alphapass)? GPU_BLEND_ALPHA: GPU_BLEND_SOLID;
972                 GPU_set_material_blend_mode(blendmode);
973         }
974
975         return GMS.lastretval;
976 }
977
978 void GPU_set_material_blend_mode(int blendmode)
979 {
980         if(GMS.lastblendmode == blendmode)
981                 return;
982         
983         gpu_set_blend_mode(blendmode);
984         GMS.lastblendmode = blendmode;
985 }
986
987 int GPU_get_material_blend_mode(void)
988 {
989         return GMS.lastblendmode;
990 }
991
992 void GPU_disable_material(void)
993 {
994         GMS.lastmatnr= -1;
995         GMS.lastretval= 1;
996
997         if(GMS.gboundmat) {
998                 if(GMS.alphapass) glDepthMask(0);
999                 GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
1000                 GMS.gboundmat= NULL;
1001         }
1002
1003         GPU_set_material_blend_mode(GPU_BLEND_SOLID);
1004 }
1005
1006 /* Lights */
1007
1008 int GPU_default_lights(void)
1009 {
1010         int a, count = 0;
1011         
1012         /* initialize */
1013         if(U.light[0].flag==0 && U.light[1].flag==0 && U.light[2].flag==0) {
1014                 U.light[0].flag= 1;
1015                 U.light[0].vec[0]= -0.3; U.light[0].vec[1]= 0.3; U.light[0].vec[2]= 0.9;
1016                 U.light[0].col[0]= 0.8; U.light[0].col[1]= 0.8; U.light[0].col[2]= 0.8;
1017                 U.light[0].spec[0]= 0.5; U.light[0].spec[1]= 0.5; U.light[0].spec[2]= 0.5;
1018                 U.light[0].spec[3]= 1.0;
1019                 
1020                 U.light[1].flag= 0;
1021                 U.light[1].vec[0]= 0.5; U.light[1].vec[1]= 0.5; U.light[1].vec[2]= 0.1;
1022                 U.light[1].col[0]= 0.4; U.light[1].col[1]= 0.4; U.light[1].col[2]= 0.8;
1023                 U.light[1].spec[0]= 0.3; U.light[1].spec[1]= 0.3; U.light[1].spec[2]= 0.5;
1024                 U.light[1].spec[3]= 1.0;
1025         
1026                 U.light[2].flag= 0;
1027                 U.light[2].vec[0]= 0.3; U.light[2].vec[1]= -0.3; U.light[2].vec[2]= -0.2;
1028                 U.light[2].col[0]= 0.8; U.light[2].col[1]= 0.5; U.light[2].col[2]= 0.4;
1029                 U.light[2].spec[0]= 0.5; U.light[2].spec[1]= 0.4; U.light[2].spec[2]= 0.3;
1030                 U.light[2].spec[3]= 1.0;
1031         }
1032
1033         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
1034
1035         glLightfv(GL_LIGHT0, GL_POSITION, U.light[0].vec); 
1036         glLightfv(GL_LIGHT0, GL_DIFFUSE, U.light[0].col); 
1037         glLightfv(GL_LIGHT0, GL_SPECULAR, U.light[0].spec); 
1038
1039         glLightfv(GL_LIGHT1, GL_POSITION, U.light[1].vec); 
1040         glLightfv(GL_LIGHT1, GL_DIFFUSE, U.light[1].col); 
1041         glLightfv(GL_LIGHT1, GL_SPECULAR, U.light[1].spec); 
1042
1043         glLightfv(GL_LIGHT2, GL_POSITION, U.light[2].vec); 
1044         glLightfv(GL_LIGHT2, GL_DIFFUSE, U.light[2].col); 
1045         glLightfv(GL_LIGHT2, GL_SPECULAR, U.light[2].spec); 
1046
1047         for(a=0; a<8; a++) {
1048                 if(a<3) {
1049                         if(U.light[a].flag) {
1050                                 glEnable(GL_LIGHT0+a);
1051                                 count++;
1052                         }
1053                         else
1054                                 glDisable(GL_LIGHT0+a);
1055                         
1056                         // clear stuff from other opengl lamp usage
1057                         glLightf(GL_LIGHT0+a, GL_SPOT_CUTOFF, 180.0);
1058                         glLightf(GL_LIGHT0+a, GL_CONSTANT_ATTENUATION, 1.0);
1059                         glLightf(GL_LIGHT0+a, GL_LINEAR_ATTENUATION, 0.0);
1060                 }
1061                 else
1062                         glDisable(GL_LIGHT0+a);
1063         }
1064         
1065         glDisable(GL_LIGHTING);
1066
1067         glDisable(GL_COLOR_MATERIAL);
1068
1069         return count;
1070 }
1071
1072 int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[][4], int ortho)
1073 {
1074         Base *base;
1075         Lamp *la;
1076         int count;
1077         float position[4], direction[4], energy[4];
1078         
1079         /* disable all lights */
1080         for(count=0; count<8; count++)
1081                 glDisable(GL_LIGHT0+count);
1082         
1083         /* view direction for specular is not compute correct by default in
1084          * opengl, so we set the settings ourselfs */
1085         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (ortho)? GL_FALSE: GL_TRUE);
1086
1087         count= 0;
1088         
1089         for(base=scene->base.first; base; base=base->next) {
1090                 if(base->object->type!=OB_LAMP)
1091                         continue;
1092
1093                 if(!(base->lay & lay) || !(base->lay & ob->lay))
1094                         continue;
1095
1096                 la= base->object->data;
1097                 
1098                 /* setup lamp transform */
1099                 glPushMatrix();
1100                 glLoadMatrixf((float *)viewmat);
1101                 
1102                 where_is_object_simul(base->object);
1103                 
1104                 if(la->type==LA_SUN) {
1105                         /* sun lamp */
1106                         VECCOPY(direction, base->object->obmat[2]);
1107                         direction[3]= 0.0;
1108
1109                         glLightfv(GL_LIGHT0+count, GL_POSITION, direction); 
1110                 }
1111                 else {
1112                         /* other lamps with attenuation */
1113                         VECCOPY(position, base->object->obmat[3]);
1114                         position[3]= 1.0f;
1115
1116                         glLightfv(GL_LIGHT0+count, GL_POSITION, position); 
1117                         glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
1118                         glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
1119                         glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
1120                         
1121                         if(la->type==LA_SPOT) {
1122                                 /* spot lamp */
1123                                 direction[0]= -base->object->obmat[2][0];
1124                                 direction[1]= -base->object->obmat[2][1];
1125                                 direction[2]= -base->object->obmat[2][2];
1126                                 glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, direction);
1127                                 glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
1128                                 glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
1129                         }
1130                         else
1131                                 glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
1132                 }
1133                 
1134                 /* setup energy */
1135                 energy[0]= la->energy*la->r;
1136                 energy[1]= la->energy*la->g;
1137                 energy[2]= la->energy*la->b;
1138                 energy[3]= 1.0;
1139
1140                 glLightfv(GL_LIGHT0+count, GL_DIFFUSE, energy); 
1141                 glLightfv(GL_LIGHT0+count, GL_SPECULAR, energy);
1142                 glEnable(GL_LIGHT0+count);
1143                 
1144                 glPopMatrix();                                  
1145                 
1146                 count++;
1147                 if(count==8)
1148                         break;
1149         }
1150
1151         return count;
1152 }
1153
1154 /* Default OpenGL State */
1155
1156 void GPU_state_init(void)
1157 {
1158         /* also called when doing opengl rendering and in the game engine */
1159         float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
1160         float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
1161         float mat_shininess[] = { 35.0 };
1162         int a, x, y;
1163         GLubyte pat[32*32];
1164         const GLubyte *patc= pat;
1165         
1166         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
1167         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
1168         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
1169         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
1170
1171         GPU_default_lights();
1172         
1173         glDepthFunc(GL_LEQUAL);
1174         /* scaling matrices */
1175         glEnable(GL_NORMALIZE);
1176
1177         glShadeModel(GL_FLAT);
1178
1179         glDisable(GL_ALPHA_TEST);
1180         glDisable(GL_BLEND);
1181         glDisable(GL_DEPTH_TEST);
1182         glDisable(GL_FOG);
1183         glDisable(GL_LIGHTING);
1184         glDisable(GL_LOGIC_OP);
1185         glDisable(GL_STENCIL_TEST);
1186         glDisable(GL_TEXTURE_1D);
1187         glDisable(GL_TEXTURE_2D);
1188
1189         /* default on, disable/enable should be local per function */
1190         glEnableClientState(GL_VERTEX_ARRAY);
1191         glEnableClientState(GL_NORMAL_ARRAY);
1192         
1193         glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
1194         glPixelTransferi(GL_RED_SCALE, 1);
1195         glPixelTransferi(GL_RED_BIAS, 0);
1196         glPixelTransferi(GL_GREEN_SCALE, 1);
1197         glPixelTransferi(GL_GREEN_BIAS, 0);
1198         glPixelTransferi(GL_BLUE_SCALE, 1);
1199         glPixelTransferi(GL_BLUE_BIAS, 0);
1200         glPixelTransferi(GL_ALPHA_SCALE, 1);
1201         glPixelTransferi(GL_ALPHA_BIAS, 0);
1202         
1203         glPixelTransferi(GL_DEPTH_BIAS, 0);
1204         glPixelTransferi(GL_DEPTH_SCALE, 1);
1205         glDepthRange(0.0, 1.0);
1206         
1207         a= 0;
1208         for(x=0; x<32; x++) {
1209                 for(y=0; y<4; y++) {
1210                         if( (x) & 1) pat[a++]= 0x88;
1211                         else pat[a++]= 0x22;
1212                 }
1213         }
1214         
1215         glPolygonStipple(patc);
1216
1217         glMatrixMode(GL_TEXTURE);
1218         glLoadIdentity();
1219         glMatrixMode(GL_MODELVIEW);
1220
1221         glFrontFace(GL_CCW);
1222         glCullFace(GL_BACK);
1223         glDisable(GL_CULL_FACE);
1224 }
1225