Smoke:
[blender.git] / source / blender / gpu / intern / gpu_extensions.c
1 /**
2  * $Id$
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 "GL/glew.h"
34
35 #include "DNA_listBase.h"
36 #include "DNA_image_types.h"
37 #include "DNA_userdef_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BKE_image.h"
42 #include "BKE_global.h"
43 #include "BKE_utildefines.h"
44
45 #include "IMB_imbuf.h"
46 #include "IMB_imbuf_types.h"
47
48 #include "BLI_blenlib.h"
49
50 #include "GPU_draw.h"
51 #include "GPU_extensions.h"
52
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56
57 /* Extensions support */
58
59 /* extensions used:
60         - texture border clamp: 1.3 core
61         - fragement shader: 2.0 core
62         - framebuffer object: ext specification
63         - multitexture 1.3 core
64         - arb non power of two: 2.0 core
65         - pixel buffer objects? 2.1 core
66         - arb draw buffers? 2.0 core
67 */
68
69 static struct GPUGlobal {
70         GLint maxtextures;
71         GLuint currentfb;
72         int minimumsupport;
73         int extdisabled;
74 } GG = {1, 0, 0, 0};
75
76 void GPU_extensions_disable()
77 {
78         GG.extdisabled = 1;
79 }
80
81 void GPU_extensions_init()
82 {
83         glewInit();
84
85         /* glewIsSupported("GL_VERSION_2_0") */
86
87         if (GLEW_ARB_multitexture)
88                 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures);
89
90         GG.minimumsupport = 1;
91         if (!GLEW_ARB_multitexture) GG.minimumsupport = 0;
92         if (!GLEW_ARB_vertex_shader) GG.minimumsupport = 0;
93         if (!GLEW_ARB_fragment_shader) GG.minimumsupport = 0;
94 }
95
96 int GPU_extensions_minimum_support()
97 {
98         return !GG.extdisabled && GG.minimumsupport;
99 }
100
101 int GPU_print_error(char *str)
102 {
103         GLenum errCode;
104
105         if (G.f & G_DEBUG) {
106                 if ((errCode = glGetError()) != GL_NO_ERROR) {
107             fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode));
108                         return 1;
109                 }
110         }
111
112         return 0;
113 }
114
115 static void GPU_print_framebuffer_error(GLenum status)
116 {
117         fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d\n",
118                 (int)status);
119
120         switch(status) {
121                 case GL_FRAMEBUFFER_COMPLETE_EXT:
122                         break;
123                 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
124                         fprintf(stderr, "Incomplete attachment.\n");
125                         break;
126                 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
127                         fprintf(stderr, "Unsupported framebuffer format.\n");
128                         break;
129                 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
130                         fprintf(stderr, "Missing attachment.\n");
131                         break;
132                 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
133                         fprintf(stderr, "Attached images must have same dimensions.\n");
134                         break;
135                 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
136                          fprintf(stderr, "Attached images must have same format.\n");
137                         break;
138                 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
139                         fprintf(stderr, "Missing draw buffer.\n");
140                         break;
141                 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
142                         fprintf(stderr, "Missing read buffer.\n");
143                         break;
144                 default:
145                         fprintf(stderr, "Unknown.\n");
146                         break;
147         }
148 }
149
150 /* GPUTexture */
151
152 struct GPUTexture {
153         int w, h;                               /* width/height */
154         int number;                             /* number for multitexture binding */
155         int refcount;                   /* reference count */
156         GLenum target;                  /* GL_TEXTURE_* */
157         GLuint bindcode;                /* opengl identifier for texture */
158         int fromblender;                /* we got the texture from Blender */
159
160         GPUFrameBuffer *fb;             /* GPUFramebuffer this texture is attached to */
161         int depth;                              /* is a depth texture? */
162 };
163
164 static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
165 {
166         unsigned char *pixels, *p;
167         float *fp;
168         int a, len;
169
170         len = 4*length;
171         fp = fpixels;
172         p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
173
174         for (a=0; a<len; a++, p++, fp++)
175                 *p = FTOCHAR((*fp));
176
177         return pixels;
178 }
179
180 static int is_pow2(int n)
181 {
182         return ((n)&(n-1))==0;
183 }
184
185 static int larger_pow2(int n)
186 {
187         if (is_pow2(n))
188                 return n;
189
190         while(!is_pow2(n))
191                 n= n&(n-1);
192
193         return n*2;
194 }
195
196 static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
197 {
198         void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels");
199
200         if (target == GL_TEXTURE_1D)
201                 glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
202         else
203                 glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
204         
205         MEM_freeN(pixels);
206 }
207
208 static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth)
209 {
210         GPUTexture *tex;
211         GLenum type, format, internalformat;
212         void *pixels = NULL;
213
214         if(depth && !GLEW_ARB_depth_texture)
215                 return NULL;
216
217         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
218         tex->w = w;
219         tex->h = h;
220         tex->number = -1;
221         tex->refcount = 1;
222         tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D;
223         tex->depth = depth;
224
225         glGenTextures(1, &tex->bindcode);
226
227         if (!tex->bindcode) {
228                 fprintf(stderr, "GPUTexture: texture create failed: %d\n",
229                         (int)glGetError());
230                 GPU_texture_free(tex);
231                 return NULL;
232         }
233
234         if (!GLEW_ARB_texture_non_power_of_two) {
235                 tex->w = larger_pow2(tex->w);
236                 tex->h = larger_pow2(tex->h);
237         }
238
239         tex->number = 0;
240         glBindTexture(tex->target, tex->bindcode);
241
242         if(depth) {
243                 type = GL_UNSIGNED_BYTE;
244                 format = GL_DEPTH_COMPONENT;
245                 internalformat = GL_DEPTH_COMPONENT;
246         }
247         else {
248                 type = GL_UNSIGNED_BYTE;
249                 format = GL_RGBA;
250                 internalformat = GL_RGBA8;
251
252                 if (fpixels)
253                         pixels = GPU_texture_convert_pixels(w*h, fpixels);
254         }
255
256         if (tex->target == GL_TEXTURE_1D) {
257                 glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, 0);
258
259                 if (fpixels) {
260                         glTexSubImage1D(tex->target, 0, 0, w, format, type,
261                                 pixels? pixels: fpixels);
262
263                         if (tex->w > w)
264                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0,
265                                         tex->w-w, 1);
266                 }
267         }
268         else {
269                 glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
270                         format, type, 0);
271
272                 if (fpixels) {
273                         glTexSubImage2D(tex->target, 0, 0, 0, w, h,
274                                 format, type, pixels? pixels: fpixels);
275
276                         if (tex->w > w)
277                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
278                         if (tex->h > h)
279                                 GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
280                 }
281         }
282
283         if (pixels)
284                 MEM_freeN(pixels);
285
286         if(depth) {
287                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
288                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
289                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
290                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
291                 glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);  
292         }
293         else {
294                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
295                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
296         }
297
298         if (tex->target != GL_TEXTURE_1D) {
299                 /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */
300                 GLenum wrapmode = (depth)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER;
301                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode);
302                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode);
303
304 #if 0
305                 float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
306                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 
307 #endif
308         }
309         else
310                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
311
312         return tex;
313 }
314
315
316 GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
317 {
318         GPUTexture *tex;
319         GLenum type, format, internalformat;
320         void *pixels = NULL;
321         float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
322
323         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
324         tex->w = w;
325         tex->h = h;
326         tex->depth = depth;
327         tex->number = -1;
328         tex->refcount = 1;
329         tex->target = GL_TEXTURE_3D;
330
331         glGenTextures(1, &tex->bindcode);
332
333         if (!tex->bindcode) {
334                 fprintf(stderr, "GPUTexture: texture create failed: %d\n",
335                         (int)glGetError());
336                 GPU_texture_free(tex);
337                 return NULL;
338         }
339
340         if (!GLEW_ARB_texture_non_power_of_two) 
341         {
342                 tex->w = larger_pow2(tex->w);
343                 tex->h = larger_pow2(tex->h);
344                 tex->depth = larger_pow2(tex->depth);
345         }
346
347         tex->number = 0;
348         glBindTexture(tex->target, tex->bindcode);
349
350         type = GL_UNSIGNED_BYTE;
351         format = GL_RGBA;
352         internalformat = GL_RGBA8;
353
354         if (fpixels)
355                 pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
356
357         glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, 0);
358
359         if (fpixels) {
360                 glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, pixels);
361         }
362
363         glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
364         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
365         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
366         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
367         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
368         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
369
370         if (pixels)
371                 MEM_freeN(pixels);
372
373         if (tex)
374                 GPU_texture_unbind(tex);
375
376         return tex;
377 }
378
379 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
380 {
381         GPUTexture *tex;
382         GLint w, h, border, lastbindcode, bindcode;
383
384         glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
385
386         GPU_update_image_time(ima, time);
387         bindcode = GPU_verify_image(ima, 0, 0, 0, mipmap);
388
389         if(ima->gputexture) {
390                 ima->gputexture->bindcode = bindcode;
391                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
392                 return ima->gputexture;
393         }
394
395         if(!bindcode) {
396                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
397                 return NULL;
398         }
399
400         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
401         tex->bindcode = bindcode;
402         tex->number = -1;
403         tex->refcount = 1;
404         tex->target = GL_TEXTURE_2D;
405         tex->fromblender = 1;
406
407         ima->gputexture= tex;
408
409         if (!glIsTexture(tex->bindcode)) {
410                 GPU_print_error("Blender Texture");
411         }
412         else {
413                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
414                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
415                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
416                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
417
418                 tex->w = w - border;
419                 tex->h = h - border;
420         }
421
422         glBindTexture(GL_TEXTURE_2D, lastbindcode);
423
424         return tex;
425 }
426
427 GPUTexture *GPU_texture_create_1D(int w, float *fpixels)
428 {
429         GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0);
430
431         if (tex)
432                 GPU_texture_unbind(tex);
433         
434         return tex;
435 }
436
437 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels)
438 {
439         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0);
440
441         if (tex)
442                 GPU_texture_unbind(tex);
443         
444         return tex;
445 }
446
447 GPUTexture *GPU_texture_create_depth(int w, int h)
448 {
449         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1);
450
451         if (tex)
452                 GPU_texture_unbind(tex);
453         
454         return tex;
455 }
456
457 void GPU_texture_bind(GPUTexture *tex, int number)
458 {
459         GLenum arbnumber;
460
461         if (number >= GG.maxtextures) {
462                 GPU_print_error("Not enough texture slots.");
463                 return;
464         }
465
466         if(number == -1)
467                 return;
468
469         GPU_print_error("Pre Texture Bind");
470
471         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
472         if (number != 0) glActiveTextureARB(arbnumber);
473         glBindTexture(tex->target, tex->bindcode);
474         glEnable(tex->target);
475         if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
476
477         tex->number = number;
478
479         GPU_print_error("Post Texture Bind");
480 }
481
482 void GPU_texture_unbind(GPUTexture *tex)
483 {
484         GLenum arbnumber;
485
486         if (tex->number >= GG.maxtextures) {
487                 GPU_print_error("Not enough texture slots.");
488                 return;
489         }
490
491         if(tex->number == -1)
492                 return;
493         
494         GPU_print_error("Pre Texture Unbind");
495
496         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
497         if (tex->number != 0) glActiveTextureARB(arbnumber);
498         glBindTexture(tex->target, 0);
499         glDisable(tex->target);
500         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
501
502         tex->number = -1;
503
504         GPU_print_error("Post Texture Unbind");
505 }
506
507 void GPU_texture_free(GPUTexture *tex)
508 {
509         tex->refcount--;
510
511         if (tex->refcount < 0)
512                 fprintf(stderr, "GPUTexture: negative refcount\n");
513         
514         if (tex->refcount == 0) {
515                 if (tex->fb)
516                         GPU_framebuffer_texture_detach(tex->fb, tex);
517                 if (tex->bindcode && !tex->fromblender)
518                         glDeleteTextures(1, &tex->bindcode);
519
520                 MEM_freeN(tex);
521         }
522 }
523
524 void GPU_texture_ref(GPUTexture *tex)
525 {
526         tex->refcount++;
527 }
528
529 int GPU_texture_target(GPUTexture *tex)
530 {
531         return tex->target;
532 }
533
534 int GPU_texture_opengl_width(GPUTexture *tex)
535 {
536         return tex->w;
537 }
538
539 int GPU_texture_opengl_height(GPUTexture *tex)
540 {
541         return tex->h;
542 }
543
544 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
545 {
546         return tex->fb;
547 }
548
549 /* GPUFrameBuffer */
550
551 struct GPUFrameBuffer {
552         GLuint object;
553         GPUTexture *colortex;
554         GPUTexture *depthtex;
555 };
556
557 GPUFrameBuffer *GPU_framebuffer_create()
558 {
559         GPUFrameBuffer *fb;
560
561         if (!GLEW_EXT_framebuffer_object)
562                 return NULL;
563         
564         fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
565         glGenFramebuffersEXT(1, &fb->object);
566
567         if (!fb->object) {
568                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
569                         (int)glGetError());
570                 GPU_framebuffer_free(fb);
571                 return NULL;
572         }
573
574         return fb;
575 }
576
577 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex)
578 {
579         GLenum status;
580         GLenum attachment;
581
582         if(tex->depth)
583                 attachment = GL_DEPTH_ATTACHMENT_EXT;
584         else
585                 attachment = GL_COLOR_ATTACHMENT0_EXT;
586
587         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
588         GG.currentfb = fb->object;
589
590         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
591                 tex->target, tex->bindcode, 0);
592
593         if(tex->depth) {
594                 glDrawBuffer(GL_NONE);
595                 glReadBuffer(GL_NONE);
596         }
597         else {
598                 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
599                 glReadBuffer(GL_NONE);
600         }
601
602         status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
603
604         if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
605                 GPU_framebuffer_restore();
606                 GPU_print_framebuffer_error(status);
607                 return 0;
608         }
609
610         if(tex->depth)
611                 fb->depthtex = tex;
612         else
613                 fb->colortex = tex;
614
615         tex->fb= fb;
616
617         return 1;
618 }
619
620 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
621 {
622         GLenum attachment;
623
624         if(!tex->fb)
625                 return;
626
627         if(GG.currentfb != tex->fb->object) {
628                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
629                 GG.currentfb = tex->fb->object;
630         }
631
632         if(tex->depth) {
633                 fb->depthtex = NULL;
634                 attachment = GL_DEPTH_ATTACHMENT_EXT;
635         }
636         else {
637                 fb->colortex = NULL;
638                 attachment = GL_COLOR_ATTACHMENT0_EXT;
639         }
640
641         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
642                 tex->target, 0, 0);
643
644         tex->fb = NULL;
645 }
646
647 void GPU_framebuffer_texture_bind(GPUFrameBuffer *fb, GPUTexture *tex)
648 {
649         /* push attributes */
650         glPushAttrib(GL_ENABLE_BIT);
651         glPushAttrib(GL_VIEWPORT_BIT);
652         glDisable(GL_SCISSOR_TEST);
653
654         /* bind framebuffer */
655         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
656
657         /* push matrices and set default viewport and matrix */
658         glViewport(0, 0, tex->w, tex->h);
659         GG.currentfb = tex->fb->object;
660
661         glMatrixMode(GL_PROJECTION);
662         glPushMatrix();
663         glLoadIdentity();
664         glMatrixMode(GL_MODELVIEW);
665         glPushMatrix();
666         glLoadIdentity();
667 }
668
669 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex)
670 {
671         /* restore matrix */
672         glMatrixMode(GL_PROJECTION);
673         glPopMatrix();
674         glMatrixMode(GL_MODELVIEW);
675         glPopMatrix();
676
677         /* restore attributes */
678         glPopAttrib();
679         glPopAttrib();
680         glEnable(GL_SCISSOR_TEST);
681 }
682
683 void GPU_framebuffer_free(GPUFrameBuffer *fb)
684 {
685         if(fb->depthtex)
686                 GPU_framebuffer_texture_detach(fb, fb->depthtex);
687         if(fb->colortex)
688                 GPU_framebuffer_texture_detach(fb, fb->colortex);
689
690         if(fb->object) {
691                 glDeleteFramebuffersEXT(1, &fb->object);
692
693                 if (GG.currentfb == fb->object) {
694                         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
695                         GG.currentfb = 0;
696                 }
697         }
698
699         MEM_freeN(fb);
700 }
701
702 void GPU_framebuffer_restore()
703 {
704         if (GG.currentfb != 0) {
705                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
706                 GG.currentfb = 0;
707         }
708 }
709
710 /* GPUShader */
711
712 struct GPUShader {
713         GLhandleARB object;             /* handle for full shader */
714         GLhandleARB vertex;             /* handle for vertex shader */
715         GLhandleARB fragment;   /* handle for fragment shader */
716         GLhandleARB lib;                /* handle for libment shader */
717         int totattrib;                  /* total number of attributes */
718 };
719
720 static void shader_print_errors(char *task, char *log, const char *code)
721 {
722         const char *c, *pos, *end = code + strlen(code);
723         int line = 1;
724
725         fprintf(stderr, "GPUShader: %s error:\n", task);
726
727         if(G.f & G_DEBUG) {
728                 c = code;
729                 while ((c < end) && (pos = strchr(c, '\n'))) {
730                         fprintf(stderr, "%2d  ", line);
731                         fwrite(c, (pos+1)-c, 1, stderr);
732                         c = pos+1;
733                         line++;
734                 }
735
736                 fprintf(stderr, "%s", c);
737         }
738
739         fprintf(stderr, "%s\n", log);
740 }
741
742 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
743 {
744         GLint status;
745         GLcharARB log[5000];
746         const char *fragsource[2];
747         GLsizei length = 0;
748         GLint count;
749         GPUShader *shader;
750
751         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
752                 return NULL;
753
754         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
755
756         if(vertexcode)
757                 shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
758         if(fragcode)
759                 shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
760         shader->object = glCreateProgramObjectARB();
761
762         if (!shader->object ||
763                 (vertexcode && !shader->vertex) ||
764                 (fragcode && !shader->fragment)) {
765                 fprintf(stderr, "GPUShader, object creation failed.\n");
766                 GPU_shader_free(shader);
767                 return NULL;
768         }
769
770         if(vertexcode) {
771                 glAttachObjectARB(shader->object, shader->vertex);
772                 glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
773
774                 glCompileShaderARB(shader->vertex);
775                 glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
776
777                 if (!status) {
778                         glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
779                         shader_print_errors("compile", log, vertexcode);
780
781                         GPU_shader_free(shader);
782                         return NULL;
783                 }
784         }
785
786         if(fragcode) {
787                 count = 0;
788                 if(libcode) fragsource[count++] = libcode;
789                 if(fragcode) fragsource[count++] = fragcode;
790
791                 glAttachObjectARB(shader->object, shader->fragment);
792                 glShaderSourceARB(shader->fragment, count, fragsource, NULL);
793
794                 glCompileShaderARB(shader->fragment);
795                 glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
796
797                 if (!status) {
798                         glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
799                         shader_print_errors("compile", log, fragcode);
800
801                         GPU_shader_free(shader);
802                         return NULL;
803                 }
804         }
805
806         /*if(lib && lib->lib)
807                 glAttachObjectARB(shader->object, lib->lib);*/
808
809         glLinkProgramARB(shader->object);
810         glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
811         if (!status) {
812                 glGetInfoLogARB(shader->object, sizeof(log), &length, log);
813                 if (fragcode) shader_print_errors("linking", log, fragcode);
814                 else if (vertexcode) shader_print_errors("linking", log, vertexcode);
815                 else if (libcode) shader_print_errors("linking", log, libcode);
816
817                 GPU_shader_free(shader);
818                 return NULL;
819         }
820
821         return shader;
822 }
823
824 #if 0
825 GPUShader *GPU_shader_create_lib(const char *code)
826 {
827         GLint status;
828         GLcharARB log[5000];
829         GLsizei length = 0;
830         GPUShader *shader;
831
832         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
833                 return NULL;
834
835         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
836
837         shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
838
839         if (!shader->lib) {
840                 fprintf(stderr, "GPUShader, object creation failed.\n");
841                 GPU_shader_free(shader);
842                 return NULL;
843         }
844
845         glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
846
847         glCompileShaderARB(shader->lib);
848         glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
849
850         if (!status) {
851                 glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
852                 shader_print_errors("compile", log, code);
853
854                 GPU_shader_free(shader);
855                 return NULL;
856         }
857
858         return shader;
859 }
860 #endif
861
862 void GPU_shader_bind(GPUShader *shader)
863 {
864         GPU_print_error("Pre Shader Bind");
865         glUseProgramObjectARB(shader->object);
866         GPU_print_error("Post Shader Bind");
867 }
868
869 void GPU_shader_unbind()
870 {
871         GPU_print_error("Pre Shader Unbind");
872         glUseProgramObjectARB(0);
873         GPU_print_error("Post Shader Unbind");
874 }
875
876 void GPU_shader_free(GPUShader *shader)
877 {
878         if (shader->lib)
879                 glDeleteObjectARB(shader->lib);
880         if (shader->vertex)
881                 glDeleteObjectARB(shader->vertex);
882         if (shader->fragment)
883                 glDeleteObjectARB(shader->fragment);
884         if (shader->object)
885                 glDeleteObjectARB(shader->object);
886         MEM_freeN(shader);
887 }
888
889 int GPU_shader_get_uniform(GPUShader *shader, char *name)
890 {
891         return glGetUniformLocationARB(shader->object, name);
892 }
893
894 void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, float *value)
895 {
896         if(location == -1)
897                 return;
898
899         GPU_print_error("Pre Uniform Vector");
900
901         if (length == 1) glUniform1fvARB(location, arraysize, value);
902         else if (length == 2) glUniform2fvARB(location, arraysize, value);
903         else if (length == 3) glUniform3fvARB(location, arraysize, value);
904         else if (length == 4) glUniform4fvARB(location, arraysize, value);
905         else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
906         else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
907
908         GPU_print_error("Post Uniform Vector");
909 }
910
911 void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex)
912 {
913         GLenum arbnumber;
914
915         if (tex->number >= GG.maxtextures) {
916                 GPU_print_error("Not enough texture slots.");
917                 return;
918         }
919                 
920         if(tex->number == -1)
921                 return;
922
923         if(location == -1)
924                 return;
925
926         GPU_print_error("Pre Uniform Texture");
927
928         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
929
930         if (tex->number != 0) glActiveTextureARB(arbnumber);
931         glBindTexture(tex->target, tex->bindcode);
932         glUniform1iARB(location, tex->number);
933         glEnable(tex->target);
934         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
935
936         GPU_print_error("Post Uniform Texture");
937 }
938
939 int GPU_shader_get_attribute(GPUShader *shader, char *name)
940 {
941         int index;
942         
943         GPU_print_error("Pre Get Attribute");
944
945         index = glGetAttribLocationARB(shader->object, name);
946
947         GPU_print_error("Post Get Attribute");
948
949         return index;
950 }
951
952 #if 0
953 /* GPUPixelBuffer */
954
955 typedef struct GPUPixelBuffer {
956         GLuint bindcode[2];
957         GLuint current;
958         int datasize;
959         int numbuffers;
960         int halffloat;
961 } GPUPixelBuffer;
962
963 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
964 {
965         if (pb->bindcode[0])
966                 glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
967         MEM_freeN(pb);
968 }
969
970 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
971 {
972         GPUPixelBuffer *pb;
973
974         if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
975                 return NULL;
976         
977         pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
978         pb->datasize = x*y*4*((halffloat)? 16: 8);
979         pb->numbuffers = numbuffers;
980         pb->halffloat = halffloat;
981
982         glGenBuffersARB(pb->numbuffers, pb->bindcode);
983
984         if (!pb->bindcode[0]) {
985                 fprintf(stderr, "GPUPixelBuffer allocation failed\n");
986                 GPU_pixelbuffer_free(pb);
987                 return NULL;
988         }
989
990         return pb;
991 }
992
993 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
994 {
995         void *pixels;
996         int i;
997
998     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
999  
1000         for (i = 0; i < pb->numbuffers; i++) {
1001                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
1002                 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
1003                         GL_STREAM_DRAW_ARB);
1004     
1005                 pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1006                 /*memcpy(pixels, _oImage.data(), pb->datasize);*/
1007     
1008                 if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1009                         fprintf(stderr, "Could not unmap opengl PBO\n");
1010                         break;
1011                 }
1012         }
1013
1014     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1015 }
1016
1017 static int pixelbuffer_map_into_gpu(GLuint bindcode)
1018 {
1019         void *pixels;
1020
1021     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1022         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1023
1024         /* do stuff in pixels */
1025
1026     if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1027                 fprintf(stderr, "Could not unmap opengl PBO\n");
1028                 return 0;
1029     }
1030         
1031         return 1;
1032 }
1033
1034 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
1035 {
1036         GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
1037     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1038     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1039
1040     glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
1041                     GL_RGBA, type, NULL);
1042
1043         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
1044     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1045 }
1046
1047 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
1048 {
1049         int newbuffer;
1050
1051         if (pb->numbuffers == 1) {
1052                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
1053                 pixelbuffer_map_into_gpu(pb->bindcode[0]);
1054         }
1055         else {
1056                 pb->current = (pb->current+1)%pb->numbuffers;
1057                 newbuffer = (pb->current+1)%pb->numbuffers;
1058
1059                 pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
1060                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
1061     }
1062 }
1063 #endif
1064