~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to source/blender/gpu/intern/gpu_extensions.c

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

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