fix for compiling with the c90 standard, support for non-static variable initializers...
[blender.git] / source / blender / gpu / intern / gpu_buffers.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 <limits.h>
34 #include <stddef.h>
35 #include <string.h>
36
37 #include "GL/glew.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_ghash.h"
42 #include "BLI_math.h"
43 #include "BLI_threads.h"
44
45 #include "DNA_meshdata_types.h"
46
47 #include "BKE_DerivedMesh.h"
48
49 #include "DNA_userdef_types.h"
50
51 #include "GPU_buffers.h"
52
53 #define GPU_BUFFER_VERTEX_STATE 1
54 #define GPU_BUFFER_NORMAL_STATE 2
55 #define GPU_BUFFER_TEXCOORD_STATE 4
56 #define GPU_BUFFER_COLOR_STATE 8
57 #define GPU_BUFFER_ELEMENT_STATE 16
58
59 #define MAX_GPU_ATTRIB_DATA 32
60
61 /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
62 int useVBOs = -1;
63 GPUBufferPool *globalPool = 0;
64 int GLStates = 0;
65 GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
66
67 GPUBufferPool *GPU_buffer_pool_new()
68 {
69         GPUBufferPool *pool;
70
71         DEBUG_VBO("GPU_buffer_pool_new\n");
72
73         if( useVBOs < 0 ) {
74                 if( GL_ARB_vertex_buffer_object ) {
75                         DEBUG_VBO( "Vertex Buffer Objects supported.\n" );
76                         useVBOs = 1;
77                 }
78                 else {
79                         DEBUG_VBO( "Vertex Buffer Objects NOT supported.\n" );
80                         useVBOs = 0;
81                 }
82         }
83
84         pool = MEM_callocN(sizeof(GPUBufferPool), "GPU_buffer_pool_new");
85         pool->maxsize = MAX_FREE_GPU_BUFFERS;
86         pool->buffers = MEM_callocN(sizeof(GPUBuffer*)*pool->maxsize, "GPU_buffer_pool_new buffers");
87
88         return pool;
89 }
90
91 void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
92 {
93         int i;
94
95         if( index >= pool->size || index < 0 ) {
96                 ERROR_VBO("Wrong index, out of bounds in call to GPU_buffer_pool_remove");
97                 return;
98         }
99         DEBUG_VBO("GPU_buffer_pool_remove\n");
100
101         for( i = index; i < pool->size-1; i++ ) {
102                 pool->buffers[i] = pool->buffers[i+1];
103         }
104         if( pool->size > 0 )
105                 pool->buffers[pool->size-1] = 0;
106
107         pool->size--;
108 }
109
110 void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
111 {
112         int last;
113
114         DEBUG_VBO("GPU_buffer_pool_delete_last\n");
115
116         if( pool->size <= 0 )
117                 return;
118
119         last = pool->size-1;
120
121         if( pool->buffers[last] != 0 ) {
122                 if( useVBOs ) {
123                         glDeleteBuffersARB(1,&pool->buffers[last]->id);
124                         MEM_freeN( pool->buffers[last] );
125                 }
126                 else {
127                         MEM_freeN( pool->buffers[last]->pointer );
128                         MEM_freeN( pool->buffers[last] );
129                 }
130                 pool->buffers[last] = 0;
131         } else {
132                 DEBUG_VBO("Why are we accessing a null buffer?\n");
133         }
134         pool->size--;
135 }
136
137 void GPU_buffer_pool_free(GPUBufferPool *pool)
138 {
139         DEBUG_VBO("GPU_buffer_pool_free\n");
140
141         if( pool == 0 )
142                 pool = globalPool;
143         if( pool == 0 )
144                 return;
145         
146         while( pool->size )
147                 GPU_buffer_pool_delete_last(pool);
148
149         MEM_freeN(pool->buffers);
150         MEM_freeN(pool);
151         /* if we are releasing the global pool, stop keeping a reference to it */
152         if (pool == globalPool)
153                 globalPool = NULL;
154 }
155
156 void GPU_buffer_pool_free_unused(GPUBufferPool *pool)
157 {
158         DEBUG_VBO("GPU_buffer_pool_free_unused\n");
159
160         if( pool == 0 )
161                 pool = globalPool;
162         if( pool == 0 )
163                 return;
164         
165         while( pool->size > MAX_FREE_GPU_BUFFERS )
166                 GPU_buffer_pool_delete_last(pool);
167 }
168
169 GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool )
170 {
171         char buffer[60];
172         int i;
173         int cursize;
174         GPUBuffer *allocated;
175         int bestfit = -1;
176
177         DEBUG_VBO("GPU_buffer_alloc\n");
178
179         if( pool == 0 ) {
180                 if( globalPool == 0 )
181                         globalPool = GPU_buffer_pool_new();
182                 pool = globalPool;
183         }
184
185         for( i = 0; i < pool->size; i++ ) {
186                 cursize = pool->buffers[i]->size;
187                 if( cursize == size ) {
188                         allocated = pool->buffers[i];
189                         GPU_buffer_pool_remove(i,pool);
190                         DEBUG_VBO("free buffer of exact size found\n");
191                         return allocated;
192                 }
193                 /* smaller buffers won't fit data and buffers at least twice as big are a waste of memory */
194                 else if( cursize > size && size > cursize/2 ) {
195                         /* is it closer to the required size than the last appropriate buffer found. try to save memory */
196                         if( bestfit == -1 || pool->buffers[bestfit]->size > cursize ) {
197                                 bestfit = i;
198                         }
199                 }
200         }
201         if( bestfit == -1 ) {
202                 DEBUG_VBO("allocating a new buffer\n");
203
204                 allocated = MEM_mallocN(sizeof(GPUBuffer), "GPU_buffer_alloc");
205                 allocated->size = size;
206                 if( useVBOs == 1 ) {
207                         glGenBuffersARB( 1, &allocated->id );
208                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, allocated->id );
209                         glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB );
210                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
211                 }
212                 else {
213                         allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
214                         while( allocated->pointer == 0 && pool->size > 0 ) {
215                                 GPU_buffer_pool_delete_last(pool);
216                                 allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
217                         }
218                         if( allocated->pointer == 0 && pool->size == 0 ) {
219                                 return 0;
220                         }
221                 }
222         }
223         else {
224                 sprintf(buffer,"free buffer found. Wasted %d bytes\n", pool->buffers[bestfit]->size-size);
225                 DEBUG_VBO(buffer);
226
227                 allocated = pool->buffers[bestfit];
228                 GPU_buffer_pool_remove(bestfit,pool);
229         }
230         return allocated;
231 }
232
233 void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
234 {
235         int i;
236
237         DEBUG_VBO("GPU_buffer_free\n");
238
239         if( buffer == 0 )
240                 return;
241         if( pool == 0 )
242                 pool = globalPool;
243         if( pool == 0 )
244                 globalPool = GPU_buffer_pool_new();
245
246         /* free the last used buffer in the queue if no more space, but only
247            if we are in the main thread. for e.g. rendering or baking it can
248            happen that we are in other thread and can't call OpenGL, in that
249            case cleanup will be done GPU_buffer_pool_free_unused */
250         if( BLI_thread_is_main() ) {
251                 while( pool->size >= MAX_FREE_GPU_BUFFERS )
252                         GPU_buffer_pool_delete_last( pool );
253         }
254         else {
255                 if( pool->maxsize == pool->size ) {
256                         pool->maxsize += MAX_FREE_GPU_BUFFERS;
257                         pool->buffers = MEM_reallocN(pool->buffers, sizeof(GPUBuffer*)*pool->maxsize);
258                 }
259         }
260
261         for( i =pool->size; i > 0; i-- ) {
262                 pool->buffers[i] = pool->buffers[i-1];
263         }
264         pool->buffers[0] = buffer;
265         pool->size++;
266 }
267
268 GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
269 {
270         GPUDrawObject *object;
271         MVert *mvert;
272         MFace *mface;
273         int numverts[32768];    /* material number is an 16-bit short so there's at most 32768 materials */
274         int redir[32768];               /* material number is an 16-bit short so there's at most 32768 materials */
275         int *index;
276         int i;
277         int curmat, curverts, numfaces;
278
279         DEBUG_VBO("GPU_drawobject_new\n");
280
281         object = MEM_callocN(sizeof(GPUDrawObject),"GPU_drawobject_new_object");
282         object->nindices = dm->getNumVerts(dm);
283         object->indices = MEM_mallocN(sizeof(IndexLink)*object->nindices, "GPU_drawobject_new_indices");
284         object->nedges = dm->getNumEdges(dm);
285
286         for( i = 0; i < object->nindices; i++ ) {
287                 object->indices[i].element = -1;
288                 object->indices[i].next = 0;
289         }
290         /*object->legacy = 1;*/
291         memset(numverts,0,sizeof(int)*32768);
292
293         mvert = dm->getVertArray(dm);
294         mface = dm->getFaceArray(dm);
295
296         numfaces= dm->getNumFaces(dm);
297         for( i=0; i < numfaces; i++ ) {
298                 if( mface[i].v4 )
299                         numverts[mface[i].mat_nr+16383] += 6;   /* split every quad into two triangles */
300                 else
301                         numverts[mface[i].mat_nr+16383] += 3;
302         }
303
304         for( i = 0; i < 32768; i++ ) {
305                 if( numverts[i] > 0 ) {
306                         object->nmaterials++;
307                         object->nelements += numverts[i];
308                 }
309         }
310         object->materials = MEM_mallocN(sizeof(GPUBufferMaterial)*object->nmaterials,"GPU_drawobject_new_materials");
311         index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_drawobject_new_index");
312
313         curmat = curverts = 0;
314         for( i = 0; i < 32768; i++ ) {
315                 if( numverts[i] > 0 ) {
316                         object->materials[curmat].mat_nr = i-16383;
317                         object->materials[curmat].start = curverts;
318                         index[curmat] = curverts/3;
319                         object->materials[curmat].end = curverts+numverts[i];
320                         curverts += numverts[i];
321                         curmat++;
322                 }
323         }
324         object->faceRemap = MEM_mallocN(sizeof(int)*object->nelements/3,"GPU_drawobject_new_faceRemap");
325         for( i = 0; i < object->nmaterials; i++ ) {
326                 redir[object->materials[i].mat_nr+16383] = i;   /* material number -> material index */
327         }
328
329         object->indexMem = MEM_callocN(sizeof(IndexLink)*object->nelements,"GPU_drawobject_new_indexMem");
330         object->indexMemUsage = 0;
331
332 #define ADDLINK( INDEX, ACTUAL ) \
333                 if( object->indices[INDEX].element == -1 ) { \
334                         object->indices[INDEX].element = ACTUAL; \
335                 } else { \
336                         IndexLink *lnk = &object->indices[INDEX]; \
337                         while( lnk->next != 0 ) lnk = lnk->next; \
338                         lnk->next = &object->indexMem[object->indexMemUsage]; \
339                         lnk->next->element = ACTUAL; \
340                         object->indexMemUsage++; \
341                 }
342
343         for( i=0; i < numfaces; i++ ) {
344                 int curInd = index[redir[mface[i].mat_nr+16383]];
345                 object->faceRemap[curInd] = i; 
346                 ADDLINK( mface[i].v1, curInd*3 );
347                 ADDLINK( mface[i].v2, curInd*3+1 );
348                 ADDLINK( mface[i].v3, curInd*3+2 );
349                 if( mface[i].v4 ) {
350                         object->faceRemap[curInd+1] = i;
351                         ADDLINK( mface[i].v3, curInd*3+3 );
352                         ADDLINK( mface[i].v4, curInd*3+4 );
353                         ADDLINK( mface[i].v1, curInd*3+5 );
354
355                         index[redir[mface[i].mat_nr+16383]]+=2;
356                 }
357                 else {
358                         index[redir[mface[i].mat_nr+16383]]++;
359                 }
360         }
361
362         for( i = 0; i < object->nindices; i++ ) {
363                 if( object->indices[i].element == -1 ) {
364                         object->indices[i].element = object->nelements + object->nlooseverts;
365                         object->nlooseverts++;
366                 }
367         }
368 #undef ADDLINK
369
370         MEM_freeN(index);
371         return object;
372 }
373
374 void GPU_drawobject_free( DerivedMesh *dm )
375 {
376         GPUDrawObject *object;
377
378         DEBUG_VBO("GPU_drawobject_free\n");
379
380         if( dm == 0 )
381                 return;
382         object = dm->drawObject;
383         if( object == 0 )
384                 return;
385
386         MEM_freeN(object->materials);
387         MEM_freeN(object->faceRemap);
388         MEM_freeN(object->indices);
389         MEM_freeN(object->indexMem);
390         GPU_buffer_free( object->vertices, globalPool );
391         GPU_buffer_free( object->normals, globalPool );
392         GPU_buffer_free( object->uv, globalPool );
393         GPU_buffer_free( object->colors, globalPool );
394         GPU_buffer_free( object->edges, globalPool );
395         GPU_buffer_free( object->uvedges, globalPool );
396
397         MEM_freeN(object);
398         dm->drawObject = 0;
399 }
400
401 /* Convenience struct for building the VBO. */
402 typedef struct {
403         float co[3];
404         short no[3];
405 } VertexBufferFormat;
406
407 typedef struct {
408         /* opengl buffer handles */
409         GLuint vert_buf, index_buf;
410         GLenum index_type;
411
412         /* mesh pointers in case buffer allocation fails */
413         MFace *mface;
414         MVert *mvert;
415         int *face_indices;
416         int totface;
417
418         /* grid pointers */
419         DMGridData **grids;
420         int *grid_indices;
421         int totgrid;
422         int gridsize;
423
424         unsigned int tot_tri, tot_quad;
425 } GPU_Buffers;
426
427 void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert,
428                         int *vert_indices, int totvert)
429 {
430         GPU_Buffers *buffers = buffers_v;
431         VertexBufferFormat *vert_data;
432         int i;
433
434         if(buffers->vert_buf) {
435                 /* Build VBO */
436                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
437                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
438                                  sizeof(VertexBufferFormat) * totvert,
439                                  NULL, GL_STATIC_DRAW_ARB);
440                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
441
442                 if(vert_data) {
443                         for(i = 0; i < totvert; ++i) {
444                                 MVert *v = mvert + vert_indices[i];
445                                 VertexBufferFormat *out = vert_data + i;
446
447                                 copy_v3_v3(out->co, v->co);
448                                 memcpy(out->no, v->no, sizeof(short) * 3);
449                         }
450
451                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
452                 }
453                 else {
454                         glDeleteBuffersARB(1, &buffers->vert_buf);
455                         buffers->vert_buf = 0;
456                 }
457
458                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
459         }
460
461         buffers->mvert = mvert;
462 }
463
464 void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
465                         int *face_indices, int totface,
466                         int *vert_indices, int tot_uniq_verts,
467                         int totvert)
468 {
469         GPU_Buffers *buffers;
470         unsigned short *tri_data;
471         int i, j, k, tottri;
472
473         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
474         buffers->index_type = GL_UNSIGNED_SHORT;
475
476         /* Count the number of triangles */
477         for(i = 0, tottri = 0; i < totface; ++i)
478                 tottri += mface[face_indices[i]].v4 ? 2 : 1;
479         
480         if(GL_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
481                 glGenBuffersARB(1, &buffers->index_buf);
482
483         if(buffers->index_buf) {
484                 /* Generate index buffer object */
485                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
486                 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
487                                  sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB);
488
489                 /* Fill the triangle buffer */
490                 tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
491                 if(tri_data) {
492                         for(i = 0; i < totface; ++i) {
493                                 MFace *f = mface + face_indices[i];
494                                 int v[3];
495
496                                 v[0]= f->v1;
497                                 v[1]= f->v2;
498                                 v[2]= f->v3;
499
500                                 for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
501                                         for(k = 0; k < 3; ++k) {
502                                                 void *value, *key = SET_INT_IN_POINTER(v[k]);
503                                                 int vbo_index;
504
505                                                 value = BLI_ghash_lookup(map, key);
506                                                 vbo_index = GET_INT_FROM_POINTER(value);
507
508                                                 if(vbo_index < 0) {
509                                                         vbo_index = -vbo_index +
510                                                                 tot_uniq_verts - 1;
511                                                 }
512
513                                                 *tri_data = vbo_index;
514                                                 ++tri_data;
515                                         }
516                                         v[0] = f->v4;
517                                         v[1] = f->v1;
518                                         v[2] = f->v3;
519                                 }
520                         }
521                         glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
522                 }
523                 else {
524                         glDeleteBuffersARB(1, &buffers->index_buf);
525                         buffers->index_buf = 0;
526                 }
527
528                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
529         }
530
531         if(buffers->index_buf)
532                 glGenBuffersARB(1, &buffers->vert_buf);
533         GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert);
534
535         buffers->tot_tri = tottri;
536
537         buffers->mface = mface;
538         buffers->face_indices = face_indices;
539         buffers->totface = totface;
540
541         return buffers;
542 }
543
544 void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
545         int *grid_indices, int totgrid, int gridsize, int smooth)
546 {
547         GPU_Buffers *buffers = buffers_v;
548         DMGridData *vert_data;
549         int i, j, k, totvert;
550
551         totvert= gridsize*gridsize*totgrid;
552
553         /* Build VBO */
554         if(buffers->vert_buf) {
555                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
556                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
557                                  sizeof(DMGridData) * totvert,
558                                  NULL, GL_STATIC_DRAW_ARB);
559                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
560                 if(vert_data) {
561                         for(i = 0; i < totgrid; ++i) {
562                                 DMGridData *grid= grids[grid_indices[i]];
563                                 memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize);
564
565                                 if(!smooth) {
566                                         /* for flat shading, recalc normals and set the last vertex of
567                                            each quad in the index buffer to have the flat normal as
568                                            that is what opengl will use */
569                                         for(j = 0; j < gridsize-1; ++j) {
570                                                 for(k = 0; k < gridsize-1; ++k) {
571                                                         normal_quad_v3(vert_data[(j+1)*gridsize + (k+1)].no,
572                                                                 vert_data[(j+1)*gridsize + k].co,
573                                                                 vert_data[(j+1)*gridsize + k+1].co,
574                                                                 vert_data[j*gridsize + k+1].co,
575                                                                 vert_data[j*gridsize + k].co);
576                                                 }
577                                         }
578                                 }
579
580                                 vert_data += gridsize*gridsize;
581                         }
582                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
583                 }
584                 else {
585                         glDeleteBuffersARB(1, &buffers->vert_buf);
586                         buffers->vert_buf = 0;
587                 }
588                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
589         }
590
591         buffers->grids = grids;
592         buffers->grid_indices = grid_indices;
593         buffers->totgrid = totgrid;
594         buffers->gridsize = gridsize;
595
596         //printf("node updated %p\n", buffers_v);
597 }
598
599 void *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
600                                 int totgrid, int gridsize)
601 {
602         GPU_Buffers *buffers;
603         int i, j, k, totquad, offset= 0;
604
605         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
606
607         /* Count the number of quads */
608         totquad= (gridsize-1)*(gridsize-1)*totgrid;
609
610         /* Generate index buffer object */
611         if(GL_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
612                 glGenBuffersARB(1, &buffers->index_buf);
613
614         if(buffers->index_buf) {
615                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
616
617                 if(totquad < USHRT_MAX) {
618                         unsigned short *quad_data;
619
620                         buffers->index_type = GL_UNSIGNED_SHORT;
621                         glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
622                                          sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
623
624                         /* Fill the quad buffer */
625                         quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
626                         if(quad_data) {
627                                 for(i = 0; i < totgrid; ++i) {
628                                         for(j = 0; j < gridsize-1; ++j) {
629                                                 for(k = 0; k < gridsize-1; ++k) {
630                                                         *(quad_data++)= offset + j*gridsize + k+1;
631                                                         *(quad_data++)= offset + j*gridsize + k;
632                                                         *(quad_data++)= offset + (j+1)*gridsize + k;
633                                                         *(quad_data++)= offset + (j+1)*gridsize + k+1;
634                                                 }
635                                         }
636
637                                         offset += gridsize*gridsize;
638                                 }
639                                 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
640                         }
641                         else {
642                                 glDeleteBuffersARB(1, &buffers->index_buf);
643                                 buffers->index_buf = 0;
644                         }
645                 }
646                 else {
647                         unsigned int *quad_data;
648
649                         buffers->index_type = GL_UNSIGNED_INT;
650                         glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
651                                          sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
652
653                         /* Fill the quad buffer */
654                         quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
655
656                         if(quad_data) {
657                                 for(i = 0; i < totgrid; ++i) {
658                                         for(j = 0; j < gridsize-1; ++j) {
659                                                 for(k = 0; k < gridsize-1; ++k) {
660                                                         *(quad_data++)= offset + j*gridsize + k+1;
661                                                         *(quad_data++)= offset + j*gridsize + k;
662                                                         *(quad_data++)= offset + (j+1)*gridsize + k;
663                                                         *(quad_data++)= offset + (j+1)*gridsize + k+1;
664                                                 }
665                                         }
666
667                                         offset += gridsize*gridsize;
668                                 }
669                                 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
670                         }
671                         else {
672                                 glDeleteBuffersARB(1, &buffers->index_buf);
673                                 buffers->index_buf = 0;
674                         }
675                 }
676
677                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
678         }
679
680         /* Build VBO */
681         if(buffers->index_buf)
682                 glGenBuffersARB(1, &buffers->vert_buf);
683
684         buffers->tot_quad = totquad;
685
686         return buffers;
687 }
688
689 void GPU_draw_buffers(void *buffers_v)
690 {
691         GPU_Buffers *buffers = buffers_v;
692
693         if(buffers->vert_buf && buffers->index_buf) {
694                 glEnableClientState(GL_VERTEX_ARRAY);
695                 glEnableClientState(GL_NORMAL_ARRAY);
696
697                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
698                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
699
700                 if(buffers->tot_quad) {
701                         glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, co));
702                         glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no));
703
704                         glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0);
705                 }
706                 else {
707                         glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, co));
708                         glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
709
710                         glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
711                 }
712
713                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
714                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
715
716                 glDisableClientState(GL_VERTEX_ARRAY);
717                 glDisableClientState(GL_NORMAL_ARRAY);
718         }
719         else if(buffers->totface) {
720                 /* fallback if we are out of memory */
721                 int i;
722
723                 for(i = 0; i < buffers->totface; ++i) {
724                         MFace *f = buffers->mface + buffers->face_indices[i];
725
726                         glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
727                         glNormal3sv(buffers->mvert[f->v1].no);
728                         glVertex3fv(buffers->mvert[f->v1].co);
729                         glNormal3sv(buffers->mvert[f->v2].no);
730                         glVertex3fv(buffers->mvert[f->v2].co);
731                         glNormal3sv(buffers->mvert[f->v3].no);
732                         glVertex3fv(buffers->mvert[f->v3].co);
733                         if(f->v4) {
734                                 glNormal3sv(buffers->mvert[f->v4].no);
735                                 glVertex3fv(buffers->mvert[f->v4].co);
736                         }
737                         glEnd();
738                 }
739         }
740         else if(buffers->totgrid) {
741                 int i, x, y, gridsize = buffers->gridsize;
742
743                 for(i = 0; i < buffers->totgrid; ++i) {
744                         DMGridData *grid = buffers->grids[buffers->grid_indices[i]];
745
746                         for(y = 0; y < gridsize-1; y++) {
747                                 glBegin(GL_QUAD_STRIP);
748                                 for(x = 0; x < gridsize; x++) {
749                                         DMGridData *a = &grid[y*gridsize + x];
750                                         DMGridData *b = &grid[(y+1)*gridsize + x];
751
752                                         glNormal3fv(a->no);
753                                         glVertex3fv(a->co);
754                                         glNormal3fv(b->no);
755                                         glVertex3fv(b->co);
756                                 }
757                                 glEnd();
758                         }
759                 }
760         }
761 }
762
763 void GPU_free_buffers(void *buffers_v)
764 {
765         if(buffers_v) {
766                 GPU_Buffers *buffers = buffers_v;
767                 
768                 if(buffers->vert_buf)
769                         glDeleteBuffersARB(1, &buffers->vert_buf);
770                 if(buffers->index_buf)
771                         glDeleteBuffersARB(1, &buffers->index_buf);
772
773                 MEM_freeN(buffers);
774         }
775 }
776
777 GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
778 {
779         GPUBuffer *buffer;
780         float *varray;
781         int redir[32768];
782         int *index;
783         int i;
784         int success;
785         GLboolean uploaded;
786
787         DEBUG_VBO("GPU_buffer_setup\n");
788
789         if( globalPool == 0 )
790                 globalPool = GPU_buffer_pool_new();
791
792         buffer = GPU_buffer_alloc(size,globalPool);
793         if( buffer == 0 ) {
794                 dm->drawObject->legacy = 1;
795         }
796         if( dm->drawObject->legacy ) {
797                 return 0;
798         }
799
800         index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
801         for( i = 0; i < object->nmaterials; i++ ) {
802                 index[i] = object->materials[i].start*3;
803                 redir[object->materials[i].mat_nr+16383] = i;
804         }
805
806         if( useVBOs ) {
807                 success = 0;
808                 while( success == 0 ) {
809                         glBindBufferARB( target, buffer->id );
810                         glBufferDataARB( target, buffer->size, 0, GL_STATIC_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
811                         varray = glMapBufferARB( target, GL_WRITE_ONLY_ARB );
812                         if( varray == 0 ) {
813                                 DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
814                                 GPU_buffer_free( buffer, globalPool );
815                                 GPU_buffer_pool_delete_last( globalPool );
816                                 buffer= NULL;
817                                 if( globalPool->size > 0 ) {
818                                         GPU_buffer_pool_delete_last( globalPool );
819                                         buffer = GPU_buffer_alloc( size, globalPool );
820                                         if( buffer == 0 ) {
821                                                 dm->drawObject->legacy = 1;
822                                                 success = 1;
823                                         }
824                                 }
825                                 else {
826                                         dm->drawObject->legacy = 1;
827                                         success = 1;
828                                 }
829                         }
830                         else {
831                                 success = 1;
832                         }
833                 }
834
835                 if( dm->drawObject->legacy == 0 ) {
836                         uploaded = GL_FALSE;
837                         while( !uploaded ) {
838                                 (*copy_f)( dm, varray, index, redir, user );
839                                 uploaded = glUnmapBufferARB( target );  /* returns false if data got corruped during transfer */
840                         }
841                 }
842                 glBindBufferARB(target, 0);
843         }
844         else {
845                 if( buffer->pointer != 0 ) {
846                         varray = buffer->pointer;
847                         (*copy_f)( dm, varray, index, redir, user );
848                 }
849                 else {
850                         dm->drawObject->legacy = 1;
851                 }
852         }
853
854         MEM_freeN(index);
855
856         return buffer;
857 }
858
859 void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
860 {
861         int start;
862         int i, j, numfaces;
863
864         MVert *mvert;
865         MFace *mface;
866
867         DEBUG_VBO("GPU_buffer_copy_vertex\n");
868
869         mvert = dm->getVertArray(dm);
870         mface = dm->getFaceArray(dm);
871
872         numfaces= dm->getNumFaces(dm);
873         for( i=0; i < numfaces; i++ ) {
874                 start = index[redir[mface[i].mat_nr+16383]];
875                 if( mface[i].v4 )
876                         index[redir[mface[i].mat_nr+16383]] += 18;
877                 else
878                         index[redir[mface[i].mat_nr+16383]] += 9;
879
880                 /* v1 v2 v3 */
881                 VECCOPY(&varray[start],mvert[mface[i].v1].co);
882                 VECCOPY(&varray[start+3],mvert[mface[i].v2].co);
883                 VECCOPY(&varray[start+6],mvert[mface[i].v3].co);
884
885                 if( mface[i].v4 ) {
886                         /* v3 v4 v1 */
887                         VECCOPY(&varray[start+9],mvert[mface[i].v3].co);
888                         VECCOPY(&varray[start+12],mvert[mface[i].v4].co);
889                         VECCOPY(&varray[start+15],mvert[mface[i].v1].co);
890                 }
891         }
892         j = dm->drawObject->nelements*3;
893         for( i = 0; i < dm->drawObject->nindices; i++ ) {
894                 if( dm->drawObject->indices[i].element >= dm->drawObject->nelements ) {
895                         VECCOPY(&varray[j],mvert[i].co);
896                         j+=3;
897                 }
898         }
899 }
900
901 GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
902 {
903         DEBUG_VBO("GPU_buffer_vertex\n");
904
905         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
906 }
907
908 void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
909 {
910         int i, numfaces;
911         int start;
912         float norm[3];
913
914         float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
915         MVert *mvert = dm->getVertArray(dm);
916         MFace *mface = dm->getFaceArray(dm);
917
918         DEBUG_VBO("GPU_buffer_copy_normal\n");
919
920         numfaces= dm->getNumFaces(dm);
921         for( i=0; i < numfaces; i++ ) {
922                 start = index[redir[mface[i].mat_nr+16383]];
923                 if( mface[i].v4 )
924                         index[redir[mface[i].mat_nr+16383]] += 18;
925                 else
926                         index[redir[mface[i].mat_nr+16383]] += 9;
927
928                 /* v1 v2 v3 */
929                 if( mface[i].flag & ME_SMOOTH ) {
930                         VECCOPY(&varray[start],mvert[mface[i].v1].no);
931                         VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
932                         VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
933                 }
934                 else {
935                         if( nors ) {
936                                 VECCOPY(&varray[start],&nors[i*3]);
937                                 VECCOPY(&varray[start+3],&nors[i*3]);
938                                 VECCOPY(&varray[start+6],&nors[i*3]);
939                         }
940                         if( mface[i].v4 )
941                                 normal_quad_v3( norm,mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co);
942                         else
943                                 normal_tri_v3( norm,mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co);
944                         VECCOPY(&varray[start],norm);
945                         VECCOPY(&varray[start+3],norm);
946                         VECCOPY(&varray[start+6],norm);
947                 }
948
949                 if( mface[i].v4 ) {
950                         /* v3 v4 v1 */
951                         if( mface[i].flag & ME_SMOOTH ) {
952                                 VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
953                                 VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
954                                 VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
955                         }
956                         else {
957                                 VECCOPY(&varray[start+9],norm);
958                                 VECCOPY(&varray[start+12],norm);
959                                 VECCOPY(&varray[start+15],norm);
960                         }
961                 }
962         }
963 }
964
965 GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
966 {
967         DEBUG_VBO("GPU_buffer_normal\n");
968
969         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
970 }
971
972 void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
973 {
974         int start;
975         int i, numfaces;
976
977         MTFace *mtface;
978         MFace *mface;
979
980         DEBUG_VBO("GPU_buffer_copy_uv\n");
981
982         mface = dm->getFaceArray(dm);
983         mtface = DM_get_face_data_layer(dm, CD_MTFACE);
984
985         if( mtface == 0 ) {
986                 DEBUG_VBO("Texture coordinates do not exist for this mesh");
987                 return;
988         }
989                 
990         numfaces= dm->getNumFaces(dm);
991         for( i=0; i < numfaces; i++ ) {
992                 start = index[redir[mface[i].mat_nr+16383]];
993                 if( mface[i].v4 )
994                         index[redir[mface[i].mat_nr+16383]] += 12;
995                 else
996                         index[redir[mface[i].mat_nr+16383]] += 6;
997
998                 /* v1 v2 v3 */
999                 VECCOPY2D(&varray[start],mtface[i].uv[0]);
1000                 VECCOPY2D(&varray[start+2],mtface[i].uv[1]);
1001                 VECCOPY2D(&varray[start+4],mtface[i].uv[2]);
1002
1003                 if( mface[i].v4 ) {
1004                         /* v3 v4 v1 */
1005                         VECCOPY2D(&varray[start+6],mtface[i].uv[2]);
1006                         VECCOPY2D(&varray[start+8],mtface[i].uv[3]);
1007                         VECCOPY2D(&varray[start+10],mtface[i].uv[0]);
1008                 }
1009         }
1010 }
1011
1012 GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
1013 {
1014         DEBUG_VBO("GPU_buffer_uv\n");
1015         if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 ) /* was sizeof(float)*2 but caused buffer overrun  */
1016                 return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
1017         else
1018                 return 0;
1019 }
1020
1021 void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
1022 {
1023         int i, numfaces;
1024         unsigned char *varray = (unsigned char *)varray_;
1025         unsigned char *mcol = (unsigned char *)user;
1026         MFace *mface = dm->getFaceArray(dm);
1027
1028         DEBUG_VBO("GPU_buffer_copy_color3\n");
1029
1030         numfaces= dm->getNumFaces(dm);
1031         for( i=0; i < numfaces; i++ ) {
1032                 int start = index[redir[mface[i].mat_nr+16383]];
1033                 if( mface[i].v4 )
1034                         index[redir[mface[i].mat_nr+16383]] += 18;
1035                 else
1036                         index[redir[mface[i].mat_nr+16383]] += 9;
1037
1038                 /* v1 v2 v3 */
1039                 VECCOPY(&varray[start],&mcol[i*12]);
1040                 VECCOPY(&varray[start+3],&mcol[i*12+3]);
1041                 VECCOPY(&varray[start+6],&mcol[i*12+6]);
1042                 if( mface[i].v4 ) {
1043                         /* v3 v4 v1 */
1044                         VECCOPY(&varray[start+9],&mcol[i*12+6]);
1045                         VECCOPY(&varray[start+12],&mcol[i*12+9]);
1046                         VECCOPY(&varray[start+15],&mcol[i*12]);
1047                 }
1048         }
1049 }
1050
1051 void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
1052 {
1053         int i, numfaces;
1054         unsigned char *varray = (unsigned char *)varray_;
1055         unsigned char *mcol = (unsigned char *)user;
1056         MFace *mface = dm->getFaceArray(dm);
1057
1058         DEBUG_VBO("GPU_buffer_copy_color4\n");
1059
1060         numfaces= dm->getNumFaces(dm);
1061         for( i=0; i < numfaces; i++ ) {
1062                 int start = index[redir[mface[i].mat_nr+16383]];
1063                 if( mface[i].v4 )
1064                         index[redir[mface[i].mat_nr+16383]] += 18;
1065                 else
1066                         index[redir[mface[i].mat_nr+16383]] += 9;
1067
1068                 /* v1 v2 v3 */
1069                 VECCOPY(&varray[start],&mcol[i*16]);
1070                 VECCOPY(&varray[start+3],&mcol[i*16+4]);
1071                 VECCOPY(&varray[start+6],&mcol[i*16+8]);
1072                 if( mface[i].v4 ) {
1073                         /* v3 v4 v1 */
1074                         VECCOPY(&varray[start+9],&mcol[i*16+8]);
1075                         VECCOPY(&varray[start+12],&mcol[i*16+12]);
1076                         VECCOPY(&varray[start+15],&mcol[i*16]);
1077                 }
1078         }
1079 }
1080
1081 GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
1082 {
1083         unsigned char *colors;
1084         int i, numfaces;
1085         MCol *mcol;
1086         GPUBuffer *result;
1087         DEBUG_VBO("GPU_buffer_color\n");
1088
1089         mcol = DM_get_face_data_layer(dm, CD_ID_MCOL);
1090         dm->drawObject->colType = CD_ID_MCOL;
1091         if(!mcol) {
1092                 mcol = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
1093                 dm->drawObject->colType = CD_WEIGHT_MCOL;
1094         }
1095         if(!mcol) {
1096                 mcol = DM_get_face_data_layer(dm, CD_MCOL);
1097                 dm->drawObject->colType = CD_MCOL;
1098         }
1099
1100         numfaces= dm->getNumFaces(dm);
1101         colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
1102         for( i=0; i < numfaces*4; i++ ) {
1103                 colors[i*3] = mcol[i].b;
1104                 colors[i*3+1] = mcol[i].g;
1105                 colors[i*3+2] = mcol[i].r;
1106         }
1107
1108         result = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
1109
1110         MEM_freeN(colors);
1111         return result;
1112 }
1113
1114 void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(redir), void *UNUSED(user))
1115 {
1116         int i;
1117
1118         MVert *mvert;
1119         MEdge *medge;
1120         unsigned int *varray_ = (unsigned int *)varray;
1121         int numedges;
1122  
1123         DEBUG_VBO("GPU_buffer_copy_edge\n");
1124
1125         mvert = dm->getVertArray(dm);
1126         medge = dm->getEdgeArray(dm);
1127
1128         numedges= dm->getNumEdges(dm);
1129         for(i = 0; i < numedges; i++) {
1130                 varray_[i*2] = (unsigned int)dm->drawObject->indices[medge[i].v1].element;
1131                 varray_[i*2+1] = (unsigned int)dm->drawObject->indices[medge[i].v2].element;
1132         }
1133 }
1134
1135 GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
1136 {
1137         DEBUG_VBO("GPU_buffer_edge\n");
1138
1139         return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
1140 }
1141
1142 void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(redir), void *UNUSED(user))
1143 {
1144         MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
1145         int i, j=0;
1146
1147         DEBUG_VBO("GPU_buffer_copy_uvedge\n");
1148
1149         if(tf) {
1150                 for(i = 0; i < dm->numFaceData; i++, tf++) {
1151                         MFace mf;
1152                         dm->getFace(dm,i,&mf);
1153
1154                         VECCOPY2D(&varray[j],tf->uv[0]);
1155                         VECCOPY2D(&varray[j+2],tf->uv[1]);
1156
1157                         VECCOPY2D(&varray[j+4],tf->uv[1]);
1158                         VECCOPY2D(&varray[j+6],tf->uv[2]);
1159
1160                         if(!mf.v4) {
1161                                 VECCOPY2D(&varray[j+8],tf->uv[2]);
1162                                 VECCOPY2D(&varray[j+10],tf->uv[0]);
1163                                 j+=12;
1164                         } else {
1165                                 VECCOPY2D(&varray[j+8],tf->uv[2]);
1166                                 VECCOPY2D(&varray[j+10],tf->uv[3]);
1167
1168                                 VECCOPY2D(&varray[j+12],tf->uv[3]);
1169                                 VECCOPY2D(&varray[j+14],tf->uv[0]);
1170                                 j+=16;
1171                         }
1172                 }
1173         }
1174         else {
1175                 DEBUG_VBO("Could not get MTFACE data layer");
1176         }
1177 }
1178
1179 GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
1180 {
1181         DEBUG_VBO("GPU_buffer_uvedge\n");
1182
1183         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
1184 }
1185
1186
1187 void GPU_vertex_setup( DerivedMesh *dm )
1188 {
1189         DEBUG_VBO("GPU_vertex_setup\n");
1190         if( dm->drawObject == 0 )
1191                 dm->drawObject = GPU_drawobject_new( dm );
1192         if( dm->drawObject->vertices == 0 )
1193                 dm->drawObject->vertices = GPU_buffer_vertex( dm );
1194         if( dm->drawObject->vertices == 0 ) {
1195                 DEBUG_VBO( "Failed to setup vertices\n" );
1196                 return;
1197         }
1198
1199         glEnableClientState( GL_VERTEX_ARRAY );
1200         if( useVBOs ) {
1201                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
1202                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
1203         }
1204         else {
1205                 glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
1206         }
1207         
1208         GLStates |= GPU_BUFFER_VERTEX_STATE;
1209 }
1210
1211 void GPU_normal_setup( DerivedMesh *dm )
1212 {
1213         DEBUG_VBO("GPU_normal_setup\n");
1214         if( dm->drawObject == 0 )
1215                 dm->drawObject = GPU_drawobject_new( dm );
1216         if( dm->drawObject->normals == 0 )
1217                 dm->drawObject->normals = GPU_buffer_normal( dm );
1218         if( dm->drawObject->normals == 0 ) {
1219                 DEBUG_VBO( "Failed to setup normals\n" );
1220                 return;
1221         }
1222         glEnableClientState( GL_NORMAL_ARRAY );
1223         if( useVBOs ) {
1224                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id );
1225                 glNormalPointer( GL_FLOAT, 0, 0 );
1226         }
1227         else {
1228                 glNormalPointer( GL_FLOAT, 0, dm->drawObject->normals->pointer );
1229         }
1230
1231         GLStates |= GPU_BUFFER_NORMAL_STATE;
1232 }
1233
1234 void GPU_uv_setup( DerivedMesh *dm )
1235 {
1236         DEBUG_VBO("GPU_uv_setup\n");
1237         if( dm->drawObject == 0 )
1238                 dm->drawObject = GPU_drawobject_new( dm );
1239         if( dm->drawObject->uv == 0 )
1240                 dm->drawObject->uv = GPU_buffer_uv( dm );
1241         
1242         if( dm->drawObject->uv != 0 ) {
1243                 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1244                 if( useVBOs ) {
1245                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id );
1246                         glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
1247                 }
1248                 else {
1249                         glTexCoordPointer( 2, GL_FLOAT, 0, dm->drawObject->uv->pointer );
1250                 }
1251
1252                 GLStates |= GPU_BUFFER_TEXCOORD_STATE;
1253         }
1254 }
1255
1256 void GPU_color_setup( DerivedMesh *dm )
1257 {
1258         DEBUG_VBO("GPU_color_setup\n");
1259         if( dm->drawObject == 0 )
1260                 dm->drawObject = GPU_drawobject_new( dm );
1261         if( dm->drawObject->colors == 0 )
1262                 dm->drawObject->colors = GPU_buffer_color( dm );
1263         if( dm->drawObject->colors == 0 ) {
1264                 DEBUG_VBO( "Failed to setup colors\n" );
1265                 return;
1266         }
1267         glEnableClientState( GL_COLOR_ARRAY );
1268         if( useVBOs ) {
1269                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id );
1270                 glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
1271         }
1272         else {
1273                 glColorPointer( 3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer );
1274         }
1275
1276         GLStates |= GPU_BUFFER_COLOR_STATE;
1277 }
1278
1279 void GPU_edge_setup( DerivedMesh *dm )
1280 {
1281         DEBUG_VBO("GPU_edge_setup\n");
1282         if( dm->drawObject == 0 )
1283                 dm->drawObject = GPU_drawobject_new( dm );
1284         if( dm->drawObject->edges == 0 )
1285                 dm->drawObject->edges = GPU_buffer_edge( dm );
1286         if( dm->drawObject->edges == 0 ) {
1287                 DEBUG_VBO( "Failed to setup edges\n" );
1288                 return;
1289         }
1290         if( dm->drawObject->vertices == 0 )
1291                 dm->drawObject->vertices = GPU_buffer_vertex( dm );
1292         if( dm->drawObject->vertices == 0 ) {
1293                 DEBUG_VBO( "Failed to setup vertices\n" );
1294                 return;
1295         }
1296
1297         glEnableClientState( GL_VERTEX_ARRAY );
1298         if( useVBOs ) {
1299                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
1300                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
1301         }
1302         else {
1303                 glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
1304         }
1305         
1306         GLStates |= GPU_BUFFER_VERTEX_STATE;
1307
1308         if( useVBOs ) {
1309                 glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
1310         }
1311
1312         GLStates |= GPU_BUFFER_ELEMENT_STATE;
1313 }
1314
1315 void GPU_uvedge_setup( DerivedMesh *dm )
1316 {
1317         DEBUG_VBO("GPU_uvedge_setup\n");
1318         if( dm->drawObject == 0 )
1319                 dm->drawObject = GPU_drawobject_new( dm );
1320         if( dm->drawObject->uvedges == 0 )
1321                 dm->drawObject->uvedges = GPU_buffer_uvedge( dm );
1322         if( dm->drawObject->uvedges == 0 ) {
1323                 DEBUG_VBO( "Failed to setup UV edges\n" );
1324                 return;
1325         }
1326
1327         glEnableClientState( GL_VERTEX_ARRAY );
1328         if( useVBOs ) {
1329                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id );
1330                 glVertexPointer( 2, GL_FLOAT, 0, 0 );
1331         }
1332         else {
1333                 glVertexPointer( 2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer );
1334         }
1335         
1336         GLStates |= GPU_BUFFER_VERTEX_STATE;
1337 }
1338
1339 void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
1340         int i;
1341         int elementsize = 0;
1342         intptr_t offset = 0;
1343
1344         DEBUG_VBO("GPU_interleaved_setup\n");
1345
1346         for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
1347                 switch( data[i] ) {
1348                         case GPU_BUFFER_INTER_V3F:
1349                                 elementsize += 3*sizeof(float);
1350                                 break;
1351                         case GPU_BUFFER_INTER_N3F:
1352                                 elementsize += 3*sizeof(float);
1353                                 break;
1354                         case GPU_BUFFER_INTER_T2F:
1355                                 elementsize += 2*sizeof(float);
1356                                 break;
1357                         case GPU_BUFFER_INTER_C3UB:
1358                                 elementsize += 3*sizeof(unsigned char);
1359                                 break;
1360                         case GPU_BUFFER_INTER_C4UB:
1361                                 elementsize += 4*sizeof(unsigned char);
1362                                 break;
1363                         default:
1364                                 DEBUG_VBO( "Unknown element in data type array in GPU_interleaved_setup\n" );
1365                 }
1366         }
1367
1368         if( useVBOs ) {
1369                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1370                 for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
1371                         switch( data[i] ) {
1372                                 case GPU_BUFFER_INTER_V3F:
1373                                         glEnableClientState( GL_VERTEX_ARRAY );
1374                                         glVertexPointer( 3, GL_FLOAT, elementsize, (void *)offset );
1375                                         GLStates |= GPU_BUFFER_VERTEX_STATE;
1376                                         offset += 3*sizeof(float);
1377                                         break;
1378                                 case GPU_BUFFER_INTER_N3F:
1379                                         glEnableClientState( GL_NORMAL_ARRAY );
1380                                         glNormalPointer( GL_FLOAT, elementsize, (void *)offset );
1381                                         GLStates |= GPU_BUFFER_NORMAL_STATE;
1382                                         offset += 3*sizeof(float);
1383                                         break;
1384                                 case GPU_BUFFER_INTER_T2F:
1385                                         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1386                                         glTexCoordPointer( 2, GL_FLOAT, elementsize, (void *)offset );
1387                                         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
1388                                         offset += 2*sizeof(float);
1389                                         break;
1390                                 case GPU_BUFFER_INTER_C3UB:
1391                                         glEnableClientState( GL_COLOR_ARRAY );
1392                                         glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
1393                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1394                                         offset += 3*sizeof(unsigned char);
1395                                         break;
1396                                 case GPU_BUFFER_INTER_C4UB:
1397                                         glEnableClientState( GL_COLOR_ARRAY );
1398                                         glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
1399                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1400                                         offset += 4*sizeof(unsigned char);
1401                                         break;
1402                         }
1403                 }
1404         }
1405         else {
1406                 for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
1407                         switch( data[i] ) {
1408                                 case GPU_BUFFER_INTER_V3F:
1409                                         glEnableClientState( GL_VERTEX_ARRAY );
1410                                         glVertexPointer( 3, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1411                                         GLStates |= GPU_BUFFER_VERTEX_STATE;
1412                                         offset += 3*sizeof(float);
1413                                         break;
1414                                 case GPU_BUFFER_INTER_N3F:
1415                                         glEnableClientState( GL_NORMAL_ARRAY );
1416                                         glNormalPointer( GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1417                                         GLStates |= GPU_BUFFER_NORMAL_STATE;
1418                                         offset += 3*sizeof(float);
1419                                         break;
1420                                 case GPU_BUFFER_INTER_T2F:
1421                                         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1422                                         glTexCoordPointer( 2, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1423                                         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
1424                                         offset += 2*sizeof(float);
1425                                         break;
1426                                 case GPU_BUFFER_INTER_C3UB:
1427                                         glEnableClientState( GL_COLOR_ARRAY );
1428                                         glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
1429                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1430                                         offset += 3*sizeof(unsigned char);
1431                                         break;
1432                                 case GPU_BUFFER_INTER_C4UB:
1433                                         glEnableClientState( GL_COLOR_ARRAY );
1434                                         glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
1435                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1436                                         offset += 4*sizeof(unsigned char);
1437                                         break;
1438                         }
1439                 }
1440         }
1441 }
1442
1443 static int GPU_typesize( int type ) {
1444         switch( type ) {
1445                 case GL_FLOAT:
1446                         return sizeof(float);
1447                 case GL_INT:
1448                         return sizeof(int);
1449                 case GL_UNSIGNED_INT:
1450                         return sizeof(unsigned int);
1451                 case GL_BYTE:
1452                         return sizeof(char);
1453                 case GL_UNSIGNED_BYTE:
1454                         return sizeof(unsigned char);
1455                 default:
1456                         return 0;
1457         }
1458 }
1459
1460 int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
1461         int i, elementsize = 0;
1462
1463         for( i = 0; i < numdata; i++ ) {
1464                 int typesize = GPU_typesize(data[i].type);
1465                 if( typesize == 0 )
1466                         DEBUG_VBO( "Unknown element in data type array in GPU_attrib_element_size\n" );
1467                 else {
1468                         elementsize += typesize*data[i].size;
1469                 }
1470         }
1471         return elementsize;
1472 }
1473
1474 void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
1475         int i;
1476         int elementsize;
1477         intptr_t offset = 0;
1478
1479         DEBUG_VBO("GPU_interleaved_attrib_setup\n");
1480
1481         for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
1482                 if( attribData[i].index != -1 ) {
1483                         glDisableVertexAttribArrayARB( attribData[i].index );
1484                 }
1485                 else
1486                         break;
1487         }
1488         elementsize = GPU_attrib_element_size( data, numdata );
1489
1490         if( useVBOs ) {
1491                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1492                 for( i = 0; i < numdata; i++ ) {
1493                         glEnableVertexAttribArrayARB( data[i].index );
1494                         glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (void *)offset );
1495                         offset += data[i].size*GPU_typesize(data[i].type);
1496
1497                         attribData[i].index = data[i].index;
1498                         attribData[i].size = data[i].size;
1499                         attribData[i].type = data[i].type;
1500                 }
1501                 attribData[numdata].index = -1;
1502         }
1503         else {
1504                 for( i = 0; i < numdata; i++ ) {
1505                         glEnableVertexAttribArrayARB( data[i].index );
1506                         glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (char *)buffer->pointer + offset );
1507                         offset += data[i].size*GPU_typesize(data[i].type);
1508                 }
1509         }
1510 }
1511
1512
1513 void GPU_buffer_unbind()
1514 {
1515         int i;
1516         DEBUG_VBO("GPU_buffer_unbind\n");
1517
1518         if( GLStates & GPU_BUFFER_VERTEX_STATE )
1519                 glDisableClientState( GL_VERTEX_ARRAY );
1520         if( GLStates & GPU_BUFFER_NORMAL_STATE )
1521                 glDisableClientState( GL_NORMAL_ARRAY );
1522         if( GLStates & GPU_BUFFER_TEXCOORD_STATE )
1523                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1524         if( GLStates & GPU_BUFFER_COLOR_STATE )
1525                 glDisableClientState( GL_COLOR_ARRAY );
1526         if( GLStates & GPU_BUFFER_ELEMENT_STATE ) {
1527                 if( useVBOs ) {
1528                         glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
1529                 }
1530         }
1531         GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
1532
1533         for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
1534                 if( attribData[i].index != -1 ) {
1535                         glDisableVertexAttribArrayARB( attribData[i].index );
1536                 }
1537                 else
1538                         break;
1539         }
1540         if( GLStates != 0 ) {
1541                 DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
1542         }
1543         if( useVBOs )
1544                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1545 }
1546
1547 void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
1548 {
1549         if( dm->drawObject == 0 )
1550                 dm->drawObject = GPU_drawobject_new(dm);
1551         GPU_buffer_free(dm->drawObject->colors,globalPool);
1552         dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
1553 }
1554 void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
1555 {
1556         if( dm->drawObject == 0 )
1557                 dm->drawObject = GPU_drawobject_new(dm);
1558         GPU_buffer_free(dm->drawObject->colors,globalPool);
1559         dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
1560 }
1561
1562 void GPU_color_switch( int mode )
1563 {
1564         if( mode ) {
1565                 if( !(GLStates & GPU_BUFFER_COLOR_STATE) )
1566                         glEnableClientState( GL_COLOR_ARRAY );
1567                 GLStates |= GPU_BUFFER_COLOR_STATE;
1568         }
1569         else {
1570                 if( GLStates & GPU_BUFFER_COLOR_STATE )
1571                         glDisableClientState( GL_COLOR_ARRAY );
1572                 GLStates &= (!GPU_BUFFER_COLOR_STATE);
1573         }
1574 }
1575
1576 int GPU_buffer_legacy( DerivedMesh *dm )
1577 {
1578         int test= (U.gameflags & USER_DISABLE_VBO);
1579         if( test )
1580                 return 1;
1581
1582         if( dm->drawObject == 0 )
1583                 dm->drawObject = GPU_drawobject_new(dm);
1584         return dm->drawObject->legacy;
1585 }
1586
1587 void *GPU_buffer_lock( GPUBuffer *buffer )
1588 {
1589         float *varray;
1590
1591         DEBUG_VBO("GPU_buffer_lock\n");
1592         if( buffer == 0 ) {
1593                 DEBUG_VBO( "Failed to lock NULL buffer\n" );
1594                 return 0;
1595         }
1596
1597         if( useVBOs ) {
1598                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1599                 varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1600                 if( varray == 0 ) {
1601                         DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
1602                 }
1603                 return varray;
1604         }
1605         else {
1606                 return buffer->pointer;
1607         }
1608 }
1609
1610 void *GPU_buffer_lock_stream( GPUBuffer *buffer )
1611 {
1612         float *varray;
1613
1614         DEBUG_VBO("GPU_buffer_lock_stream\n");
1615         if( buffer == 0 ) {
1616                 DEBUG_VBO( "Failed to lock NULL buffer\n" );
1617                 return 0;
1618         }
1619
1620         if( useVBOs ) {
1621                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1622                 glBufferDataARB( GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB );    /* discard previous data, avoid stalling gpu */
1623                 varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1624                 if( varray == 0 ) {
1625                         DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
1626                 }
1627                 return varray;
1628         }
1629         else {
1630                 return buffer->pointer;
1631         }
1632 }
1633
1634 void GPU_buffer_unlock( GPUBuffer *buffer )
1635 {
1636         DEBUG_VBO( "GPU_buffer_unlock\n" ); 
1637         if( useVBOs ) {
1638                 if( buffer != 0 ) {
1639                         if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == 0 ) {
1640                                 DEBUG_VBO( "Failed to copy new data\n" ); 
1641                         }
1642                 }
1643                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1644         }
1645 }
1646
1647 void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
1648 {
1649         if( useVBOs ) {
1650                 glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
1651         }
1652         else {
1653                 glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
1654         }
1655 }