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