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