VBO:
[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., 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 <string.h>
34
35 #include "GL/glew.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_math.h"
40
41 #include "DNA_meshdata_types.h"
42
43 #include "BKE_DerivedMesh.h"
44 #include "BKE_utildefines.h"
45
46 #include "DNA_userdef_types.h"
47
48 #include "gpu_buffers.h"
49
50 #define GPU_BUFFER_VERTEX_STATE 1
51 #define GPU_BUFFER_NORMAL_STATE 2
52 #define GPU_BUFFER_TEXCOORD_STATE 4
53 #define GPU_BUFFER_COLOR_STATE 8
54 #define GPU_BUFFER_ELEMENT_STATE 16
55
56 #define MAX_GPU_ATTRIB_DATA 32
57
58 /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
59 int useVBOs = -1;
60 GPUBufferPool *globalPool = 0;
61 int GLStates = 0;
62 GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
63
64 GPUBufferPool *GPU_buffer_pool_new()
65 {
66         GPUBufferPool *pool;
67
68         DEBUG_VBO("GPU_buffer_pool_new\n");
69
70         if( useVBOs < 0 ) {
71                 if( GL_ARB_vertex_buffer_object ) {
72                         DEBUG_VBO( "Vertex Buffer Objects supported.\n" );
73                         useVBOs = 1;
74                 }
75                 else {
76                         DEBUG_VBO( "Vertex Buffer Objects NOT supported.\n" );
77                         useVBOs = 0;
78                 }
79         }
80
81         pool = MEM_callocN(sizeof(GPUBufferPool), "GPU_buffer_pool_new");
82
83         return pool;
84 }
85
86 void GPU_buffer_pool_free(GPUBufferPool *pool)
87 {
88         int i;
89
90         DEBUG_VBO("GPU_buffer_pool_free\n");
91
92         if( pool == 0 )
93                 pool = globalPool;
94         if( pool == 0 )
95                 return;
96
97         while( pool->start < 0 )
98                 pool->start += MAX_FREE_GPU_BUFFERS;
99
100         for( i = 0; i < pool->size; i++ ) {
101                 if( useVBOs ) {
102                         glDeleteBuffersARB( 1, &pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->id );
103                 }
104                 else {
105                         MEM_freeN( pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->pointer );
106                 }
107                 MEM_freeN(pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]);
108         }
109         MEM_freeN(pool);
110 }
111
112 void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
113 {
114         int i;
115
116         DEBUG_VBO("GPU_buffer_pool_remove\n");
117
118         while( pool->start < 0 )
119                 pool->start += MAX_FREE_GPU_BUFFERS;
120         for( i = index; i < pool->size-1; i++ ) {
121                 pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS] = pool->buffers[(pool->start+i+1)%MAX_FREE_GPU_BUFFERS];
122         }
123         pool->size--;
124 }
125
126 void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
127 {
128         int last;
129
130         DEBUG_VBO("GPU_buffer_pool_delete_last\n");
131
132         if( pool->size == 0 )
133                 return;
134
135         last = pool->start+pool->size-1;
136         while( last < 0 )
137                 last += MAX_FREE_GPU_BUFFERS;
138         last = (last+MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
139
140         if( useVBOs ) {
141                 glDeleteBuffersARB(1,&pool->buffers[last]->id);
142                 MEM_freeN( pool->buffers[last] );
143         }
144         else {
145                 MEM_freeN( pool->buffers[last]->pointer );
146                 MEM_freeN( pool->buffers[last] );
147         }
148         pool->size--;
149 }
150
151 GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool )
152 {
153         char buffer[60];
154         int i;
155         int cursize;
156         GPUBuffer *allocated;
157         int bestfit = -1;
158
159         DEBUG_VBO("GPU_buffer_alloc\n");
160
161         if( pool == 0 ) {
162                 if( globalPool == 0 )
163                         globalPool = GPU_buffer_pool_new();
164                 pool = globalPool;
165         }
166
167         while( pool->start < 0 )
168                 pool->start += MAX_FREE_GPU_BUFFERS;
169
170         for( i = 0; i < pool->size; i++ ) {
171                 int actuali = (pool->start+i)%MAX_FREE_GPU_BUFFERS;
172                 cursize = pool->buffers[actuali]->size;
173                 if( cursize == size ) {
174                         allocated = pool->buffers[actuali];
175                         GPU_buffer_pool_remove(i,pool);
176                         DEBUG_VBO("free buffer of exact size found\n");
177                         return allocated;
178                 }
179                 /* smaller buffers won't fit data and buffers at least twice as big are a waste of memory */
180                 else if( cursize > size && size > cursize/2 ) {
181                         /* is it closer to the required size than the last appropriate buffer found. try to save memory */
182                         if( bestfit == -1 || pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size > cursize ) {
183                                 bestfit = i;
184                         }
185                 }
186         }
187         if( bestfit == -1 ) {
188                 DEBUG_VBO("allocating a new buffer\n");
189
190                 allocated = MEM_mallocN(sizeof(GPUBuffer), "GPU_buffer_alloc");
191                 allocated->size = size;
192                 if( useVBOs == 1 ) {
193                         glGenBuffersARB( 1, &allocated->id );
194                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, allocated->id );
195                         glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB );
196                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
197                 }
198                 else {
199                         allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
200                         while( allocated->pointer == 0 && pool->size > 0 ) {
201                                 GPU_buffer_pool_delete_last(pool);
202                                 allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
203                         }
204                         if( allocated->pointer == 0 && pool->size == 0 ) {
205                                 return 0;
206                         }
207                 }
208         }
209         else {
210                 sprintf(buffer,"free buffer found. Wasted %d bytes\n", pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size-size);
211                 DEBUG_VBO(buffer);
212
213                 allocated = pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS];
214                 GPU_buffer_pool_remove(bestfit,pool);
215         }
216         return allocated;
217 }
218
219 void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
220 {
221         int place;
222
223         DEBUG_VBO("GPU_buffer_free\n");
224
225         if( buffer == 0 )
226                 return;
227         if( pool == 0 )
228                 pool = globalPool;
229         if( pool == 0 )
230                 globalPool = GPU_buffer_pool_new();
231
232         while( pool->start < 0 )
233                 pool->start += MAX_FREE_GPU_BUFFERS;
234         place = (pool->start-1 + MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
235
236         /* free the last used buffer in the queue if no more space */
237         if( pool->size == MAX_FREE_GPU_BUFFERS ) {
238                 GPU_buffer_pool_delete_last( pool );
239         }
240
241         pool->size++;
242         pool->start = place;
243         pool->buffers[place] = buffer;
244 }
245
246 GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
247 {
248         GPUDrawObject *object;
249         MVert *mvert;
250         MFace *mface;
251         int numverts[32768];    /* material number is an 16-bit short so there's at most 32768 materials */
252         int redir[32768];               /* material number is an 16-bit short so there's at most 32768 materials */
253         int *index;
254         int i;
255         int curmat, curverts, numfaces;
256
257         DEBUG_VBO("GPU_drawobject_new\n");
258
259         object = MEM_callocN(sizeof(GPUDrawObject),"GPU_drawobject_new_object");
260         object->nindices = dm->getNumVerts(dm);
261         object->indices = MEM_mallocN(sizeof(IndexLink)*object->nindices, "GPU_drawobject_new_indices");
262         object->nedges = dm->getNumEdges(dm);
263
264         for( i = 0; i < object->nindices; i++ ) {
265                 object->indices[i].element = -1;
266                 object->indices[i].next = 0;
267         }
268         /*object->legacy = 1;*/
269         memset(numverts,0,sizeof(int)*32768);
270
271         mvert = dm->getVertArray(dm);
272         mface = dm->getFaceArray(dm);
273
274         numfaces= dm->getNumFaces(dm);
275         for( i=0; i < numfaces; i++ ) {
276                 if( mface[i].v4 )
277                         numverts[mface[i].mat_nr+16383] += 6;   /* split every quad into two triangles */
278                 else
279                         numverts[mface[i].mat_nr+16383] += 3;
280         }
281
282         for( i = 0; i < 32768; i++ ) {
283                 if( numverts[i] > 0 ) {
284                         object->nmaterials++;
285                         object->nelements += numverts[i];
286                 }
287         }
288         object->materials = MEM_mallocN(sizeof(GPUBufferMaterial)*object->nmaterials,"GPU_drawobject_new_materials");
289         index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_drawobject_new_index");
290
291         curmat = curverts = 0;
292         for( i = 0; i < 32768; i++ ) {
293                 if( numverts[i] > 0 ) {
294                         object->materials[curmat].mat_nr = i-16383;
295                         object->materials[curmat].start = curverts;
296                         index[curmat] = curverts/3;
297                         object->materials[curmat].end = curverts+numverts[i];
298                         curverts += numverts[i];
299                         curmat++;
300                 }
301         }
302         object->faceRemap = MEM_mallocN(sizeof(int)*object->nelements/3,"GPU_drawobject_new_faceRemap");
303         for( i = 0; i < object->nmaterials; i++ ) {
304                 redir[object->materials[i].mat_nr+16383] = i;   /* material number -> material index */
305         }
306
307         object->indexMem = MEM_callocN(sizeof(IndexLink)*object->nelements,"GPU_drawobject_new_indexMem");
308         object->indexMemUsage = 0;
309
310 #define ADDLINK( INDEX, ACTUAL ) \
311                 if( object->indices[INDEX].element == -1 ) { \
312                         object->indices[INDEX].element = ACTUAL; \
313                 } else { \
314                         IndexLink *lnk = &object->indices[INDEX]; \
315                         while( lnk->next != 0 ) lnk = lnk->next; \
316                         lnk->next = &object->indexMem[object->indexMemUsage]; \
317                         lnk->next->element = ACTUAL; \
318                         object->indexMemUsage++; \
319                 }
320
321         for( i=0; i < numfaces; i++ ) {
322                 int curInd = index[redir[mface[i].mat_nr+16383]];
323                 object->faceRemap[curInd] = i; 
324                 ADDLINK( mface[i].v1, curInd*3 );
325                 ADDLINK( mface[i].v2, curInd*3+1 );
326                 ADDLINK( mface[i].v3, curInd*3+2 );
327                 if( mface[i].v4 ) {
328                         object->faceRemap[curInd+1] = i;
329                         ADDLINK( mface[i].v3, curInd*3+3 );
330                         ADDLINK( mface[i].v4, curInd*3+4 );
331                         ADDLINK( mface[i].v1, curInd*3+5 );
332
333                         index[redir[mface[i].mat_nr+16383]]+=2;
334                 }
335                 else {
336                         index[redir[mface[i].mat_nr+16383]]++;
337                 }
338         }
339
340         for( i = 0; i < object->nindices; i++ ) {
341                 if( object->indices[i].element == -1 ) {
342                         object->indices[i].element = object->nelements + object->nlooseverts;
343                         object->nlooseverts++;
344                 }
345         }
346 #undef ADDLINK
347
348         MEM_freeN(index);
349         return object;
350 }
351
352 void GPU_drawobject_free( DerivedMesh *dm )
353 {
354         GPUDrawObject *object;
355
356         DEBUG_VBO("GPU_drawobject_free\n");
357
358         if( dm == 0 )
359                 return;
360         object = dm->drawObject;
361         if( object == 0 )
362                 return;
363
364         MEM_freeN(object->materials);
365         MEM_freeN(object->faceRemap);
366         MEM_freeN(object->indices);
367         MEM_freeN(object->indexMem);
368         GPU_buffer_free( object->vertices, globalPool );
369         GPU_buffer_free( object->normals, globalPool );
370         GPU_buffer_free( object->uv, globalPool );
371         GPU_buffer_free( object->colors, globalPool );
372         GPU_buffer_free( object->edges, globalPool );
373         GPU_buffer_free( object->uvedges, globalPool );
374
375         MEM_freeN(object);
376         dm->drawObject = 0;
377 }
378
379 GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
380 {
381         GPUBuffer *buffer;
382         float *varray;
383         int redir[32768];
384         int *index;
385         int i;
386         int success;
387         GLboolean uploaded;
388
389         DEBUG_VBO("GPU_buffer_setup\n");
390
391         if( globalPool == 0 )
392                 globalPool = GPU_buffer_pool_new();
393
394         buffer = GPU_buffer_alloc(size,globalPool);
395         if( buffer == 0 ) {
396                 dm->drawObject->legacy = 1;
397         }
398         if( dm->drawObject->legacy ) {
399                 return 0;
400         }
401
402         index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
403         for( i = 0; i < object->nmaterials; i++ ) {
404                 index[i] = object->materials[i].start*3;
405                 redir[object->materials[i].mat_nr+16383] = i;
406         }
407
408         if( useVBOs ) {
409                 success = 0;
410                 while( success == 0 ) {
411                         glBindBufferARB( target, buffer->id );
412                         glBufferDataARB( target, buffer->size, 0, GL_STATIC_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
413                         varray = glMapBufferARB( target, GL_WRITE_ONLY_ARB );
414                         if( varray == 0 ) {
415                                 DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
416                                 GPU_buffer_free( buffer, globalPool );
417                                 GPU_buffer_pool_delete_last( globalPool );
418                                 if( globalPool->size > 0 ) {
419                                         GPU_buffer_pool_delete_last( globalPool );
420                                         buffer = GPU_buffer_alloc( size, globalPool );
421                                         if( buffer == 0 ) {
422                                                 dm->drawObject->legacy = 1;
423                                                 success = 1;
424                                         }
425                                 }
426                                 else {
427                                         dm->drawObject->legacy = 1;
428                                         success = 1;
429                                 }
430                         }
431                         else {
432                                 success = 1;
433                         }
434                 }
435
436                 if( dm->drawObject->legacy == 0 ) {
437                         uploaded = GL_FALSE;
438                         while( !uploaded ) {
439                                 (*copy_f)( dm, varray, index, redir, user );
440                                 uploaded = glUnmapBufferARB( target );  /* returns false if data got corruped during transfer */
441                         }
442                 }
443                 glBindBufferARB(target, 0);
444         }
445         else {
446                 if( buffer->pointer != 0 ) {
447                         varray = buffer->pointer;
448                         (*copy_f)( dm, varray, index, redir, user );
449                 }
450                 else {
451                         dm->drawObject->legacy = 1;
452                 }
453         }
454
455         MEM_freeN(index);
456
457         return buffer;
458 }
459
460 void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
461 {
462         int start;
463         int i, j, numfaces;
464
465         MVert *mvert;
466         MFace *mface;
467
468         DEBUG_VBO("GPU_buffer_copy_vertex\n");
469
470         mvert = dm->getVertArray(dm);
471         mface = dm->getFaceArray(dm);
472
473         numfaces= dm->getNumFaces(dm);
474         for( i=0; i < numfaces; i++ ) {
475                 start = index[redir[mface[i].mat_nr+16383]];
476                 if( mface[i].v4 )
477                         index[redir[mface[i].mat_nr+16383]] += 18;
478                 else
479                         index[redir[mface[i].mat_nr+16383]] += 9;
480
481                 /* v1 v2 v3 */
482                 VECCOPY(&varray[start],mvert[mface[i].v1].co);
483                 VECCOPY(&varray[start+3],mvert[mface[i].v2].co);
484                 VECCOPY(&varray[start+6],mvert[mface[i].v3].co);
485
486                 if( mface[i].v4 ) {
487                         /* v3 v4 v1 */
488                         VECCOPY(&varray[start+9],mvert[mface[i].v3].co);
489                         VECCOPY(&varray[start+12],mvert[mface[i].v4].co);
490                         VECCOPY(&varray[start+15],mvert[mface[i].v1].co);
491                 }
492         }
493         j = dm->drawObject->nelements*3;
494         for( i = 0; i < dm->drawObject->nindices; i++ ) {
495                 if( dm->drawObject->indices[i].element >= dm->drawObject->nelements ) {
496                         VECCOPY(&varray[j],mvert[i].co);
497                         j+=3;
498                 }
499         }
500 }
501
502 GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
503 {
504         DEBUG_VBO("GPU_buffer_vertex\n");
505
506         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);
507 }
508
509 void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
510 {
511         int i, numfaces;
512         int start;
513         float norm[3];
514
515         float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
516         MVert *mvert = dm->getVertArray(dm);
517         MFace *mface = dm->getFaceArray(dm);
518
519         DEBUG_VBO("GPU_buffer_copy_normal\n");
520
521         numfaces= dm->getNumFaces(dm);
522         for( i=0; i < numfaces; i++ ) {
523                 start = index[redir[mface[i].mat_nr+16383]];
524                 if( mface[i].v4 )
525                         index[redir[mface[i].mat_nr+16383]] += 18;
526                 else
527                         index[redir[mface[i].mat_nr+16383]] += 9;
528
529                 /* v1 v2 v3 */
530                 if( mface[i].flag & ME_SMOOTH ) {
531                         VECCOPY(&varray[start],mvert[mface[i].v1].no);
532                         VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
533                         VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
534                 }
535                 else {
536                         if( nors ) {
537                                 VECCOPY(&varray[start],&nors[i*3]);
538                                 VECCOPY(&varray[start+3],&nors[i*3]);
539                                 VECCOPY(&varray[start+6],&nors[i*3]);
540                         }
541                         if( mface[i].v4 )
542                                 normal_quad_v3( norm,mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co);
543                         else
544                                 normal_tri_v3( norm,mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co);
545                         VECCOPY(&varray[start],norm);
546                         VECCOPY(&varray[start+3],norm);
547                         VECCOPY(&varray[start+6],norm);
548                 }
549
550                 if( mface[i].v4 ) {
551                         /* v3 v4 v1 */
552                         if( mface[i].flag & ME_SMOOTH ) {
553                                 VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
554                                 VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
555                                 VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
556                         }
557                         else {
558                                 VECCOPY(&varray[start+9],norm);
559                                 VECCOPY(&varray[start+12],norm);
560                                 VECCOPY(&varray[start+15],norm);
561                         }
562                 }
563         }
564 }
565
566 GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
567 {
568         DEBUG_VBO("GPU_buffer_normal\n");
569
570         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
571 }
572
573 void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
574 {
575         int start;
576         int i, numfaces;
577
578         MTFace *mtface;
579         MFace *mface;
580
581         DEBUG_VBO("GPU_buffer_copy_uv\n");
582
583         mface = dm->getFaceArray(dm);
584         mtface = DM_get_face_data_layer(dm, CD_MTFACE);
585
586         if( mtface == 0 ) {
587                 DEBUG_VBO("Texture coordinates do not exist for this mesh");
588                 return;
589         }
590                 
591         numfaces= dm->getNumFaces(dm);
592         for( i=0; i < numfaces; i++ ) {
593                 start = index[redir[mface[i].mat_nr+16383]];
594                 if( mface[i].v4 )
595                         index[redir[mface[i].mat_nr+16383]] += 12;
596                 else
597                         index[redir[mface[i].mat_nr+16383]] += 6;
598
599                 /* v1 v2 v3 */
600                 VECCOPY2D(&varray[start],mtface[i].uv[0]);
601                 VECCOPY2D(&varray[start+2],mtface[i].uv[1]);
602                 VECCOPY2D(&varray[start+4],mtface[i].uv[2]);
603
604                 if( mface[i].v4 ) {
605                         /* v3 v4 v1 */
606                         VECCOPY2D(&varray[start+6],mtface[i].uv[2]);
607                         VECCOPY2D(&varray[start+8],mtface[i].uv[3]);
608                         VECCOPY2D(&varray[start+10],mtface[i].uv[0]);
609                 }
610         }
611 }
612
613 GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
614 {
615         DEBUG_VBO("GPU_buffer_uv\n");
616         if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 )
617                 return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
618         else
619                 return 0;
620 }
621
622 void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
623 {
624         int i, numfaces;
625         unsigned char *varray = (unsigned char *)varray_;
626         unsigned char *mcol = (unsigned char *)user;
627         MFace *mface = dm->getFaceArray(dm);
628
629         DEBUG_VBO("GPU_buffer_copy_color3\n");
630
631         numfaces= dm->getNumFaces(dm);
632         for( i=0; i < numfaces; i++ ) {
633                 int start = index[redir[mface[i].mat_nr+16383]];
634                 if( mface[i].v4 )
635                         index[redir[mface[i].mat_nr+16383]] += 18;
636                 else
637                         index[redir[mface[i].mat_nr+16383]] += 9;
638
639                 /* v1 v2 v3 */
640                 VECCOPY(&varray[start],&mcol[i*12]);
641                 VECCOPY(&varray[start+3],&mcol[i*12+3]);
642                 VECCOPY(&varray[start+6],&mcol[i*12+6]);
643                 if( mface[i].v4 ) {
644                         /* v3 v4 v1 */
645                         VECCOPY(&varray[start+9],&mcol[i*12+6]);
646                         VECCOPY(&varray[start+12],&mcol[i*12+9]);
647                         VECCOPY(&varray[start+15],&mcol[i*12]);
648                 }
649         }
650 }
651
652 void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
653 {
654         int i, numfaces;
655         unsigned char *varray = (unsigned char *)varray_;
656         unsigned char *mcol = (unsigned char *)user;
657         MFace *mface = dm->getFaceArray(dm);
658
659         DEBUG_VBO("GPU_buffer_copy_color4\n");
660
661         numfaces= dm->getNumFaces(dm);
662         for( i=0; i < numfaces; i++ ) {
663                 int start = index[redir[mface[i].mat_nr+16383]];
664                 if( mface[i].v4 )
665                         index[redir[mface[i].mat_nr+16383]] += 18;
666                 else
667                         index[redir[mface[i].mat_nr+16383]] += 9;
668
669                 /* v1 v2 v3 */
670                 VECCOPY(&varray[start],&mcol[i*16]);
671                 VECCOPY(&varray[start+3],&mcol[i*16+4]);
672                 VECCOPY(&varray[start+6],&mcol[i*16+8]);
673                 if( mface[i].v4 ) {
674                         /* v3 v4 v1 */
675                         VECCOPY(&varray[start+9],&mcol[i*16+8]);
676                         VECCOPY(&varray[start+12],&mcol[i*16+12]);
677                         VECCOPY(&varray[start+15],&mcol[i*16]);
678                 }
679         }
680 }
681
682 GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
683 {
684         unsigned char *colors;
685         int i, numfaces;
686         MCol *mcol;
687         GPUBuffer *result;
688         DEBUG_VBO("GPU_buffer_color\n");
689
690         mcol = DM_get_face_data_layer(dm, CD_ID_MCOL);
691         dm->drawObject->colType = CD_ID_MCOL;
692         if(!mcol) {
693                 mcol = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
694                 dm->drawObject->colType = CD_WEIGHT_MCOL;
695         }
696         if(!mcol) {
697                 mcol = DM_get_face_data_layer(dm, CD_MCOL);
698                 dm->drawObject->colType = CD_MCOL;
699         }
700
701         numfaces= dm->getNumFaces(dm);
702         colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
703         for( i=0; i < numfaces*4; i++ ) {
704                 colors[i*3] = mcol[i].b;
705                 colors[i*3+1] = mcol[i].g;
706                 colors[i*3+2] = mcol[i].r;
707         }
708
709         result = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
710
711         MEM_freeN(colors);
712         return result;
713 }
714
715 void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
716 {
717         int i;
718
719         MVert *mvert;
720         MEdge *medge;
721         unsigned int *varray_ = (unsigned int *)varray;
722         int numedges;
723  
724         DEBUG_VBO("GPU_buffer_copy_edge\n");
725
726         mvert = dm->getVertArray(dm);
727         medge = dm->getEdgeArray(dm);
728
729         numedges= dm->getNumEdges(dm);
730         for(i = 0; i < numedges; i++) {
731                 varray_[i*2] = (unsigned int)dm->drawObject->indices[medge[i].v1].element;
732                 varray_[i*2+1] = (unsigned int)dm->drawObject->indices[medge[i].v2].element;
733         }
734 }
735
736 GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
737 {
738         DEBUG_VBO("GPU_buffer_edge\n");
739
740         return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
741 }
742
743 void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
744 {
745         MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
746         int i, j=0;
747
748         DEBUG_VBO("GPU_buffer_copy_uvedge\n");
749
750         if(tf) {
751                 for(i = 0; i < dm->numFaceData; i++, tf++) {
752                         MFace mf;
753                         dm->getFace(dm,i,&mf);
754
755                         VECCOPY2D(&varray[j],tf->uv[0]);
756                         VECCOPY2D(&varray[j+2],tf->uv[1]);
757
758                         VECCOPY2D(&varray[j+4],tf->uv[1]);
759                         VECCOPY2D(&varray[j+6],tf->uv[2]);
760
761                         if(!mf.v4) {
762                                 VECCOPY2D(&varray[j+8],tf->uv[2]);
763                                 VECCOPY2D(&varray[j+10],tf->uv[0]);
764                                 j+=12;
765                         } else {
766                                 VECCOPY2D(&varray[j+8],tf->uv[2]);
767                                 VECCOPY2D(&varray[j+10],tf->uv[3]);
768
769                                 VECCOPY2D(&varray[j+12],tf->uv[3]);
770                                 VECCOPY2D(&varray[j+14],tf->uv[0]);
771                                 j+=16;
772                         }
773                 }
774         }
775         else {
776                 DEBUG_VBO("Could not get MTFACE data layer");
777         }
778 }
779
780 GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
781 {
782         DEBUG_VBO("GPU_buffer_uvedge\n");
783
784         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
785 }
786
787
788 void GPU_vertex_setup( DerivedMesh *dm )
789 {
790         DEBUG_VBO("GPU_vertex_setup\n");
791         if( dm->drawObject == 0 )
792                 dm->drawObject = GPU_drawobject_new( dm );
793         if( dm->drawObject->vertices == 0 )
794                 dm->drawObject->vertices = GPU_buffer_vertex( dm );
795         if( dm->drawObject->vertices == 0 ) {
796                 DEBUG_VBO( "Failed to setup vertices\n" );
797                 return;
798         }
799
800         glEnableClientState( GL_VERTEX_ARRAY );
801         if( useVBOs ) {
802                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
803                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
804         }
805         else {
806                 glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
807         }
808         
809         GLStates |= GPU_BUFFER_VERTEX_STATE;
810 }
811
812 void GPU_normal_setup( DerivedMesh *dm )
813 {
814         DEBUG_VBO("GPU_normal_setup\n");
815         if( dm->drawObject == 0 )
816                 dm->drawObject = GPU_drawobject_new( dm );
817         if( dm->drawObject->normals == 0 )
818                 dm->drawObject->normals = GPU_buffer_normal( dm );
819         if( dm->drawObject->normals == 0 ) {
820                 DEBUG_VBO( "Failed to setup normals\n" );
821                 return;
822         }
823         glEnableClientState( GL_NORMAL_ARRAY );
824         if( useVBOs ) {
825                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id );
826                 glNormalPointer( GL_FLOAT, 0, 0 );
827         }
828         else {
829                 glNormalPointer( GL_FLOAT, 0, dm->drawObject->normals->pointer );
830         }
831
832         GLStates |= GPU_BUFFER_NORMAL_STATE;
833 }
834
835 void GPU_uv_setup( DerivedMesh *dm )
836 {
837         DEBUG_VBO("GPU_uv_setup\n");
838         if( dm->drawObject == 0 )
839                 dm->drawObject = GPU_drawobject_new( dm );
840         if( dm->drawObject->uv == 0 )
841                 dm->drawObject->uv = GPU_buffer_uv( dm );
842         
843         if( dm->drawObject->uv != 0 ) {
844                 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
845                 if( useVBOs ) {
846                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id );
847                         glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
848                 }
849                 else {
850                         glTexCoordPointer( 2, GL_FLOAT, 0, dm->drawObject->uv->pointer );
851                 }
852
853                 GLStates |= GPU_BUFFER_TEXCOORD_STATE;
854         }
855 }
856
857 void GPU_color_setup( DerivedMesh *dm )
858 {
859         DEBUG_VBO("GPU_color_setup\n");
860         if( dm->drawObject == 0 )
861                 dm->drawObject = GPU_drawobject_new( dm );
862         if( dm->drawObject->colors == 0 )
863                 dm->drawObject->colors = GPU_buffer_color( dm );
864         if( dm->drawObject->colors == 0 ) {
865                 DEBUG_VBO( "Failed to setup colors\n" );
866                 return;
867         }
868         glEnableClientState( GL_COLOR_ARRAY );
869         if( useVBOs ) {
870                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id );
871                 glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
872         }
873         else {
874                 glColorPointer( 3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer );
875         }
876
877         GLStates |= GPU_BUFFER_COLOR_STATE;
878 }
879
880 void GPU_edge_setup( DerivedMesh *dm )
881 {
882         DEBUG_VBO("GPU_edge_setup\n");
883         if( dm->drawObject == 0 )
884                 dm->drawObject = GPU_drawobject_new( dm );
885         if( dm->drawObject->edges == 0 )
886                 dm->drawObject->edges = GPU_buffer_edge( dm );
887         if( dm->drawObject->edges == 0 ) {
888                 DEBUG_VBO( "Failed to setup edges\n" );
889                 return;
890         }
891         if( dm->drawObject->vertices == 0 )
892                 dm->drawObject->vertices = GPU_buffer_vertex( dm );
893         if( dm->drawObject->vertices == 0 ) {
894                 DEBUG_VBO( "Failed to setup vertices\n" );
895                 return;
896         }
897
898         glEnableClientState( GL_VERTEX_ARRAY );
899         if( useVBOs ) {
900                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
901                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
902         }
903         else {
904                 glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
905         }
906         
907         GLStates |= GPU_BUFFER_VERTEX_STATE;
908
909         if( useVBOs ) {
910                 glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
911         }
912
913         GLStates |= GPU_BUFFER_ELEMENT_STATE;
914 }
915
916 void GPU_uvedge_setup( DerivedMesh *dm )
917 {
918         DEBUG_VBO("GPU_uvedge_setup\n");
919         if( dm->drawObject == 0 )
920                 dm->drawObject = GPU_drawobject_new( dm );
921         if( dm->drawObject->uvedges == 0 )
922                 dm->drawObject->uvedges = GPU_buffer_uvedge( dm );
923         if( dm->drawObject->uvedges == 0 ) {
924                 DEBUG_VBO( "Failed to setup UV edges\n" );
925                 return;
926         }
927
928         glEnableClientState( GL_VERTEX_ARRAY );
929         if( useVBOs ) {
930                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id );
931                 glVertexPointer( 2, GL_FLOAT, 0, 0 );
932         }
933         else {
934                 glVertexPointer( 2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer );
935         }
936         
937         GLStates |= GPU_BUFFER_VERTEX_STATE;
938 }
939
940 void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
941         int i;
942         int elementsize = 0;
943         intptr_t offset = 0;
944
945         DEBUG_VBO("GPU_interleaved_setup\n");
946
947         for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
948                 switch( data[i] ) {
949                         case GPU_BUFFER_INTER_V3F:
950                                 elementsize += 3*sizeof(float);
951                                 break;
952                         case GPU_BUFFER_INTER_N3F:
953                                 elementsize += 3*sizeof(float);
954                                 break;
955                         case GPU_BUFFER_INTER_T2F:
956                                 elementsize += 2*sizeof(float);
957                                 break;
958                         case GPU_BUFFER_INTER_C3UB:
959                                 elementsize += 3*sizeof(unsigned char);
960                                 break;
961                         case GPU_BUFFER_INTER_C4UB:
962                                 elementsize += 4*sizeof(unsigned char);
963                                 break;
964                         default:
965                                 DEBUG_VBO( "Unknown element in data type array in GPU_interleaved_setup\n" );
966                 }
967         }
968
969         if( useVBOs ) {
970                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
971                 for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
972                         switch( data[i] ) {
973                                 case GPU_BUFFER_INTER_V3F:
974                                         glEnableClientState( GL_VERTEX_ARRAY );
975                                         glVertexPointer( 3, GL_FLOAT, elementsize, (void *)offset );
976                                         GLStates |= GPU_BUFFER_VERTEX_STATE;
977                                         offset += 3*sizeof(float);
978                                         break;
979                                 case GPU_BUFFER_INTER_N3F:
980                                         glEnableClientState( GL_NORMAL_ARRAY );
981                                         glNormalPointer( GL_FLOAT, elementsize, (void *)offset );
982                                         GLStates |= GPU_BUFFER_NORMAL_STATE;
983                                         offset += 3*sizeof(float);
984                                         break;
985                                 case GPU_BUFFER_INTER_T2F:
986                                         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
987                                         glTexCoordPointer( 2, GL_FLOAT, elementsize, (void *)offset );
988                                         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
989                                         offset += 2*sizeof(float);
990                                         break;
991                                 case GPU_BUFFER_INTER_C3UB:
992                                         glEnableClientState( GL_COLOR_ARRAY );
993                                         glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
994                                         GLStates |= GPU_BUFFER_COLOR_STATE;
995                                         offset += 3*sizeof(unsigned char);
996                                         break;
997                                 case GPU_BUFFER_INTER_C4UB:
998                                         glEnableClientState( GL_COLOR_ARRAY );
999                                         glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
1000                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1001                                         offset += 4*sizeof(unsigned char);
1002                                         break;
1003                         }
1004                 }
1005         }
1006         else {
1007                 for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
1008                         switch( data[i] ) {
1009                                 case GPU_BUFFER_INTER_V3F:
1010                                         glEnableClientState( GL_VERTEX_ARRAY );
1011                                         glVertexPointer( 3, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1012                                         GLStates |= GPU_BUFFER_VERTEX_STATE;
1013                                         offset += 3*sizeof(float);
1014                                         break;
1015                                 case GPU_BUFFER_INTER_N3F:
1016                                         glEnableClientState( GL_NORMAL_ARRAY );
1017                                         glNormalPointer( GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1018                                         GLStates |= GPU_BUFFER_NORMAL_STATE;
1019                                         offset += 3*sizeof(float);
1020                                         break;
1021                                 case GPU_BUFFER_INTER_T2F:
1022                                         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1023                                         glTexCoordPointer( 2, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1024                                         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
1025                                         offset += 2*sizeof(float);
1026                                         break;
1027                                 case GPU_BUFFER_INTER_C3UB:
1028                                         glEnableClientState( GL_COLOR_ARRAY );
1029                                         glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
1030                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1031                                         offset += 3*sizeof(unsigned char);
1032                                         break;
1033                                 case GPU_BUFFER_INTER_C4UB:
1034                                         glEnableClientState( GL_COLOR_ARRAY );
1035                                         glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
1036                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1037                                         offset += 4*sizeof(unsigned char);
1038                                         break;
1039                         }
1040                 }
1041         }
1042 }
1043
1044 static int GPU_typesize( int type ) {
1045         switch( type ) {
1046                 case GL_FLOAT:
1047                         return sizeof(float);
1048                 case GL_INT:
1049                         return sizeof(int);
1050                 case GL_UNSIGNED_INT:
1051                         return sizeof(unsigned int);
1052                 case GL_BYTE:
1053                         return sizeof(char);
1054                 case GL_UNSIGNED_BYTE:
1055                         return sizeof(unsigned char);
1056                 default:
1057                         return 0;
1058         }
1059 }
1060
1061 int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
1062         int i, elementsize = 0;
1063
1064         for( i = 0; i < numdata; i++ ) {
1065                 int typesize = GPU_typesize(data[i].type);
1066                 if( typesize == 0 )
1067                         DEBUG_VBO( "Unknown element in data type array in GPU_attrib_element_size\n" );
1068                 else {
1069                         elementsize += typesize*data[i].size;
1070                 }
1071         }
1072         return elementsize;
1073 }
1074
1075 void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
1076         int i;
1077         int elementsize;
1078         intptr_t offset = 0;
1079
1080         DEBUG_VBO("GPU_interleaved_attrib_setup\n");
1081
1082         for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
1083                 if( attribData[i].index != -1 ) {
1084                         glDisableVertexAttribArrayARB( attribData[i].index );
1085                 }
1086                 else
1087                         break;
1088         }
1089         elementsize = GPU_attrib_element_size( data, numdata );
1090
1091         if( useVBOs ) {
1092                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1093                 for( i = 0; i < numdata; i++ ) {
1094                         glEnableVertexAttribArrayARB( data[i].index );
1095                         glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (void *)offset );
1096                         offset += data[i].size*GPU_typesize(data[i].type);
1097
1098                         attribData[i].index = data[i].index;
1099                         attribData[i].size = data[i].size;
1100                         attribData[i].type = data[i].type;
1101                 }
1102                 attribData[numdata].index = -1;
1103         }
1104         else {
1105                 for( i = 0; i < numdata; i++ ) {
1106                         glEnableVertexAttribArrayARB( data[i].index );
1107                         glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (char *)buffer->pointer + offset );
1108                         offset += data[i].size*GPU_typesize(data[i].type);
1109                 }
1110         }
1111 }
1112
1113
1114 void GPU_buffer_unbind()
1115 {
1116         int i;
1117         DEBUG_VBO("GPU_buffer_unbind\n");
1118
1119         if( GLStates & GPU_BUFFER_VERTEX_STATE )
1120                 glDisableClientState( GL_VERTEX_ARRAY );
1121         if( GLStates & GPU_BUFFER_NORMAL_STATE )
1122                 glDisableClientState( GL_NORMAL_ARRAY );
1123         if( GLStates & GPU_BUFFER_TEXCOORD_STATE )
1124                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1125         if( GLStates & GPU_BUFFER_COLOR_STATE )
1126                 glDisableClientState( GL_COLOR_ARRAY );
1127         if( GLStates & GPU_BUFFER_ELEMENT_STATE ) {
1128                 if( useVBOs ) {
1129                         glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
1130                 }
1131         }
1132         GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
1133
1134         for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
1135                 if( attribData[i].index != -1 ) {
1136                         glDisableVertexAttribArrayARB( attribData[i].index );
1137                 }
1138                 else
1139                         break;
1140         }
1141         if( GLStates != 0 )
1142                 DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
1143         if( useVBOs )
1144                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1145 }
1146
1147 void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
1148 {
1149         if( dm->drawObject == 0 )
1150                 dm->drawObject = GPU_drawobject_new(dm);
1151         GPU_buffer_free(dm->drawObject->colors,globalPool);
1152         dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
1153 }
1154 void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
1155 {
1156         if( dm->drawObject == 0 )
1157                 dm->drawObject = GPU_drawobject_new(dm);
1158         GPU_buffer_free(dm->drawObject->colors,globalPool);
1159         dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
1160 }
1161
1162 void GPU_color_switch( int mode )
1163 {
1164         if( mode ) {
1165                 if( !(GLStates & GPU_BUFFER_COLOR_STATE) )
1166                         glEnableClientState( GL_COLOR_ARRAY );
1167                 GLStates |= GPU_BUFFER_COLOR_STATE;
1168         }
1169         else {
1170                 if( GLStates & GPU_BUFFER_COLOR_STATE )
1171                         glDisableClientState( GL_COLOR_ARRAY );
1172                 GLStates &= (!GPU_BUFFER_COLOR_STATE);
1173         }
1174 }
1175
1176 int GPU_buffer_legacy( DerivedMesh *dm )
1177 {
1178         int test= (U.gameflags & USER_DISABLE_VBO);
1179         if( test )
1180                 return 1;
1181
1182         if( dm->drawObject == 0 )
1183                 dm->drawObject = GPU_drawobject_new(dm);
1184         return dm->drawObject->legacy;
1185 }
1186
1187 void *GPU_buffer_lock( GPUBuffer *buffer )
1188 {
1189         float *varray;
1190
1191         DEBUG_VBO("GPU_buffer_lock\n");
1192         if( buffer == 0 ) {
1193                 DEBUG_VBO( "Failed to lock NULL buffer\n" );
1194                 return 0;
1195         }
1196
1197         if( useVBOs ) {
1198                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1199                 varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1200                 if( varray == 0 ) {
1201                         DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
1202                 }
1203                 return varray;
1204         }
1205         else {
1206                 return buffer->pointer;
1207         }
1208 }
1209
1210 void *GPU_buffer_lock_stream( GPUBuffer *buffer )
1211 {
1212         float *varray;
1213
1214         DEBUG_VBO("GPU_buffer_lock_stream\n");
1215         if( buffer == 0 ) {
1216                 DEBUG_VBO( "Failed to lock NULL buffer\n" );
1217                 return 0;
1218         }
1219
1220         if( useVBOs ) {
1221                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1222                 glBufferDataARB( GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB );    /* discard previous data, avoid stalling gpu */
1223                 varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1224                 if( varray == 0 ) {
1225                         DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
1226                 }
1227                 return varray;
1228         }
1229         else {
1230                 return buffer->pointer;
1231         }
1232 }
1233
1234 void GPU_buffer_unlock( GPUBuffer *buffer )
1235 {
1236         DEBUG_VBO( "GPU_buffer_unlock\n" ); 
1237         if( useVBOs ) {
1238                 if( buffer != 0 ) {
1239                         if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == 0 ) {
1240                                 DEBUG_VBO( "Failed to copy new data\n" ); 
1241                         }
1242                 }
1243                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1244         }
1245 }
1246
1247 void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
1248 {
1249         if( useVBOs ) {
1250                 glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
1251         }
1252         else {
1253                 glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
1254         }
1255 }