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