Make compiler happy, remove doubtful non init usage.
[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 <string.h>
34
35 #include "GL/glew.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_arithb.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                 /* somehow GL_NORMAL_ARRAY is enabled on startup and causes edge drawing code to crash */
395                 glDisableClientState( GL_VERTEX_ARRAY );
396                 glDisableClientState( GL_NORMAL_ARRAY );
397                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
398                 glDisableClientState( GL_COLOR_ARRAY );
399         }
400         buffer = GPU_buffer_alloc(size,globalPool);
401         if( buffer == 0 ) {
402                 dm->drawObject->legacy = 1;
403         }
404         if( dm->drawObject->legacy ) {
405                 return 0;
406         }
407
408         index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
409         for( i = 0; i < object->nmaterials; i++ ) {
410                 index[i] = object->materials[i].start*3;
411                 redir[object->materials[i].mat_nr+16383] = i;
412         }
413
414         if( useVBOs ) {
415                 success = 0;
416                 while( success == 0 ) {
417                         glBindBufferARB( target, buffer->id );
418                         glBufferDataARB( target, buffer->size, 0, GL_STATIC_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
419                         varray = glMapBufferARB( target, GL_WRITE_ONLY_ARB );
420                         if( varray == 0 ) {
421                                 DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
422                                 GPU_buffer_free( buffer, globalPool );
423                                 GPU_buffer_pool_delete_last( globalPool );
424                                 if( globalPool->size > 0 ) {
425                                         GPU_buffer_pool_delete_last( globalPool );
426                                         buffer = GPU_buffer_alloc( size, globalPool );
427                                         if( buffer == 0 ) {
428                                                 dm->drawObject->legacy = 1;
429                                                 success = 1;
430                                         }
431                                 }
432                                 else {
433                                         dm->drawObject->legacy = 1;
434                                         success = 1;
435                                 }
436                         }
437                         else {
438                                 success = 1;
439                         }
440                 }
441
442                 if( dm->drawObject->legacy == 0 ) {
443                         uploaded = GL_FALSE;
444                         while( !uploaded ) {
445                                 (*copy_f)( dm, varray, index, redir, user );
446                                 uploaded = glUnmapBufferARB( target );  /* returns false if data got corruped during transfer */
447                         }
448                 }
449                 glBindBufferARB(target, 0);
450         }
451         else {
452                 if( buffer->pointer != 0 ) {
453                         varray = buffer->pointer;
454                         (*copy_f)( dm, varray, index, redir, user );
455                 }
456                 else {
457                         dm->drawObject->legacy = 1;
458                 }
459         }
460
461         MEM_freeN(index);
462
463         return buffer;
464 }
465
466 void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
467 {
468         int start;
469         int i, j, numfaces;
470
471         MVert *mvert;
472         MFace *mface;
473
474         DEBUG_VBO("GPU_buffer_copy_vertex\n");
475
476         mvert = dm->getVertArray(dm);
477         mface = dm->getFaceArray(dm);
478
479         numfaces= dm->getNumFaces(dm);
480         for( i=0; i < numfaces; i++ ) {
481                 start = index[redir[mface[i].mat_nr+16383]];
482                 if( mface[i].v4 )
483                         index[redir[mface[i].mat_nr+16383]] += 18;
484                 else
485                         index[redir[mface[i].mat_nr+16383]] += 9;
486
487                 /* v1 v2 v3 */
488                 VECCOPY(&varray[start],mvert[mface[i].v1].co);
489                 VECCOPY(&varray[start+3],mvert[mface[i].v2].co);
490                 VECCOPY(&varray[start+6],mvert[mface[i].v3].co);
491
492                 if( mface[i].v4 ) {
493                         /* v3 v4 v1 */
494                         VECCOPY(&varray[start+9],mvert[mface[i].v3].co);
495                         VECCOPY(&varray[start+12],mvert[mface[i].v4].co);
496                         VECCOPY(&varray[start+15],mvert[mface[i].v1].co);
497                 }
498         }
499         j = dm->drawObject->nelements*3;
500         for( i = 0; i < dm->drawObject->nindices; i++ ) {
501                 if( dm->drawObject->indices[i].element >= dm->drawObject->nelements ) {
502                         VECCOPY(&varray[j],mvert[i].co);
503                         j+=3;
504                 }
505         }
506 }
507
508 GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
509 {
510         DEBUG_VBO("GPU_buffer_vertex\n");
511
512         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);
513 }
514
515 void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
516 {
517         int i, numfaces;
518         int start;
519         float norm[3];
520
521         float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
522         MVert *mvert = dm->getVertArray(dm);
523         MFace *mface = dm->getFaceArray(dm);
524
525         DEBUG_VBO("GPU_buffer_copy_normal\n");
526
527         numfaces= dm->getNumFaces(dm);
528         for( i=0; i < numfaces; i++ ) {
529                 start = index[redir[mface[i].mat_nr+16383]];
530                 if( mface[i].v4 )
531                         index[redir[mface[i].mat_nr+16383]] += 18;
532                 else
533                         index[redir[mface[i].mat_nr+16383]] += 9;
534
535                 /* v1 v2 v3 */
536                 if( mface[i].flag & ME_SMOOTH ) {
537                         VECCOPY(&varray[start],mvert[mface[i].v1].no);
538                         VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
539                         VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
540                 }
541                 else {
542                         if( nors ) {
543                                 VECCOPY(&varray[start],&nors[i*3]);
544                                 VECCOPY(&varray[start+3],&nors[i*3]);
545                                 VECCOPY(&varray[start+6],&nors[i*3]);
546                         }
547                         if( mface[i].v4 )
548                                 CalcNormFloat4(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co, norm);
549                         else
550                                 CalcNormFloat(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, norm);
551                         VECCOPY(&varray[start],norm);
552                         VECCOPY(&varray[start+3],norm);
553                         VECCOPY(&varray[start+6],norm);
554                 }
555
556                 if( mface[i].v4 ) {
557                         /* v3 v4 v1 */
558                         if( mface[i].flag & ME_SMOOTH ) {
559                                 VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
560                                 VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
561                                 VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
562                         }
563                         else {
564                                 VECCOPY(&varray[start+9],norm);
565                                 VECCOPY(&varray[start+12],norm);
566                                 VECCOPY(&varray[start+15],norm);
567                         }
568                 }
569         }
570 }
571
572 GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
573 {
574         DEBUG_VBO("GPU_buffer_normal\n");
575
576         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
577 }
578
579 void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
580 {
581         int start;
582         int i, numfaces;
583
584         MTFace *mtface;
585         MFace *mface;
586
587         DEBUG_VBO("GPU_buffer_copy_uv\n");
588
589         mface = dm->getFaceArray(dm);
590         mtface = DM_get_face_data_layer(dm, CD_MTFACE);
591
592         if( mtface == 0 ) {
593                 DEBUG_VBO("Texture coordinates do not exist for this mesh");
594                 return;
595         }
596                 
597         numfaces= dm->getNumFaces(dm);
598         for( i=0; i < numfaces; i++ ) {
599                 start = index[redir[mface[i].mat_nr+16383]];
600                 if( mface[i].v4 )
601                         index[redir[mface[i].mat_nr+16383]] += 12;
602                 else
603                         index[redir[mface[i].mat_nr+16383]] += 6;
604
605                 /* v1 v2 v3 */
606                 VECCOPY2D(&varray[start],mtface[i].uv[0]);
607                 VECCOPY2D(&varray[start+2],mtface[i].uv[1]);
608                 VECCOPY2D(&varray[start+4],mtface[i].uv[2]);
609
610                 if( mface[i].v4 ) {
611                         /* v3 v4 v1 */
612                         VECCOPY2D(&varray[start+6],mtface[i].uv[2]);
613                         VECCOPY2D(&varray[start+8],mtface[i].uv[3]);
614                         VECCOPY2D(&varray[start+10],mtface[i].uv[0]);
615                 }
616         }
617 }
618
619 GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
620 {
621         DEBUG_VBO("GPU_buffer_uv\n");
622         if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 )
623                 return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
624         else
625                 return 0;
626 }
627
628 void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
629 {
630         int i, numfaces;
631         unsigned char *varray = (unsigned char *)varray_;
632         unsigned char *mcol = (unsigned char *)user;
633         MFace *mface = dm->getFaceArray(dm);
634
635         DEBUG_VBO("GPU_buffer_copy_color3\n");
636
637         numfaces= dm->getNumFaces(dm);
638         for( i=0; i < numfaces; i++ ) {
639                 int start = index[redir[mface[i].mat_nr+16383]];
640                 if( mface[i].v4 )
641                         index[redir[mface[i].mat_nr+16383]] += 18;
642                 else
643                         index[redir[mface[i].mat_nr+16383]] += 9;
644
645                 /* v1 v2 v3 */
646                 VECCOPY(&varray[start],&mcol[i*12]);
647                 VECCOPY(&varray[start+3],&mcol[i*12+3]);
648                 VECCOPY(&varray[start+6],&mcol[i*12+6]);
649                 if( mface[i].v4 ) {
650                         /* v3 v4 v1 */
651                         VECCOPY(&varray[start+9],&mcol[i*12+6]);
652                         VECCOPY(&varray[start+12],&mcol[i*12+9]);
653                         VECCOPY(&varray[start+15],&mcol[i*12]);
654                 }
655         }
656 }
657
658 void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
659 {
660         int i, numfaces;
661         unsigned char *varray = (unsigned char *)varray_;
662         unsigned char *mcol = (unsigned char *)user;
663         MFace *mface = dm->getFaceArray(dm);
664
665         DEBUG_VBO("GPU_buffer_copy_color4\n");
666
667         numfaces= dm->getNumFaces(dm);
668         for( i=0; i < numfaces; i++ ) {
669                 int start = index[redir[mface[i].mat_nr+16383]];
670                 if( mface[i].v4 )
671                         index[redir[mface[i].mat_nr+16383]] += 18;
672                 else
673                         index[redir[mface[i].mat_nr+16383]] += 9;
674
675                 /* v1 v2 v3 */
676                 VECCOPY(&varray[start],&mcol[i*16]);
677                 VECCOPY(&varray[start+3],&mcol[i*16+4]);
678                 VECCOPY(&varray[start+6],&mcol[i*16+8]);
679                 if( mface[i].v4 ) {
680                         /* v3 v4 v1 */
681                         VECCOPY(&varray[start+9],&mcol[i*16+8]);
682                         VECCOPY(&varray[start+12],&mcol[i*16+12]);
683                         VECCOPY(&varray[start+15],&mcol[i*16]);
684                 }
685         }
686 }
687
688 GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
689 {
690         unsigned char *colors;
691         int i, numfaces;
692         MCol *mcol;
693         GPUBuffer *result;
694         DEBUG_VBO("GPU_buffer_color\n");
695
696         mcol = DM_get_face_data_layer(dm, CD_ID_MCOL);
697         dm->drawObject->colType = CD_ID_MCOL;
698         if(!mcol) {
699                 mcol = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
700                 dm->drawObject->colType = CD_WEIGHT_MCOL;
701         }
702         if(!mcol) {
703                 mcol = DM_get_face_data_layer(dm, CD_MCOL);
704                 dm->drawObject->colType = CD_MCOL;
705         }
706
707         numfaces= dm->getNumFaces(dm);
708         colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
709         for( i=0; i < numfaces*4; i++ ) {
710                 colors[i*3] = mcol[i].b;
711                 colors[i*3+1] = mcol[i].g;
712                 colors[i*3+2] = mcol[i].r;
713         }
714
715         result = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
716
717         MEM_freeN(colors);
718         return result;
719 }
720
721 void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
722 {
723         int i;
724
725         MVert *mvert;
726         MEdge *medge;
727         unsigned int *varray_ = (unsigned int *)varray;
728         int numedges;
729  
730         DEBUG_VBO("GPU_buffer_copy_edge\n");
731
732         mvert = dm->getVertArray(dm);
733         medge = dm->getEdgeArray(dm);
734
735         numedges= dm->getNumEdges(dm);
736         for(i = 0; i < numedges; i++) {
737                 varray_[i*2] = (unsigned int)dm->drawObject->indices[medge[i].v1].element;
738                 varray_[i*2+1] = (unsigned int)dm->drawObject->indices[medge[i].v2].element;
739         }
740 }
741
742 GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
743 {
744         DEBUG_VBO("GPU_buffer_edge\n");
745
746         return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
747 }
748
749 void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
750 {
751         MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
752         int i, j=0;
753
754         DEBUG_VBO("GPU_buffer_copy_uvedge\n");
755
756         if(tf) {
757                 for(i = 0; i < dm->numFaceData; i++, tf++) {
758                         MFace mf;
759                         dm->getFace(dm,i,&mf);
760
761                         VECCOPY2D(&varray[j],tf->uv[0]);
762                         VECCOPY2D(&varray[j+2],tf->uv[1]);
763
764                         VECCOPY2D(&varray[j+4],tf->uv[1]);
765                         VECCOPY2D(&varray[j+6],tf->uv[2]);
766
767                         if(!mf.v4) {
768                                 VECCOPY2D(&varray[j+8],tf->uv[2]);
769                                 VECCOPY2D(&varray[j+10],tf->uv[0]);
770                                 j+=12;
771                         } else {
772                                 VECCOPY2D(&varray[j+8],tf->uv[2]);
773                                 VECCOPY2D(&varray[j+10],tf->uv[3]);
774
775                                 VECCOPY2D(&varray[j+12],tf->uv[3]);
776                                 VECCOPY2D(&varray[j+14],tf->uv[0]);
777                                 j+=16;
778                         }
779                 }
780         }
781         else {
782                 DEBUG_VBO("Could not get MTFACE data layer");
783         }
784 }
785
786 GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
787 {
788         DEBUG_VBO("GPU_buffer_uvedge\n");
789
790         return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
791 }
792
793
794 void GPU_vertex_setup( DerivedMesh *dm )
795 {
796         DEBUG_VBO("GPU_vertex_setup\n");
797         if( dm->drawObject == 0 )
798                 dm->drawObject = GPU_drawobject_new( dm );
799         if( dm->drawObject->vertices == 0 )
800                 dm->drawObject->vertices = GPU_buffer_vertex( dm );
801         if( dm->drawObject->vertices == 0 ) {
802                 DEBUG_VBO( "Failed to setup vertices\n" );
803                 return;
804         }
805
806         glEnableClientState( GL_VERTEX_ARRAY );
807         if( useVBOs ) {
808                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
809                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
810         }
811         else {
812                 glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
813         }
814         
815         GLStates |= GPU_BUFFER_VERTEX_STATE;
816 }
817
818 void GPU_normal_setup( DerivedMesh *dm )
819 {
820         DEBUG_VBO("GPU_normal_setup\n");
821         if( dm->drawObject == 0 )
822                 dm->drawObject = GPU_drawobject_new( dm );
823         if( dm->drawObject->normals == 0 )
824                 dm->drawObject->normals = GPU_buffer_normal( dm );
825         if( dm->drawObject->normals == 0 ) {
826                 DEBUG_VBO( "Failed to setup normals\n" );
827                 return;
828         }
829         glEnableClientState( GL_NORMAL_ARRAY );
830         if( useVBOs ) {
831                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id );
832                 glNormalPointer( GL_FLOAT, 0, 0 );
833         }
834         else {
835                 glNormalPointer( GL_FLOAT, 0, dm->drawObject->normals->pointer );
836         }
837
838         GLStates |= GPU_BUFFER_NORMAL_STATE;
839 }
840
841 void GPU_uv_setup( DerivedMesh *dm )
842 {
843         DEBUG_VBO("GPU_uv_setup\n");
844         if( dm->drawObject == 0 )
845                 dm->drawObject = GPU_drawobject_new( dm );
846         if( dm->drawObject->uv == 0 )
847                 dm->drawObject->uv = GPU_buffer_uv( dm );
848         
849         if( dm->drawObject->uv != 0 ) {
850                 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
851                 if( useVBOs ) {
852                         glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id );
853                         glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
854                 }
855                 else {
856                         glTexCoordPointer( 2, GL_FLOAT, 0, dm->drawObject->uv->pointer );
857                 }
858
859                 GLStates |= GPU_BUFFER_TEXCOORD_STATE;
860         }
861 }
862
863 void GPU_color_setup( DerivedMesh *dm )
864 {
865         DEBUG_VBO("GPU_color_setup\n");
866         if( dm->drawObject == 0 )
867                 dm->drawObject = GPU_drawobject_new( dm );
868         if( dm->drawObject->colors == 0 )
869                 dm->drawObject->colors = GPU_buffer_color( dm );
870         if( dm->drawObject->colors == 0 ) {
871                 DEBUG_VBO( "Failed to setup colors\n" );
872                 return;
873         }
874         glEnableClientState( GL_COLOR_ARRAY );
875         if( useVBOs ) {
876                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id );
877                 glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
878         }
879         else {
880                 glColorPointer( 3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer );
881         }
882
883         GLStates |= GPU_BUFFER_COLOR_STATE;
884 }
885
886 void GPU_edge_setup( DerivedMesh *dm )
887 {
888         DEBUG_VBO("GPU_edge_setup\n");
889         if( dm->drawObject == 0 )
890                 dm->drawObject = GPU_drawobject_new( dm );
891         if( dm->drawObject->edges == 0 )
892                 dm->drawObject->edges = GPU_buffer_edge( dm );
893         if( dm->drawObject->edges == 0 ) {
894                 DEBUG_VBO( "Failed to setup edges\n" );
895                 return;
896         }
897         if( dm->drawObject->vertices == 0 )
898                 dm->drawObject->vertices = GPU_buffer_vertex( dm );
899         if( dm->drawObject->vertices == 0 ) {
900                 DEBUG_VBO( "Failed to setup vertices\n" );
901                 return;
902         }
903
904         glEnableClientState( GL_VERTEX_ARRAY );
905         if( useVBOs ) {
906                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
907                 glVertexPointer( 3, GL_FLOAT, 0, 0 );
908         }
909         else {
910                 glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
911         }
912         
913         GLStates |= GPU_BUFFER_VERTEX_STATE;
914
915         if( useVBOs ) {
916                 glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
917         }
918
919         GLStates |= GPU_BUFFER_ELEMENT_STATE;
920 }
921
922 void GPU_uvedge_setup( DerivedMesh *dm )
923 {
924         DEBUG_VBO("GPU_uvedge_setup\n");
925         if( dm->drawObject == 0 )
926                 dm->drawObject = GPU_drawobject_new( dm );
927         if( dm->drawObject->uvedges == 0 )
928                 dm->drawObject->uvedges = GPU_buffer_uvedge( dm );
929         if( dm->drawObject->uvedges == 0 ) {
930                 DEBUG_VBO( "Failed to setup UV edges\n" );
931                 return;
932         }
933
934         glEnableClientState( GL_VERTEX_ARRAY );
935         if( useVBOs ) {
936                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id );
937                 glVertexPointer( 2, GL_FLOAT, 0, 0 );
938         }
939         else {
940                 glVertexPointer( 2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer );
941         }
942         
943         GLStates |= GPU_BUFFER_VERTEX_STATE;
944 }
945
946 void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
947         int i;
948         int elementsize = 0;
949         intptr_t offset = 0;
950
951         DEBUG_VBO("GPU_interleaved_setup\n");
952
953         for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
954                 switch( data[i] ) {
955                         case GPU_BUFFER_INTER_V3F:
956                                 elementsize += 3*sizeof(float);
957                                 break;
958                         case GPU_BUFFER_INTER_N3F:
959                                 elementsize += 3*sizeof(float);
960                                 break;
961                         case GPU_BUFFER_INTER_T2F:
962                                 elementsize += 2*sizeof(float);
963                                 break;
964                         case GPU_BUFFER_INTER_C3UB:
965                                 elementsize += 3*sizeof(unsigned char);
966                                 break;
967                         case GPU_BUFFER_INTER_C4UB:
968                                 elementsize += 4*sizeof(unsigned char);
969                                 break;
970                         default:
971                                 DEBUG_VBO( "Unknown element in data type array in GPU_interleaved_setup\n" );
972                 }
973         }
974
975         if( useVBOs ) {
976                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
977                 for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
978                         switch( data[i] ) {
979                                 case GPU_BUFFER_INTER_V3F:
980                                         glEnableClientState( GL_VERTEX_ARRAY );
981                                         glVertexPointer( 3, GL_FLOAT, elementsize, (void *)offset );
982                                         GLStates |= GPU_BUFFER_VERTEX_STATE;
983                                         offset += 3*sizeof(float);
984                                         break;
985                                 case GPU_BUFFER_INTER_N3F:
986                                         glEnableClientState( GL_NORMAL_ARRAY );
987                                         glNormalPointer( GL_FLOAT, elementsize, (void *)offset );
988                                         GLStates |= GPU_BUFFER_NORMAL_STATE;
989                                         offset += 3*sizeof(float);
990                                         break;
991                                 case GPU_BUFFER_INTER_T2F:
992                                         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
993                                         glTexCoordPointer( 2, GL_FLOAT, elementsize, (void *)offset );
994                                         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
995                                         offset += 2*sizeof(float);
996                                         break;
997                                 case GPU_BUFFER_INTER_C3UB:
998                                         glEnableClientState( GL_COLOR_ARRAY );
999                                         glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
1000                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1001                                         offset += 3*sizeof(unsigned char);
1002                                         break;
1003                                 case GPU_BUFFER_INTER_C4UB:
1004                                         glEnableClientState( GL_COLOR_ARRAY );
1005                                         glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
1006                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1007                                         offset += 4*sizeof(unsigned char);
1008                                         break;
1009                         }
1010                 }
1011         }
1012         else {
1013                 for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
1014                         switch( data[i] ) {
1015                                 case GPU_BUFFER_INTER_V3F:
1016                                         glEnableClientState( GL_VERTEX_ARRAY );
1017                                         glVertexPointer( 3, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1018                                         GLStates |= GPU_BUFFER_VERTEX_STATE;
1019                                         offset += 3*sizeof(float);
1020                                         break;
1021                                 case GPU_BUFFER_INTER_N3F:
1022                                         glEnableClientState( GL_NORMAL_ARRAY );
1023                                         glNormalPointer( GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1024                                         GLStates |= GPU_BUFFER_NORMAL_STATE;
1025                                         offset += 3*sizeof(float);
1026                                         break;
1027                                 case GPU_BUFFER_INTER_T2F:
1028                                         glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1029                                         glTexCoordPointer( 2, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
1030                                         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
1031                                         offset += 2*sizeof(float);
1032                                         break;
1033                                 case GPU_BUFFER_INTER_C3UB:
1034                                         glEnableClientState( GL_COLOR_ARRAY );
1035                                         glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
1036                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1037                                         offset += 3*sizeof(unsigned char);
1038                                         break;
1039                                 case GPU_BUFFER_INTER_C4UB:
1040                                         glEnableClientState( GL_COLOR_ARRAY );
1041                                         glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
1042                                         GLStates |= GPU_BUFFER_COLOR_STATE;
1043                                         offset += 4*sizeof(unsigned char);
1044                                         break;
1045                         }
1046                 }
1047         }
1048 }
1049
1050 static int GPU_typesize( int type ) {
1051         switch( type ) {
1052                 case GL_FLOAT:
1053                         return sizeof(float);
1054                 case GL_INT:
1055                         return sizeof(int);
1056                 case GL_UNSIGNED_INT:
1057                         return sizeof(unsigned int);
1058                 case GL_BYTE:
1059                         return sizeof(char);
1060                 case GL_UNSIGNED_BYTE:
1061                         return sizeof(unsigned char);
1062                 default:
1063                         return 0;
1064         }
1065 }
1066
1067 int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
1068         int i, elementsize = 0;
1069
1070         for( i = 0; i < numdata; i++ ) {
1071                 int typesize = GPU_typesize(data[i].type);
1072                 if( typesize == 0 )
1073                         DEBUG_VBO( "Unknown element in data type array in GPU_attrib_element_size\n" );
1074                 else {
1075                         elementsize += typesize*data[i].size;
1076                 }
1077         }
1078         return elementsize;
1079 }
1080
1081 void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
1082         int i;
1083         int elementsize;
1084         intptr_t offset = 0;
1085
1086         DEBUG_VBO("GPU_interleaved_attrib_setup\n");
1087
1088         for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
1089                 if( attribData[i].index != -1 ) {
1090                         glDisableVertexAttribArrayARB( attribData[i].index );
1091                 }
1092                 else
1093                         break;
1094         }
1095         elementsize = GPU_attrib_element_size( data, numdata );
1096
1097         if( useVBOs ) {
1098                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1099                 for( i = 0; i < numdata; i++ ) {
1100                         glEnableVertexAttribArrayARB( data[i].index );
1101                         glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (void *)offset );
1102                         offset += data[i].size*GPU_typesize(data[i].type);
1103
1104                         attribData[i].index = data[i].index;
1105                         attribData[i].size = data[i].size;
1106                         attribData[i].type = data[i].type;
1107                 }
1108                 attribData[numdata].index = -1;
1109         }
1110         else {
1111                 for( i = 0; i < numdata; i++ ) {
1112                         glEnableVertexAttribArrayARB( data[i].index );
1113                         glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (char *)buffer->pointer + offset );
1114                         offset += data[i].size*GPU_typesize(data[i].type);
1115                 }
1116         }
1117 }
1118
1119
1120 void GPU_buffer_unbind()
1121 {
1122         int i;
1123         DEBUG_VBO("GPU_buffer_unbind\n");
1124
1125         if( GLStates & GPU_BUFFER_VERTEX_STATE )
1126                 glDisableClientState( GL_VERTEX_ARRAY );
1127         if( GLStates & GPU_BUFFER_NORMAL_STATE )
1128                 glDisableClientState( GL_NORMAL_ARRAY );
1129         if( GLStates & GPU_BUFFER_TEXCOORD_STATE )
1130                 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
1131         if( GLStates & GPU_BUFFER_COLOR_STATE )
1132                 glDisableClientState( GL_COLOR_ARRAY );
1133         if( GLStates & GPU_BUFFER_ELEMENT_STATE ) {
1134                 if( useVBOs ) {
1135                         glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
1136                 }
1137         }
1138         GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
1139
1140         for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
1141                 if( attribData[i].index != -1 ) {
1142                         glDisableVertexAttribArrayARB( attribData[i].index );
1143                 }
1144                 else
1145                         break;
1146         }
1147         if( GLStates != 0 )
1148                 DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
1149         if( useVBOs )
1150                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1151 }
1152
1153 void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
1154 {
1155         if( dm->drawObject == 0 )
1156                 dm->drawObject = GPU_drawobject_new(dm);
1157         GPU_buffer_free(dm->drawObject->colors,globalPool);
1158         dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
1159 }
1160 void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
1161 {
1162         if( dm->drawObject == 0 )
1163                 dm->drawObject = GPU_drawobject_new(dm);
1164         GPU_buffer_free(dm->drawObject->colors,globalPool);
1165         dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
1166 }
1167
1168 void GPU_color_switch( int mode )
1169 {
1170         if( mode ) {
1171                 if( !(GLStates & GPU_BUFFER_COLOR_STATE) )
1172                         glEnableClientState( GL_COLOR_ARRAY );
1173                 GLStates |= GPU_BUFFER_COLOR_STATE;
1174         }
1175         else {
1176                 if( GLStates & GPU_BUFFER_COLOR_STATE )
1177                         glDisableClientState( GL_COLOR_ARRAY );
1178                 GLStates &= (!GPU_BUFFER_COLOR_STATE);
1179         }
1180 }
1181
1182 int GPU_buffer_legacy( DerivedMesh *dm )
1183 {
1184         int test= (U.gameflags & USER_DISABLE_VBO);
1185         if( test )
1186                 return 1;
1187
1188         if( dm->drawObject == 0 )
1189                 dm->drawObject = GPU_drawobject_new(dm);
1190         return dm->drawObject->legacy;
1191 }
1192
1193 void *GPU_buffer_lock( GPUBuffer *buffer )
1194 {
1195         float *varray;
1196
1197         DEBUG_VBO("GPU_buffer_lock\n");
1198         if( buffer == 0 ) {
1199                 DEBUG_VBO( "Failed to lock NULL buffer\n" );
1200                 return 0;
1201         }
1202
1203         if( useVBOs ) {
1204                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1205                 varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1206                 if( varray == 0 ) {
1207                         DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
1208                 }
1209                 return varray;
1210         }
1211         else {
1212                 return buffer->pointer;
1213         }
1214 }
1215
1216 void *GPU_buffer_lock_stream( GPUBuffer *buffer )
1217 {
1218         float *varray;
1219
1220         DEBUG_VBO("GPU_buffer_lock_stream\n");
1221         if( buffer == 0 ) {
1222                 DEBUG_VBO( "Failed to lock NULL buffer\n" );
1223                 return 0;
1224         }
1225
1226         if( useVBOs ) {
1227                 glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
1228                 glBufferDataARB( GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB );    /* discard previous data, avoid stalling gpu */
1229                 varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
1230                 if( varray == 0 ) {
1231                         DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
1232                 }
1233                 return varray;
1234         }
1235         else {
1236                 return buffer->pointer;
1237         }
1238 }
1239
1240 void GPU_buffer_unlock( GPUBuffer *buffer )
1241 {
1242         DEBUG_VBO( "GPU_buffer_unlock\n" ); 
1243         if( useVBOs ) {
1244                 if( buffer != 0 ) {
1245                         if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == 0 ) {
1246                                 DEBUG_VBO( "Failed to copy new data\n" ); 
1247                         }
1248                 }
1249                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1250         }
1251 }
1252
1253 void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
1254 {
1255         if( useVBOs ) {
1256                 glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
1257         }
1258         else {
1259                 glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
1260         }
1261 }