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