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