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
322         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
323         tex->w = w;
324         tex->h = h;
325         tex->depth = depth;
326         tex->number = -1;
327         tex->refcount = 1;
328         tex->target = GL_TEXTURE_3D;
329         float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
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
371         if (pixels)
372                 MEM_freeN(pixels);
373
374         if (tex)
375                 GPU_texture_unbind(tex);
376
377         return tex;
378 }
379
380 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
381 {
382         GPUTexture *tex;
383         GLint w, h, border, lastbindcode, bindcode;
384
385         glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
386
387         GPU_update_image_time(ima, time);
388         bindcode = GPU_verify_image(ima, 0, 0, 0, mipmap);
389
390         if(ima->gputexture) {
391                 ima->gputexture->bindcode = bindcode;
392                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
393                 return ima->gputexture;
394         }
395
396         if(!bindcode) {
397                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
398                 return NULL;
399         }
400
401         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
402         tex->bindcode = bindcode;
403         tex->number = -1;
404         tex->refcount = 1;
405         tex->target = GL_TEXTURE_2D;
406         tex->fromblender = 1;
407
408         ima->gputexture= tex;
409
410         if (!glIsTexture(tex->bindcode)) {
411                 GPU_print_error("Blender Texture");
412         }
413         else {
414                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
415                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
416                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
417                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
418
419                 tex->w = w - border;
420                 tex->h = h - border;
421         }
422
423         glBindTexture(GL_TEXTURE_2D, lastbindcode);
424
425         return tex;
426 }
427
428 GPUTexture *GPU_texture_create_1D(int w, float *fpixels)
429 {
430         GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0);
431
432         if (tex)
433                 GPU_texture_unbind(tex);
434         
435         return tex;
436 }
437
438 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels)
439 {
440         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0);
441
442         if (tex)
443                 GPU_texture_unbind(tex);
444         
445         return tex;
446 }
447
448 GPUTexture *GPU_texture_create_depth(int w, int h)
449 {
450         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1);
451
452         if (tex)
453                 GPU_texture_unbind(tex);
454         
455         return tex;
456 }
457
458 void GPU_texture_bind(GPUTexture *tex, int number)
459 {
460         GLenum arbnumber;
461
462         if (number >= GG.maxtextures) {
463                 GPU_print_error("Not enough texture slots.");
464                 return;
465         }
466
467         if(number == -1)
468                 return;
469
470         GPU_print_error("Pre Texture Bind");
471
472         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
473         if (number != 0) glActiveTextureARB(arbnumber);
474         glBindTexture(tex->target, tex->bindcode);
475         glEnable(tex->target);
476         if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
477
478         tex->number = number;
479
480         GPU_print_error("Post Texture Bind");
481 }
482
483 void GPU_texture_unbind(GPUTexture *tex)
484 {
485         GLenum arbnumber;
486
487         if (tex->number >= GG.maxtextures) {
488                 GPU_print_error("Not enough texture slots.");
489                 return;
490         }
491
492         if(tex->number == -1)
493                 return;
494         
495         GPU_print_error("Pre Texture Unbind");
496
497         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
498         if (tex->number != 0) glActiveTextureARB(arbnumber);
499         glBindTexture(tex->target, 0);
500         glDisable(tex->target);
501         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
502
503         tex->number = -1;
504
505         GPU_print_error("Post Texture Unbind");
506 }
507
508 void GPU_texture_free(GPUTexture *tex)
509 {
510         tex->refcount--;
511
512         if (tex->refcount < 0)
513                 fprintf(stderr, "GPUTexture: negative refcount\n");
514         
515         if (tex->refcount == 0) {
516                 if (tex->fb)
517                         GPU_framebuffer_texture_detach(tex->fb, tex);
518                 if (tex->bindcode && !tex->fromblender)
519                         glDeleteTextures(1, &tex->bindcode);
520
521                 MEM_freeN(tex);
522         }
523 }
524
525 void GPU_texture_ref(GPUTexture *tex)
526 {
527         tex->refcount++;
528 }
529
530 int GPU_texture_target(GPUTexture *tex)
531 {
532         return tex->target;
533 }
534
535 int GPU_texture_opengl_width(GPUTexture *tex)
536 {
537         return tex->w;
538 }
539
540 int GPU_texture_opengl_height(GPUTexture *tex)
541 {
542         return tex->h;
543 }
544
545 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
546 {
547         return tex->fb;
548 }
549
550 /* GPUFrameBuffer */
551
552 struct GPUFrameBuffer {
553         GLuint object;
554         GPUTexture *colortex;
555         GPUTexture *depthtex;
556 };
557
558 GPUFrameBuffer *GPU_framebuffer_create()
559 {
560         GPUFrameBuffer *fb;
561
562         if (!GLEW_EXT_framebuffer_object)
563                 return NULL;
564         
565         fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
566         glGenFramebuffersEXT(1, &fb->object);
567
568         if (!fb->object) {
569                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
570                         (int)glGetError());
571                 GPU_framebuffer_free(fb);
572                 return NULL;
573         }
574
575         return fb;
576 }
577
578 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex)
579 {
580         GLenum status;
581         GLenum attachment;
582
583         if(tex->depth)
584                 attachment = GL_DEPTH_ATTACHMENT_EXT;
585         else
586                 attachment = GL_COLOR_ATTACHMENT0_EXT;
587
588         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
589         GG.currentfb = fb->object;
590
591         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
592                 tex->target, tex->bindcode, 0);
593
594         if(tex->depth) {
595                 glDrawBuffer(GL_NONE);
596                 glReadBuffer(GL_NONE);
597         }
598         else {
599                 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
600                 glReadBuffer(GL_NONE);
601         }
602
603         status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
604
605         if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
606                 GPU_framebuffer_restore();
607                 GPU_print_framebuffer_error(status);
608                 return 0;
609         }
610
611         if(tex->depth)
612                 fb->depthtex = tex;
613         else
614                 fb->colortex = tex;
615
616         tex->fb= fb;
617
618         return 1;
619 }
620
621 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
622 {
623         GLenum attachment;
624
625         if(!tex->fb)
626                 return;
627
628         if(GG.currentfb != tex->fb->object) {
629                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
630                 GG.currentfb = tex->fb->object;
631         }
632
633         if(tex->depth) {
634                 fb->depthtex = NULL;
635                 attachment = GL_DEPTH_ATTACHMENT_EXT;
636         }
637         else {
638                 fb->colortex = NULL;
639                 attachment = GL_COLOR_ATTACHMENT0_EXT;
640         }
641
642         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
643                 tex->target, 0, 0);
644
645         tex->fb = NULL;
646 }
647
648 void GPU_framebuffer_texture_bind(GPUFrameBuffer *fb, GPUTexture *tex)
649 {
650         /* push attributes */
651         glPushAttrib(GL_ENABLE_BIT);
652         glPushAttrib(GL_VIEWPORT_BIT);
653         glDisable(GL_SCISSOR_TEST);
654
655         /* bind framebuffer */
656         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
657
658         /* push matrices and set default viewport and matrix */
659         glViewport(0, 0, tex->w, tex->h);
660         GG.currentfb = tex->fb->object;
661
662         glMatrixMode(GL_PROJECTION);
663         glPushMatrix();
664         glLoadIdentity();
665         glMatrixMode(GL_MODELVIEW);
666         glPushMatrix();
667         glLoadIdentity();
668 }
669
670 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex)
671 {
672         /* restore matrix */
673         glMatrixMode(GL_PROJECTION);
674         glPopMatrix();
675         glMatrixMode(GL_MODELVIEW);
676         glPopMatrix();
677
678         /* restore attributes */
679         glPopAttrib();
680         glPopAttrib();
681         glEnable(GL_SCISSOR_TEST);
682 }
683
684 void GPU_framebuffer_free(GPUFrameBuffer *fb)
685 {
686         if(fb->depthtex)
687                 GPU_framebuffer_texture_detach(fb, fb->depthtex);
688         if(fb->colortex)
689                 GPU_framebuffer_texture_detach(fb, fb->colortex);
690
691         if(fb->object) {
692                 glDeleteFramebuffersEXT(1, &fb->object);
693
694                 if (GG.currentfb == fb->object) {
695                         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
696                         GG.currentfb = 0;
697                 }
698         }
699
700         MEM_freeN(fb);
701 }
702
703 void GPU_framebuffer_restore()
704 {
705         if (GG.currentfb != 0) {
706                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
707                 GG.currentfb = 0;
708         }
709 }
710
711 /* GPUShader */
712
713 struct GPUShader {
714         GLhandleARB object;             /* handle for full shader */
715         GLhandleARB vertex;             /* handle for vertex shader */
716         GLhandleARB fragment;   /* handle for fragment shader */
717         GLhandleARB lib;                /* handle for libment shader */
718         int totattrib;                  /* total number of attributes */
719 };
720
721 static void shader_print_errors(char *task, char *log, const char *code)
722 {
723         const char *c, *pos, *end = code + strlen(code);
724         int line = 1;
725
726         fprintf(stderr, "GPUShader: %s error:\n", task);
727
728         if(G.f & G_DEBUG) {
729                 c = code;
730                 while ((c < end) && (pos = strchr(c, '\n'))) {
731                         fprintf(stderr, "%2d  ", line);
732                         fwrite(c, (pos+1)-c, 1, stderr);
733                         c = pos+1;
734                         line++;
735                 }
736
737                 fprintf(stderr, "%s", c);
738         }
739
740         fprintf(stderr, "%s\n", log);
741 }
742
743 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
744 {
745         GLint status;
746         GLcharARB log[5000];
747         const char *fragsource[2];
748         GLsizei length = 0;
749         GLint count;
750         GPUShader *shader;
751
752         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
753                 return NULL;
754
755         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
756
757         if(vertexcode)
758                 shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
759         if(fragcode)
760                 shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
761         shader->object = glCreateProgramObjectARB();
762
763         if (!shader->object ||
764                 (vertexcode && !shader->vertex) ||
765                 (fragcode && !shader->fragment)) {
766                 fprintf(stderr, "GPUShader, object creation failed.\n");
767                 GPU_shader_free(shader);
768                 return NULL;
769         }
770
771         if(vertexcode) {
772                 glAttachObjectARB(shader->object, shader->vertex);
773                 glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
774
775                 glCompileShaderARB(shader->vertex);
776                 glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
777
778                 if (!status) {
779                         glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
780                         shader_print_errors("compile", log, vertexcode);
781
782                         GPU_shader_free(shader);
783                         return NULL;
784                 }
785         }
786
787         if(fragcode) {
788                 count = 0;
789                 if(libcode) fragsource[count++] = libcode;
790                 if(fragcode) fragsource[count++] = fragcode;
791
792                 glAttachObjectARB(shader->object, shader->fragment);
793                 glShaderSourceARB(shader->fragment, count, fragsource, NULL);
794
795                 glCompileShaderARB(shader->fragment);
796                 glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
797
798                 if (!status) {
799                         glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
800                         shader_print_errors("compile", log, fragcode);
801
802                         GPU_shader_free(shader);
803                         return NULL;
804                 }
805         }
806
807         /*if(lib && lib->lib)
808                 glAttachObjectARB(shader->object, lib->lib);*/
809
810         glLinkProgramARB(shader->object);
811         glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
812         if (!status) {
813                 glGetInfoLogARB(shader->object, sizeof(log), &length, log);
814                 if (fragcode) shader_print_errors("linking", log, fragcode);
815                 else if (vertexcode) shader_print_errors("linking", log, vertexcode);
816                 else if (libcode) shader_print_errors("linking", log, libcode);
817
818                 GPU_shader_free(shader);
819                 return NULL;
820         }
821
822         return shader;
823 }
824
825 #if 0
826 GPUShader *GPU_shader_create_lib(const char *code)
827 {
828         GLint status;
829         GLcharARB log[5000];
830         GLsizei length = 0;
831         GPUShader *shader;
832
833         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
834                 return NULL;
835
836         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
837
838         shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
839
840         if (!shader->lib) {
841                 fprintf(stderr, "GPUShader, object creation failed.\n");
842                 GPU_shader_free(shader);
843                 return NULL;
844         }
845
846         glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
847
848         glCompileShaderARB(shader->lib);
849         glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
850
851         if (!status) {
852                 glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
853                 shader_print_errors("compile", log, code);
854
855                 GPU_shader_free(shader);
856                 return NULL;
857         }
858
859         return shader;
860 }
861 #endif
862
863 void GPU_shader_bind(GPUShader *shader)
864 {
865         GPU_print_error("Pre Shader Bind");
866         glUseProgramObjectARB(shader->object);
867         GPU_print_error("Post Shader Bind");
868 }
869
870 void GPU_shader_unbind()
871 {
872         GPU_print_error("Pre Shader Unbind");
873         glUseProgramObjectARB(0);
874         GPU_print_error("Post Shader Unbind");
875 }
876
877 void GPU_shader_free(GPUShader *shader)
878 {
879         if (shader->lib)
880                 glDeleteObjectARB(shader->lib);
881         if (shader->vertex)
882                 glDeleteObjectARB(shader->vertex);
883         if (shader->fragment)
884                 glDeleteObjectARB(shader->fragment);
885         if (shader->object)
886                 glDeleteObjectARB(shader->object);
887         MEM_freeN(shader);
888 }
889
890 int GPU_shader_get_uniform(GPUShader *shader, char *name)
891 {
892         return glGetUniformLocationARB(shader->object, name);
893 }
894
895 void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, float *value)
896 {
897         if(location == -1)
898                 return;
899
900         GPU_print_error("Pre Uniform Vector");
901
902         if (length == 1) glUniform1fvARB(location, arraysize, value);
903         else if (length == 2) glUniform2fvARB(location, arraysize, value);
904         else if (length == 3) glUniform3fvARB(location, arraysize, value);
905         else if (length == 4) glUniform4fvARB(location, arraysize, value);
906         else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
907         else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
908
909         GPU_print_error("Post Uniform Vector");
910 }
911
912 void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex)
913 {
914         GLenum arbnumber;
915
916         if (tex->number >= GG.maxtextures) {
917                 GPU_print_error("Not enough texture slots.");
918                 return;
919         }
920                 
921         if(tex->number == -1)
922                 return;
923
924         if(location == -1)
925                 return;
926
927         GPU_print_error("Pre Uniform Texture");
928
929         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
930
931         if (tex->number != 0) glActiveTextureARB(arbnumber);
932         glBindTexture(tex->target, tex->bindcode);
933         glUniform1iARB(location, tex->number);
934         glEnable(tex->target);
935         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
936
937         GPU_print_error("Post Uniform Texture");
938 }
939
940 int GPU_shader_get_attribute(GPUShader *shader, char *name)
941 {
942         int index;
943         
944         GPU_print_error("Pre Get Attribute");
945
946         index = glGetAttribLocationARB(shader->object, name);
947
948         GPU_print_error("Post Get Attribute");
949
950         return index;
951 }
952
953 #if 0
954 /* GPUPixelBuffer */
955
956 typedef struct GPUPixelBuffer {
957         GLuint bindcode[2];
958         GLuint current;
959         int datasize;
960         int numbuffers;
961         int halffloat;
962 } GPUPixelBuffer;
963
964 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
965 {
966         if (pb->bindcode[0])
967                 glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
968         MEM_freeN(pb);
969 }
970
971 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
972 {
973         GPUPixelBuffer *pb;
974
975         if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
976                 return NULL;
977         
978         pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
979         pb->datasize = x*y*4*((halffloat)? 16: 8);
980         pb->numbuffers = numbuffers;
981         pb->halffloat = halffloat;
982
983         glGenBuffersARB(pb->numbuffers, pb->bindcode);
984
985         if (!pb->bindcode[0]) {
986                 fprintf(stderr, "GPUPixelBuffer allocation failed\n");
987                 GPU_pixelbuffer_free(pb);
988                 return NULL;
989         }
990
991         return pb;
992 }
993
994 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
995 {
996         void *pixels;
997         int i;
998
999     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1000  
1001         for (i = 0; i < pb->numbuffers; i++) {
1002                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
1003                 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
1004                         GL_STREAM_DRAW_ARB);
1005     
1006                 pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1007                 /*memcpy(pixels, _oImage.data(), pb->datasize);*/
1008     
1009                 if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1010                         fprintf(stderr, "Could not unmap opengl PBO\n");
1011                         break;
1012                 }
1013         }
1014
1015     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1016 }
1017
1018 static int pixelbuffer_map_into_gpu(GLuint bindcode)
1019 {
1020         void *pixels;
1021
1022     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1023         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1024
1025         /* do stuff in pixels */
1026
1027     if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1028                 fprintf(stderr, "Could not unmap opengl PBO\n");
1029                 return 0;
1030     }
1031         
1032         return 1;
1033 }
1034
1035 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
1036 {
1037         GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
1038     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1039     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1040
1041     glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
1042                     GL_RGBA, type, NULL);
1043
1044         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
1045     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1046 }
1047
1048 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
1049 {
1050         int newbuffer;
1051
1052         if (pb->numbuffers == 1) {
1053                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
1054                 pixelbuffer_map_into_gpu(pb->bindcode[0]);
1055         }
1056         else {
1057                 pb->current = (pb->current+1)%pb->numbuffers;
1058                 newbuffer = (pb->current+1)%pb->numbuffers;
1059
1060                 pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
1061                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
1062     }
1063 }
1064 #endif
1065