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