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