Fix for multires VBO drawing in sculpt mode.
[blender.git] / source / blender / gpu / intern / gpu_buffers.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_buffers.c
29  *  \ingroup gpu
30  */
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_bitmap.h"
42 #include "BLI_math.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_ghash.h"
45 #include "BLI_threads.h"
46
47 #include "DNA_meshdata_types.h"
48
49 #include "BKE_DerivedMesh.h"
50 #include "BKE_paint.h"
51 #include "BKE_subsurf.h"
52
53 #include "DNA_userdef_types.h"
54
55 #include "GPU_buffers.h"
56
57 typedef enum {
58         GPU_BUFFER_VERTEX_STATE = 1,
59         GPU_BUFFER_NORMAL_STATE = 2,
60         GPU_BUFFER_TEXCOORD_STATE = 4,
61         GPU_BUFFER_COLOR_STATE = 8,
62         GPU_BUFFER_ELEMENT_STATE = 16,
63 } GPUBufferState;
64
65 #define MAX_GPU_ATTRIB_DATA 32
66
67 /* material number is an 16-bit short and the range of short is from -16383 to 16383 (assume material number is non-negative) */
68 #define MAX_MATERIALS 16384
69
70 /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
71 static int useVBOs = -1;
72 static GPUBufferState GLStates = 0;
73 static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
74
75 /* stores recently-deleted buffers so that new buffers won't have to
76    be recreated as often
77
78    only one instance of this pool is created, stored in
79    gpu_buffer_pool
80
81    note that the number of buffers in the pool is usually limited to
82    MAX_FREE_GPU_BUFFERS, but this limit may be exceeded temporarily
83    when a GPUBuffer is released outside the main thread; due to OpenGL
84    restrictions it cannot be immediately released
85  */
86 typedef struct GPUBufferPool {
87         /* number of allocated buffers stored */
88         int totbuf;
89         /* actual allocated length of the array */
90         int maxsize;
91         GPUBuffer **buffers;
92 } GPUBufferPool;
93 #define MAX_FREE_GPU_BUFFERS 8
94
95 /* create a new GPUBufferPool */
96 static GPUBufferPool *gpu_buffer_pool_new(void)
97 {
98         GPUBufferPool *pool;
99
100         /* enable VBOs if supported */
101         if(useVBOs == -1)
102                 useVBOs = (GLEW_ARB_vertex_buffer_object ? 1 : 0);
103
104         pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer");
105
106         pool->maxsize = MAX_FREE_GPU_BUFFERS;
107         pool->buffers = MEM_callocN(sizeof(GPUBuffer*)*pool->maxsize,
108                                     "GPUBuffer.buffers");
109
110         return pool;
111 }
112
113 /* remove a GPUBuffer from the pool (does not free the GPUBuffer) */
114 static void gpu_buffer_pool_remove_index(GPUBufferPool *pool, int index)
115 {
116         int i;
117
118         if(!pool || index < 0 || index >= pool->totbuf)
119                 return;
120
121         /* shift entries down, overwriting the buffer at `index' */
122         for(i = index; i < pool->totbuf - 1; i++)
123                 pool->buffers[i] = pool->buffers[i+1];
124
125         /* clear the last entry */
126         if(pool->totbuf > 0)
127                 pool->buffers[pool->totbuf - 1] = NULL;
128
129         pool->totbuf--;
130 }
131
132 /* delete the last entry in the pool */
133 static void gpu_buffer_pool_delete_last(GPUBufferPool *pool)
134 {
135         GPUBuffer *last;
136
137         if(pool->totbuf <= 0)
138                 return;
139
140         /* get the last entry */
141         if(!(last = pool->buffers[pool->totbuf - 1]))
142                 return;
143
144         /* delete the buffer's data */
145         if(useVBOs)
146                 glDeleteBuffersARB(1, &last->id);
147         else
148                 MEM_freeN(last->pointer);
149
150         /* delete the buffer and remove from pool */
151         MEM_freeN(last);
152         pool->totbuf--;
153         pool->buffers[pool->totbuf] = NULL;
154 }
155
156 /* free a GPUBufferPool; also frees the data in the pool's
157    GPUBuffers */
158 static void gpu_buffer_pool_free(GPUBufferPool *pool)
159 {
160         if(!pool)
161                 return;
162         
163         while(pool->totbuf)
164                 gpu_buffer_pool_delete_last(pool);
165
166         MEM_freeN(pool->buffers);
167         MEM_freeN(pool);
168 }
169
170 static GPUBufferPool *gpu_buffer_pool = NULL;
171 static GPUBufferPool *gpu_get_global_buffer_pool(void)
172 {
173         /* initialize the pool */
174         if(!gpu_buffer_pool)
175                 gpu_buffer_pool = gpu_buffer_pool_new();
176
177         return gpu_buffer_pool;
178 }
179
180 void GPU_global_buffer_pool_free(void)
181 {
182         gpu_buffer_pool_free(gpu_buffer_pool);
183         gpu_buffer_pool = NULL;
184 }
185
186 /* get a GPUBuffer of at least `size' bytes; uses one from the buffer
187    pool if possible, otherwise creates a new one */
188 GPUBuffer *GPU_buffer_alloc(int size)
189 {
190         GPUBufferPool *pool;
191         GPUBuffer *buf;
192         int i, bufsize, bestfit = -1;
193
194         pool = gpu_get_global_buffer_pool();
195
196         /* not sure if this buffer pool code has been profiled much,
197            seems to me that the graphics driver and system memory
198            management might do this stuff anyway. --nicholas
199         */
200
201         /* check the global buffer pool for a recently-deleted buffer
202            that is at least as big as the request, but not more than
203            twice as big */
204         for(i = 0; i < pool->totbuf; i++) {
205                 bufsize = pool->buffers[i]->size;
206
207                 /* check for an exact size match */
208                 if(bufsize == size) {
209                         bestfit = i;
210                         break;
211                 }
212                 /* smaller buffers won't fit data and buffers at least
213                    twice as big are a waste of memory */
214                 else if(bufsize > size && size > (bufsize / 2)) {
215                         /* is it closer to the required size than the
216                            last appropriate buffer found. try to save
217                            memory */
218                         if(bestfit == -1 || pool->buffers[bestfit]->size > bufsize) {
219                                 bestfit = i;
220                         }
221                 }
222         }
223
224         /* if an acceptable buffer was found in the pool, remove it
225            from the pool and return it */
226         if(bestfit != -1) {
227                 buf = pool->buffers[bestfit];
228                 gpu_buffer_pool_remove_index(pool, bestfit);
229                 return buf;
230         }
231
232         /* no acceptable buffer found in the pool, create a new one */
233         buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer");
234         buf->size = size;
235
236         if(useVBOs == 1) {
237                 /* create a new VBO and initialize it to the requested
238                    size */
239                 glGenBuffersARB(1, &buf->id);
240                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buf->id);
241                 glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, GL_STATIC_DRAW_ARB);
242                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
243         }
244         else {
245                 buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
246                 
247                 /* purpose of this seems to be dealing with
248                    out-of-memory errors? looks a bit iffy to me
249                    though, at least on Linux I expect malloc() would
250                    just overcommit. --nicholas */
251                 while(!buf->pointer && pool->totbuf > 0) {
252                         gpu_buffer_pool_delete_last(pool);
253                         buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
254                 }
255                 if(!buf->pointer)
256                         return NULL;
257         }
258
259         return buf;
260 }
261
262 /* release a GPUBuffer; does not free the actual buffer or its data,
263    but rather moves it to the pool of recently-freed buffers for
264    possible re-use*/
265 void GPU_buffer_free(GPUBuffer *buffer)
266 {
267         GPUBufferPool *pool;
268         int i;
269
270         if(!buffer)
271                 return;
272
273         pool = gpu_get_global_buffer_pool();
274
275         /* free the last used buffer in the queue if no more space, but only
276            if we are in the main thread. for e.g. rendering or baking it can
277            happen that we are in other thread and can't call OpenGL, in that
278            case cleanup will be done GPU_buffer_pool_free_unused */
279         if(BLI_thread_is_main()) {
280                 /* in main thread, safe to decrease size of pool back
281                    down to MAX_FREE_GPU_BUFFERS */
282                 while(pool->totbuf >= MAX_FREE_GPU_BUFFERS)
283                         gpu_buffer_pool_delete_last(pool);
284         }
285         else {
286                 /* outside of main thread, can't safely delete the
287                    buffer, so increase pool size */
288                 if(pool->maxsize == pool->totbuf) {
289                         pool->maxsize += MAX_FREE_GPU_BUFFERS;
290                         pool->buffers = MEM_reallocN(pool->buffers,
291                                                      sizeof(GPUBuffer*) * pool->maxsize);
292                 }
293         }
294
295         /* shift pool entries up by one */
296         for(i = pool->totbuf; i > 0; i--)
297                 pool->buffers[i] = pool->buffers[i-1];
298
299         /* insert the buffer into the beginning of the pool */
300         pool->buffers[0] = buffer;
301         pool->totbuf++;
302 }
303
304 typedef struct GPUVertPointLink {
305         struct GPUVertPointLink *next;
306         /* -1 means uninitialized */
307         int point_index;
308 } GPUVertPointLink;
309
310 /* add a new point to the list of points related to a particular
311    vertex */
312 static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
313 {
314         GPUVertPointLink *lnk;
315
316         lnk = &gdo->vert_points[vert_index];
317
318         /* if first link is in use, add a new link at the end */
319         if(lnk->point_index != -1) {
320                 /* get last link */
321                 for(; lnk->next; lnk = lnk->next);
322
323                 /* add a new link from the pool */
324                 lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
325                 gdo->vert_points_usage++;
326         }
327
328         lnk->point_index = point_index;
329 }
330
331 /* update the vert_points and triangle_to_mface fields with a new
332    triangle */
333 static void gpu_drawobject_add_triangle(GPUDrawObject *gdo,
334                                         int base_point_index,
335                                         int face_index,
336                                         int v1, int v2, int v3)
337 {
338         int i, v[3] = {v1, v2, v3};
339         for(i = 0; i < 3; i++)
340                 gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i);
341         gdo->triangle_to_mface[base_point_index / 3] = face_index;
342 }
343
344 /* for each vertex, build a list of points related to it; these lists
345    are stored in an array sized to the number of vertices */
346 static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface)
347 {
348         GPUBufferMaterial *mat;
349         int i, mat_orig_to_new[MAX_MATERIALS];
350
351         /* allocate the array and space for links */
352         gdo->vert_points = MEM_callocN(sizeof(GPUVertPointLink) * gdo->totvert,
353                                        "GPUDrawObject.vert_points");
354         gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point,
355                                               "GPUDrawObject.vert_points_mem");
356         gdo->vert_points_usage = 0;
357
358         /* build a map from the original material indices to the new
359            GPUBufferMaterial indices */
360         for(i = 0; i < gdo->totmaterial; i++)
361                 mat_orig_to_new[gdo->materials[i].mat_nr] = i;
362
363         /* -1 indicates the link is not yet used */
364         for(i = 0; i < gdo->totvert; i++)
365                 gdo->vert_points[i].point_index = -1;
366
367         for(i = 0; i < totface; i++, f++) {
368                 mat = &gdo->materials[mat_orig_to_new[f->mat_nr]];
369
370                 /* add triangle */
371                 gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
372                                             i, f->v1, f->v2, f->v3);
373                 mat->totpoint += 3;
374
375                 /* add second triangle for quads */
376                 if(f->v4) {
377                         gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
378                                                     i, f->v3, f->v4, f->v1);
379                         mat->totpoint += 3;
380                 }
381         }
382
383         /* map any unused vertices to loose points */
384         for(i = 0; i < gdo->totvert; i++) {
385                 if(gdo->vert_points[i].point_index == -1) {
386                         gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point;
387                         gdo->tot_loose_point++;
388                 }
389         }
390 }
391
392 /* see GPUDrawObject's structure definition for a description of the
393    data being initialized here */
394 GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
395 {
396         GPUDrawObject *gdo;
397         MFace *mface;
398         int points_per_mat[MAX_MATERIALS];
399         int i, curmat, curpoint, totface;
400
401         mface = dm->getTessFaceArray(dm);
402         totface= dm->getNumTessFaces(dm);
403
404         /* get the number of points used by each material, treating
405            each quad as two triangles */
406         memset(points_per_mat, 0, sizeof(int)*MAX_MATERIALS);
407         for(i = 0; i < totface; i++)
408                 points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3;
409
410         /* create the GPUDrawObject */
411         gdo = MEM_callocN(sizeof(GPUDrawObject),"GPUDrawObject");
412         gdo->totvert = dm->getNumVerts(dm);
413         gdo->totedge = dm->getNumEdges(dm);
414
415         /* count the number of materials used by this DerivedMesh */
416         for(i = 0; i < MAX_MATERIALS; i++) {
417                 if(points_per_mat[i] > 0)
418                         gdo->totmaterial++;
419         }
420
421         /* allocate an array of materials used by this DerivedMesh */
422         gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
423                                      "GPUDrawObject.materials");
424
425         /* initialize the materials array */
426         for(i = 0, curmat = 0, curpoint = 0; i < MAX_MATERIALS; i++) {
427                 if(points_per_mat[i] > 0) {
428                         gdo->materials[curmat].start = curpoint;
429                         gdo->materials[curmat].totpoint = 0;
430                         gdo->materials[curmat].mat_nr = i;
431
432                         curpoint += points_per_mat[i];
433                         curmat++;
434                 }
435         }
436
437         /* store total number of points used for triangles */
438         gdo->tot_triangle_point = curpoint;
439
440         gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3),
441                                      "GPUDrawObject.triangle_to_mface");
442
443         gpu_drawobject_init_vert_points(gdo, mface, totface);
444
445         return gdo;
446 }
447
448 void GPU_drawobject_free(DerivedMesh *dm)
449 {
450         GPUDrawObject *gdo;
451
452         if(!dm || !(gdo = dm->drawObject))
453                 return;
454
455         MEM_freeN(gdo->materials);
456         MEM_freeN(gdo->triangle_to_mface);
457         MEM_freeN(gdo->vert_points);
458         MEM_freeN(gdo->vert_points_mem);
459         GPU_buffer_free(gdo->points);
460         GPU_buffer_free(gdo->normals);
461         GPU_buffer_free(gdo->uv);
462         GPU_buffer_free(gdo->colors);
463         GPU_buffer_free(gdo->edges);
464         GPU_buffer_free(gdo->uvedges);
465
466         MEM_freeN(gdo);
467         dm->drawObject = NULL;
468 }
469
470 typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
471                                   int *mat_orig_to_new, void *user_data);
472
473 static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
474                                    int vector_size, int size, GLenum target,
475                                    void *user, GPUBufferCopyFunc copy_f)
476 {
477         GPUBufferPool *pool;
478         GPUBuffer *buffer;
479         float *varray;
480         int mat_orig_to_new[MAX_MATERIALS];
481         int *cur_index_per_mat;
482         int i;
483         int success;
484         GLboolean uploaded;
485
486         pool = gpu_get_global_buffer_pool();
487
488         /* alloc a GPUBuffer; fall back to legacy mode on failure */
489         if(!(buffer = GPU_buffer_alloc(size)))
490                 dm->drawObject->legacy = 1;
491
492         /* nothing to do for legacy mode */
493         if(dm->drawObject->legacy)
494                 return NULL;
495
496         cur_index_per_mat = MEM_mallocN(sizeof(int)*object->totmaterial,
497                                         "GPU_buffer_setup.cur_index_per_mat");
498         for(i = 0; i < object->totmaterial; i++) {
499                 /* for each material, the current index to copy data to */
500                 cur_index_per_mat[i] = object->materials[i].start * vector_size;
501
502                 /* map from original material index to new
503                    GPUBufferMaterial index */
504                 mat_orig_to_new[object->materials[i].mat_nr] = i;
505         }
506
507         if(useVBOs) {
508                 success = 0;
509
510                 while(!success) {
511                         /* bind the buffer and discard previous data,
512                            avoids stalling gpu */
513                         glBindBufferARB(target, buffer->id);
514                         glBufferDataARB(target, buffer->size, NULL, GL_STATIC_DRAW_ARB);
515
516                         /* attempt to map the buffer */
517                         if(!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) {
518                                 /* failed to map the buffer; delete it */
519                                 GPU_buffer_free(buffer);
520                                 gpu_buffer_pool_delete_last(pool);
521                                 buffer= NULL;
522
523                                 /* try freeing an entry from the pool
524                                    and reallocating the buffer */
525                                 if(pool->totbuf > 0) {
526                                         gpu_buffer_pool_delete_last(pool);
527                                         buffer = GPU_buffer_alloc(size);
528                                 }
529
530                                 /* allocation still failed; fall back
531                                    to legacy mode */
532                                 if(!buffer) {
533                                         dm->drawObject->legacy = 1;
534                                         success = 1;
535                                 }
536                         }
537                         else {
538                                 success = 1;
539                         }
540                 }
541
542                 /* check legacy fallback didn't happen */
543                 if(dm->drawObject->legacy == 0) {
544                         uploaded = GL_FALSE;
545                         /* attempt to upload the data to the VBO */
546                         while(uploaded == GL_FALSE) {
547                                 (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
548                                 /* glUnmapBuffer returns GL_FALSE if
549                                  * the data store is corrupted; retry
550                                  * in that case */
551                                 uploaded = glUnmapBufferARB(target);
552                         }
553                 }
554                 glBindBufferARB(target, 0);
555         }
556         else {
557                 /* VBO not supported, use vertex array fallback */
558                 if(buffer->pointer) {
559                         varray = buffer->pointer;
560                         (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
561                 }
562                 else {
563                         dm->drawObject->legacy = 1;
564                 }
565         }
566
567         MEM_freeN(cur_index_per_mat);
568
569         return buffer;
570 }
571
572 static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
573 {
574         MVert *mvert;
575         MFace *f;
576         int i, j, start, totface;
577
578         mvert = dm->getVertArray(dm);
579         f = dm->getTessFaceArray(dm);
580
581         totface= dm->getNumTessFaces(dm);
582         for(i = 0; i < totface; i++, f++) {
583                 start = index[mat_orig_to_new[f->mat_nr]];
584
585                 /* v1 v2 v3 */
586                 copy_v3_v3(&varray[start], mvert[f->v1].co);
587                 copy_v3_v3(&varray[start+3], mvert[f->v2].co);
588                 copy_v3_v3(&varray[start+6], mvert[f->v3].co);
589                 index[mat_orig_to_new[f->mat_nr]] += 9;
590
591                 if(f->v4) {
592                         /* v3 v4 v1 */
593                         copy_v3_v3(&varray[start+9], mvert[f->v3].co);
594                         copy_v3_v3(&varray[start+12], mvert[f->v4].co);
595                         copy_v3_v3(&varray[start+15], mvert[f->v1].co);
596                         index[mat_orig_to_new[f->mat_nr]] += 9;
597                 }
598         }
599
600         /* copy loose points */
601         j = dm->drawObject->tot_triangle_point*3;
602         for(i = 0; i < dm->drawObject->totvert; i++) {
603                 if(dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) {
604                         copy_v3_v3(&varray[j],mvert[i].co);
605                         j+=3;
606                 }
607         }
608 }
609
610 static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
611 {
612         int i, totface;
613         int start;
614         float f_no[3];
615
616         float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
617         MVert *mvert = dm->getVertArray(dm);
618         MFace *f = dm->getTessFaceArray(dm);
619
620         totface= dm->getNumTessFaces(dm);
621         for(i = 0; i < totface; i++, f++) {
622                 const int smoothnormal = (f->flag & ME_SMOOTH);
623
624                 start = index[mat_orig_to_new[f->mat_nr]];
625                 index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9;
626
627                 if(smoothnormal) {
628                         /* copy vertex normal */
629                         normal_short_to_float_v3(&varray[start], mvert[f->v1].no);
630                         normal_short_to_float_v3(&varray[start+3], mvert[f->v2].no);
631                         normal_short_to_float_v3(&varray[start+6], mvert[f->v3].no);
632
633                         if(f->v4) {
634                                 normal_short_to_float_v3(&varray[start+9], mvert[f->v3].no);
635                                 normal_short_to_float_v3(&varray[start+12], mvert[f->v4].no);
636                                 normal_short_to_float_v3(&varray[start+15], mvert[f->v1].no);
637                         }
638                 }
639                 else if(nors) {
640                         /* copy cached face normal */
641                         copy_v3_v3(&varray[start], &nors[i*3]);
642                         copy_v3_v3(&varray[start+3], &nors[i*3]);
643                         copy_v3_v3(&varray[start+6], &nors[i*3]);
644
645                         if(f->v4) {
646                                 copy_v3_v3(&varray[start+9], &nors[i*3]);
647                                 copy_v3_v3(&varray[start+12], &nors[i*3]);
648                                 copy_v3_v3(&varray[start+15], &nors[i*3]);
649                         }
650                 }
651                 else {
652                         /* calculate face normal */
653                         if(f->v4)
654                                 normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co);
655                         else
656                                 normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co);
657
658                         copy_v3_v3(&varray[start], f_no);
659                         copy_v3_v3(&varray[start+3], f_no);
660                         copy_v3_v3(&varray[start+6], f_no);
661
662                         if(f->v4) {
663                                 copy_v3_v3(&varray[start+9], f_no);
664                                 copy_v3_v3(&varray[start+12], f_no);
665                                 copy_v3_v3(&varray[start+15], f_no);
666                         }
667                 }
668         }
669 }
670
671 static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
672 {
673         int start;
674         int i, totface;
675
676         MTFace *mtface;
677         MFace *f;
678
679         if(!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE)))
680                 return;
681         f = dm->getTessFaceArray(dm);
682                 
683         totface = dm->getNumTessFaces(dm);
684         for(i = 0; i < totface; i++, f++) {
685                 start = index[mat_orig_to_new[f->mat_nr]];
686
687                 /* v1 v2 v3 */
688                 copy_v2_v2(&varray[start],mtface[i].uv[0]);
689                 copy_v2_v2(&varray[start+2],mtface[i].uv[1]);
690                 copy_v2_v2(&varray[start+4],mtface[i].uv[2]);
691                 index[mat_orig_to_new[f->mat_nr]] += 6;
692
693                 if(f->v4) {
694                         /* v3 v4 v1 */
695                         copy_v2_v2(&varray[start+6],mtface[i].uv[2]);
696                         copy_v2_v2(&varray[start+8],mtface[i].uv[3]);
697                         copy_v2_v2(&varray[start+10],mtface[i].uv[0]);
698                         index[mat_orig_to_new[f->mat_nr]] += 6;
699                 }
700         }
701 }
702
703
704 static void GPU_buffer_copy_color3(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
705 {
706         int i, totface;
707         char *varray = (char *)varray_;
708         char *mcol = (char *)user;
709         MFace *f = dm->getTessFaceArray(dm);
710
711         totface= dm->getNumTessFaces(dm);
712         for(i=0; i < totface; i++, f++) {
713                 int start = index[mat_orig_to_new[f->mat_nr]];
714
715                 /* v1 v2 v3 */
716                 copy_v3_v3_char(&varray[start], &mcol[i*12]);
717                 copy_v3_v3_char(&varray[start+3], &mcol[i*12+3]);
718                 copy_v3_v3_char(&varray[start+6], &mcol[i*12+6]);
719                 index[mat_orig_to_new[f->mat_nr]] += 9;
720
721                 if(f->v4) {
722                         /* v3 v4 v1 */
723                         copy_v3_v3_char(&varray[start+9], &mcol[i*12+6]);
724                         copy_v3_v3_char(&varray[start+12], &mcol[i*12+9]);
725                         copy_v3_v3_char(&varray[start+15], &mcol[i*12]);
726                         index[mat_orig_to_new[f->mat_nr]] += 9;
727                 }
728         }
729 }
730
731 static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
732 {
733         v[0] = col[3];
734         v[1] = col[2];
735         v[2] = col[1];
736 }
737
738 /* treat varray_ as an array of MCol, four MCol's per face */
739 static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
740 {
741         int i, totface;
742         unsigned char *varray = (unsigned char *)varray_;
743         unsigned char *mcol = (unsigned char *)user;
744         MFace *f = dm->getTessFaceArray(dm);
745
746         totface= dm->getNumTessFaces(dm);
747         for(i=0; i < totface; i++, f++) {
748                 int start = index[mat_orig_to_new[f->mat_nr]];
749
750                 /* v1 v2 v3 */
751                 copy_mcol_uc3(&varray[start], &mcol[i*16]);
752                 copy_mcol_uc3(&varray[start+3], &mcol[i*16+4]);
753                 copy_mcol_uc3(&varray[start+6], &mcol[i*16+8]);
754                 index[mat_orig_to_new[f->mat_nr]] += 9;
755
756                 if(f->v4) {
757                         /* v3 v4 v1 */
758                         copy_mcol_uc3(&varray[start+9], &mcol[i*16+8]);
759                         copy_mcol_uc3(&varray[start+12], &mcol[i*16+12]);
760                         copy_mcol_uc3(&varray[start+15], &mcol[i*16]);
761                         index[mat_orig_to_new[f->mat_nr]] += 9;
762                 }
763         }
764 }
765
766 static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
767 {
768         MEdge *medge;
769         unsigned int *varray = (unsigned int *)varray_;
770         int i, totedge;
771  
772         medge = dm->getEdgeArray(dm);
773         totedge = dm->getNumEdges(dm);
774
775         for(i = 0; i < totedge; i++, medge++) {
776                 varray[i*2] = dm->drawObject->vert_points[medge->v1].point_index;
777                 varray[i*2+1] = dm->drawObject->vert_points[medge->v2].point_index;
778         }
779 }
780
781 static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
782 {
783         MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
784         int i, j=0;
785
786         if(!tf)
787                 return;
788
789         for(i = 0; i < dm->numTessFaceData; i++, tf++) {
790                 MFace mf;
791                 dm->getTessFace(dm,i,&mf);
792
793                 copy_v2_v2(&varray[j],tf->uv[0]);
794                 copy_v2_v2(&varray[j+2],tf->uv[1]);
795
796                 copy_v2_v2(&varray[j+4],tf->uv[1]);
797                 copy_v2_v2(&varray[j+6],tf->uv[2]);
798
799                 if(!mf.v4) {
800                         copy_v2_v2(&varray[j+8],tf->uv[2]);
801                         copy_v2_v2(&varray[j+10],tf->uv[0]);
802                         j+=12;
803                 } else {
804                         copy_v2_v2(&varray[j+8],tf->uv[2]);
805                         copy_v2_v2(&varray[j+10],tf->uv[3]);
806
807                         copy_v2_v2(&varray[j+12],tf->uv[3]);
808                         copy_v2_v2(&varray[j+14],tf->uv[0]);
809                         j+=16;
810                 }
811         }
812 }
813
814 /* get the DerivedMesh's MCols; choose (in decreasing order of
815    preference) from CD_ID_MCOL, CD_WEIGHT_MCOL, or CD_MCOL */
816 static MCol *gpu_buffer_color_type(DerivedMesh *dm)
817 {
818         MCol *c;
819         int type;
820
821         type = CD_ID_MCOL;
822         c = DM_get_tessface_data_layer(dm, type);
823         if(!c) {
824                 type = CD_WEIGHT_MCOL;
825                 c = DM_get_tessface_data_layer(dm, type);
826                 if(!c) {
827                         type = CD_MCOL;
828                         c = DM_get_tessface_data_layer(dm, type);
829                 }
830         }
831
832         dm->drawObject->colType = type;
833         return c;
834 }
835
836 typedef enum {
837         GPU_BUFFER_VERTEX = 0,
838         GPU_BUFFER_NORMAL,
839         GPU_BUFFER_COLOR,
840         GPU_BUFFER_UV,
841         GPU_BUFFER_EDGE,
842         GPU_BUFFER_UVEDGE,
843 } GPUBufferType;
844
845 typedef struct {
846         GPUBufferCopyFunc copy;
847         GLenum gl_buffer_type;
848         int vector_size;
849 } GPUBufferTypeSettings;
850
851 const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
852         {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3},
853         {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3},
854         {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3},
855         {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2},
856         {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
857         {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
858 };
859
860 /* get the GPUDrawObject buffer associated with a type */
861 static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type)
862 {
863         switch(type) {
864         case GPU_BUFFER_VERTEX:
865                 return &gdo->points;
866         case GPU_BUFFER_NORMAL:
867                 return &gdo->normals;
868         case GPU_BUFFER_COLOR:
869                 return &gdo->colors;
870         case GPU_BUFFER_UV:
871                 return &gdo->uv;
872         case GPU_BUFFER_EDGE:
873                 return &gdo->edges;
874         case GPU_BUFFER_UVEDGE:
875                 return &gdo->uvedges;
876         default:
877                 return NULL;
878         }
879 }
880
881 /* get the amount of space to allocate for a buffer of a particular type */
882 static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
883 {
884         switch(type) {
885         case GPU_BUFFER_VERTEX:
886                 return sizeof(float)*3 * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point);
887         case GPU_BUFFER_NORMAL:
888                 return sizeof(float)*3*dm->drawObject->tot_triangle_point;
889         case GPU_BUFFER_COLOR:
890                 return sizeof(char)*3*dm->drawObject->tot_triangle_point;
891         case GPU_BUFFER_UV:
892                 return sizeof(float)*2*dm->drawObject->tot_triangle_point;
893         case GPU_BUFFER_EDGE:
894                 return sizeof(int)*2*dm->drawObject->totedge;
895         case GPU_BUFFER_UVEDGE:
896                 /* each face gets 3 points, 3 edges per triangle, and
897                    each edge has its own, non-shared coords, so each
898                    tri corner needs minimum of 4 floats, quads used
899                    less so here we can over allocate and assume all
900                    tris. */
901                 return sizeof(float) * dm->drawObject->tot_triangle_point;
902         default:
903                 return -1;
904         }
905 }
906
907 /* call gpu_buffer_setup with settings for a particular type of buffer */
908 static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
909 {
910         const GPUBufferTypeSettings *ts;
911         void *user_data = NULL;
912         GPUBuffer *buf;
913
914         ts = &gpu_buffer_type_settings[type];
915
916         /* special handling for MCol and UV buffers */
917         if(type == GPU_BUFFER_COLOR) {
918                 if(!(user_data = gpu_buffer_color_type(dm)))
919                         return NULL;
920         }
921         else if(type == GPU_BUFFER_UV) {
922                 if(!DM_get_tessface_data_layer(dm, CD_MTFACE))
923                         return NULL;
924         }
925
926         buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size,
927                                gpu_buffer_size_from_type(dm, type),
928                                ts->gl_buffer_type, user_data, ts->copy);
929
930         return buf;
931 }
932
933 /* get the buffer of `type', initializing the GPUDrawObject and
934    buffer if needed */
935 static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
936 {
937         GPUBuffer **buf;
938         
939         if(!dm->drawObject)
940                 dm->drawObject = GPU_drawobject_new(dm);
941
942         buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
943         if(!(*buf))
944                 *buf = gpu_buffer_setup_type(dm, type);
945
946         return *buf;
947 }
948
949 void GPU_vertex_setup(DerivedMesh *dm)
950 {
951         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
952                 return;
953
954         glEnableClientState(GL_VERTEX_ARRAY);
955         if(useVBOs) {
956                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
957                 glVertexPointer(3, GL_FLOAT, 0, 0);
958         }
959         else {
960                 glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
961         }
962         
963         GLStates |= GPU_BUFFER_VERTEX_STATE;
964 }
965
966 void GPU_normal_setup(DerivedMesh *dm)
967 {
968         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL))
969                 return;
970
971         glEnableClientState(GL_NORMAL_ARRAY);
972         if(useVBOs) {
973                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id);
974                 glNormalPointer(GL_FLOAT, 0, 0);
975         }
976         else {
977                 glNormalPointer(GL_FLOAT, 0, dm->drawObject->normals->pointer);
978         }
979
980         GLStates |= GPU_BUFFER_NORMAL_STATE;
981 }
982
983 void GPU_uv_setup(DerivedMesh *dm)
984 {
985         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_UV))
986                 return;
987
988         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
989         if(useVBOs) {
990                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id);
991                 glTexCoordPointer(2, GL_FLOAT, 0, 0);
992         }
993         else {
994                 glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer);
995         }
996
997         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
998 }
999
1000 void GPU_color_setup(DerivedMesh *dm)
1001 {
1002         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR))
1003                 return;
1004
1005         glEnableClientState(GL_COLOR_ARRAY);
1006         if(useVBOs) {
1007                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id);
1008                 glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
1009         }
1010         else {
1011                 glColorPointer(3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer);
1012         }
1013
1014         GLStates |= GPU_BUFFER_COLOR_STATE;
1015 }
1016
1017 void GPU_edge_setup(DerivedMesh *dm)
1018 {
1019         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE))
1020                 return;
1021
1022         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
1023                 return;
1024
1025         glEnableClientState(GL_VERTEX_ARRAY);
1026         if(useVBOs) {
1027                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
1028                 glVertexPointer(3, GL_FLOAT, 0, 0);
1029         }
1030         else {
1031                 glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
1032         }
1033         
1034         GLStates |= GPU_BUFFER_VERTEX_STATE;
1035
1036         if(useVBOs)
1037                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id);
1038
1039         GLStates |= GPU_BUFFER_ELEMENT_STATE;
1040 }
1041
1042 void GPU_uvedge_setup(DerivedMesh *dm)
1043 {
1044         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE))
1045                 return;
1046
1047         glEnableClientState(GL_VERTEX_ARRAY);
1048         if(useVBOs) {
1049                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id);
1050                 glVertexPointer(2, GL_FLOAT, 0, 0);
1051         }
1052         else {
1053                 glVertexPointer(2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer);
1054         }
1055         
1056         GLStates |= GPU_BUFFER_VERTEX_STATE;
1057 }
1058
1059 static int GPU_typesize(int type)
1060 {
1061         switch(type) {
1062         case GL_FLOAT:
1063                 return sizeof(float);
1064         case GL_INT:
1065                 return sizeof(int);
1066         case GL_UNSIGNED_INT:
1067                 return sizeof(unsigned int);
1068         case GL_BYTE:
1069                 return sizeof(char);
1070         case GL_UNSIGNED_BYTE:
1071                 return sizeof(unsigned char);
1072         default:
1073                 return 0;
1074         }
1075 }
1076
1077 int GPU_attrib_element_size(GPUAttrib data[], int numdata)
1078 {
1079         int i, elementsize = 0;
1080
1081         for(i = 0; i < numdata; i++) {
1082                 int typesize = GPU_typesize(data[i].type);
1083                 if(typesize != 0)
1084                         elementsize += typesize*data[i].size;
1085         }
1086         return elementsize;
1087 }
1088
1089 void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata)
1090 {
1091         int i;
1092         int elementsize;
1093         intptr_t offset = 0;
1094
1095         for(i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
1096                 if(attribData[i].index != -1) {
1097                         glDisableVertexAttribArrayARB(attribData[i].index);
1098                 }
1099                 else
1100                         break;
1101         }
1102         elementsize = GPU_attrib_element_size(data, numdata);
1103
1104         if(useVBOs) {
1105                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
1106                 for(i = 0; i < numdata; i++) {
1107                         glEnableVertexAttribArrayARB(data[i].index);
1108                         glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
1109                                                  GL_FALSE, elementsize, (void *)offset);
1110                         offset += data[i].size*GPU_typesize(data[i].type);
1111
1112                         attribData[i].index = data[i].index;
1113                         attribData[i].size = data[i].size;
1114                         attribData[i].type = data[i].type;
1115                 }
1116                 attribData[numdata].index = -1;
1117         }
1118         else {
1119                 for(i = 0; i < numdata; i++) {
1120                         glEnableVertexAttribArrayARB(data[i].index);
1121                         glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
1122                                                  GL_FALSE, elementsize, (char *)buffer->pointer + offset);
1123                         offset += data[i].size*GPU_typesize(data[i].type);
1124                 }
1125         }
1126 }
1127
1128
1129 void GPU_buffer_unbind(void)
1130 {
1131         int i;
1132
1133         if(GLStates & GPU_BUFFER_VERTEX_STATE)
1134                 glDisableClientState(GL_VERTEX_ARRAY);
1135         if(GLStates & GPU_BUFFER_NORMAL_STATE)
1136                 glDisableClientState(GL_NORMAL_ARRAY);
1137         if(GLStates & GPU_BUFFER_TEXCOORD_STATE)
1138                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1139         if(GLStates & GPU_BUFFER_COLOR_STATE)
1140                 glDisableClientState(GL_COLOR_ARRAY);
1141         if(GLStates & GPU_BUFFER_ELEMENT_STATE) {
1142                 if(useVBOs) {
1143                         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1144                 }
1145         }
1146         GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE |
1147                       GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE |
1148                       GPU_BUFFER_ELEMENT_STATE);
1149
1150         for(i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
1151                 if(attribData[i].index != -1) {
1152                         glDisableVertexAttribArrayARB(attribData[i].index);
1153                 }
1154                 else
1155                         break;
1156         }
1157
1158         if(useVBOs)
1159                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1160 }
1161
1162 /* confusion: code in cdderivedmesh calls both GPU_color_setup and
1163    GPU_color3_upload; both of these set the `colors' buffer, so seems
1164    like it will just needlessly overwrite? --nicholas */
1165 void GPU_color3_upload(DerivedMesh *dm, unsigned char *data)
1166 {
1167         if(dm->drawObject == 0)
1168                 dm->drawObject = GPU_drawobject_new(dm);
1169         GPU_buffer_free(dm->drawObject->colors);
1170
1171         dm->drawObject->colors = gpu_buffer_setup(dm, dm->drawObject, 3,
1172                                                   sizeof(char)*3*dm->drawObject->tot_triangle_point,
1173                                                   GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3);
1174 }
1175
1176 void GPU_color_switch(int mode)
1177 {
1178         if(mode) {
1179                 if(!(GLStates & GPU_BUFFER_COLOR_STATE))
1180                         glEnableClientState(GL_COLOR_ARRAY);
1181                 GLStates |= GPU_BUFFER_COLOR_STATE;
1182         }
1183         else {
1184                 if(GLStates & GPU_BUFFER_COLOR_STATE)
1185                         glDisableClientState(GL_COLOR_ARRAY);
1186                 GLStates &= (!GPU_BUFFER_COLOR_STATE);
1187         }
1188 }
1189
1190 /* return 1 if drawing should be done using old immediate-mode
1191    code, 0 otherwise */
1192 int GPU_buffer_legacy(DerivedMesh *dm)
1193 {
1194         int test= (U.gameflags & USER_DISABLE_VBO);
1195         if(test)
1196                 return 1;
1197
1198         if(dm->drawObject == 0)
1199                 dm->drawObject = GPU_drawobject_new(dm);
1200         return dm->drawObject->legacy;
1201 }
1202
1203 void *GPU_buffer_lock(GPUBuffer *buffer)
1204 {
1205         float *varray;
1206
1207         if(!buffer)
1208                 return 0;
1209
1210         if(useVBOs) {
1211                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
1212                 varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1213                 return varray;
1214         }
1215         else {
1216                 return buffer->pointer;
1217         }
1218 }
1219
1220 void *GPU_buffer_lock_stream(GPUBuffer *buffer)
1221 {
1222         float *varray;
1223
1224         if(!buffer)
1225                 return 0;
1226
1227         if(useVBOs) {
1228                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
1229                 /* discard previous data, avoid stalling gpu */
1230                 glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB);
1231                 varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1232                 return varray;
1233         }
1234         else {
1235                 return buffer->pointer;
1236         }
1237 }
1238
1239 void GPU_buffer_unlock(GPUBuffer *buffer)
1240 {
1241         if(useVBOs) {
1242                 if(buffer) {
1243                         /* note: this operation can fail, could return
1244                            an error code from this function? */
1245                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
1246                 }
1247                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1248         }
1249 }
1250
1251 /* used for drawing edges */
1252 void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count)
1253 {
1254         glDrawElements(mode, count, GL_UNSIGNED_INT,
1255                        (useVBOs ?
1256                         (void*)(start * sizeof(unsigned int)) :
1257                         ((int*)elements->pointer) + start));
1258 }
1259
1260
1261 /* XXX: the rest of the code in this file is used for optimized PBVH
1262    drawing and doesn't interact at all with the buffer code above */
1263
1264 /* Convenience struct for building the VBO. */
1265 typedef struct {
1266         float co[3];
1267         short no[3];
1268 } VertexBufferFormat;
1269
1270 struct GPU_Buffers {
1271         /* opengl buffer handles */
1272         GLuint vert_buf, index_buf;
1273         GLenum index_type;
1274
1275         /* mesh pointers in case buffer allocation fails */
1276         MFace *mface;
1277         MVert *mvert;
1278         int *face_indices;
1279         int totface;
1280
1281         /* grid pointers */
1282         DMGridData **grids;
1283         const DMFlagMat *grid_flag_mats;
1284         const BLI_bitmap *grid_hidden;
1285         int *grid_indices;
1286         int totgrid;
1287         int gridsize;
1288         int has_hidden;
1289
1290         unsigned int tot_tri, tot_quad;
1291 };
1292
1293 void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert,
1294                         int *vert_indices, int totvert)
1295 {
1296         VertexBufferFormat *vert_data;
1297         int i;
1298
1299         if(buffers->vert_buf) {
1300                 /* Build VBO */
1301                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
1302                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
1303                                 sizeof(VertexBufferFormat) * totvert,
1304                                 NULL, GL_STATIC_DRAW_ARB);
1305                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1306
1307                 if(vert_data) {
1308                         for(i = 0; i < totvert; ++i) {
1309                                 MVert *v = mvert + vert_indices[i];
1310                                 VertexBufferFormat *out = vert_data + i;
1311
1312                                 copy_v3_v3(out->co, v->co);
1313                                 memcpy(out->no, v->no, sizeof(short) * 3);
1314                         }
1315
1316                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
1317                 }
1318                 else {
1319                         glDeleteBuffersARB(1, &buffers->vert_buf);
1320                         buffers->vert_buf = 0;
1321                 }
1322
1323                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1324         }
1325
1326         buffers->mvert = mvert;
1327 }
1328
1329 GPU_Buffers *GPU_build_mesh_buffers(int (*face_vert_indices)[4],
1330                                                                         MFace *mface, MVert *mvert,
1331                                                                         int *face_indices,
1332                                                                         int totface)
1333 {
1334         GPU_Buffers *buffers;
1335         unsigned short *tri_data;
1336         int i, j, k, tottri;
1337
1338         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
1339         buffers->index_type = GL_UNSIGNED_SHORT;
1340
1341         /* Count the number of visible triangles */
1342         for(i = 0, tottri = 0; i < totface; ++i) {
1343                 const MFace *f = &mface[face_indices[i]];
1344                 if(!paint_is_face_hidden(f, mvert))
1345                         tottri += f->v4 ? 2 : 1;
1346         }
1347         
1348         if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
1349                 glGenBuffersARB(1, &buffers->index_buf);
1350
1351         if(buffers->index_buf) {
1352                 /* Generate index buffer object */
1353                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
1354                 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
1355                                 sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB);
1356
1357                 /* Fill the triangle buffer */
1358                 tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1359                 if(tri_data) {
1360                         for(i = 0; i < totface; ++i) {
1361                                 const MFace *f = mface + face_indices[i];
1362                                 int v[3];
1363
1364                                 /* Skip hidden faces */
1365                                 if(paint_is_face_hidden(f, mvert))
1366                                         continue;
1367
1368                                 v[0]= 0;
1369                                 v[1]= 1;
1370                                 v[2]= 2;
1371
1372                                 for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
1373                                         for(k = 0; k < 3; ++k) {
1374                                                 *tri_data = face_vert_indices[i][v[k]];
1375                                                 ++tri_data;
1376                                         }
1377                                         v[0] = 3;
1378                                         v[1] = 0;
1379                                         v[2] = 2;
1380                                 }
1381                         }
1382                         glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
1383                 }
1384                 else {
1385                         glDeleteBuffersARB(1, &buffers->index_buf);
1386                         buffers->index_buf = 0;
1387                 }
1388
1389                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1390         }
1391
1392         if(buffers->index_buf)
1393                 glGenBuffersARB(1, &buffers->vert_buf);
1394
1395         buffers->tot_tri = tottri;
1396
1397         buffers->mface = mface;
1398         buffers->face_indices = face_indices;
1399         buffers->totface = totface;
1400
1401         return buffers;
1402 }
1403
1404 void GPU_update_grid_buffers(GPU_Buffers *buffers, DMGridData **grids,
1405         const DMFlagMat *grid_flag_mats, int *grid_indices, int totgrid, int gridsize)
1406 {
1407         DMGridData *vert_data;
1408         int i, j, k, totvert;
1409
1410         totvert= gridsize*gridsize*totgrid;
1411
1412         /* Build VBO */
1413         if(buffers->vert_buf) {
1414                 int smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
1415
1416                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
1417                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
1418                                 sizeof(DMGridData) * totvert,
1419                                 NULL, GL_STATIC_DRAW_ARB);
1420                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1421                 if(vert_data) {
1422                         for(i = 0; i < totgrid; ++i) {
1423                                 DMGridData *grid= grids[grid_indices[i]];
1424                                 memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize);
1425
1426                                 if(!smooth) {
1427                                         /* for flat shading, recalc normals and set the last vertex of
1428                                            each quad in the index buffer to have the flat normal as
1429                                            that is what opengl will use */
1430                                         for(j = 0; j < gridsize-1; ++j) {
1431                                                 for(k = 0; k < gridsize-1; ++k) {
1432                                                         float fno[3];
1433                                                         normal_quad_v3(fno,
1434                                                                 grid[(j+1)*gridsize + k].co,
1435                                                                 grid[(j+1)*gridsize + k+1].co,
1436                                                                 grid[j*gridsize + k+1].co,
1437                                                                 grid[j*gridsize + k].co);
1438
1439                                                         copy_v3_v3(vert_data[(j+1)*gridsize + (k+1)].no, fno);
1440                                                 }
1441                                         }
1442                                 }
1443
1444                                 vert_data += gridsize*gridsize;
1445                         }
1446                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
1447                 }
1448                 else {
1449                         glDeleteBuffersARB(1, &buffers->vert_buf);
1450                         buffers->vert_buf = 0;
1451                 }
1452                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1453         }
1454
1455         buffers->grids = grids;
1456         buffers->grid_indices = grid_indices;
1457         buffers->totgrid = totgrid;
1458         buffers->gridsize = gridsize;
1459         buffers->grid_flag_mats = grid_flag_mats;
1460
1461         //printf("node updated %p\n", buffers);
1462 }
1463
1464 /* Returns the number of visible quads in the nodes' grids. */
1465 static int gpu_count_grid_quads(BLI_bitmap *grid_hidden,
1466                                                                 int *grid_indices, int totgrid,
1467                                                                 int gridsize)
1468 {
1469         int gridarea = (gridsize-1) * (gridsize-1);
1470         int i, x, y, totquad;
1471
1472         /* grid hidden layer is present, so have to check each grid for
1473            visiblity */
1474
1475         for(i = 0, totquad = 0; i < totgrid; i++) {
1476                 const BLI_bitmap gh = grid_hidden[grid_indices[i]];
1477
1478                 if(gh) {
1479                         /* grid hidden are present, have to check each element */
1480                         for(y = 0; y < gridsize-1; y++) {
1481                                 for(x = 0; x < gridsize-1; x++) {
1482                                         if(!paint_is_grid_face_hidden(gh, gridsize, x, y))
1483                                                 totquad++;
1484                                 }
1485                         }
1486                 }
1487                 else
1488                         totquad += gridarea;
1489         }
1490
1491         return totquad;
1492 }
1493
1494 /* Build the element array buffer of grid indices using either
1495    unsigned shorts or unsigned ints. */
1496 #define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_)                                             \
1497         {                                                                   \
1498                 type_ *quad_data;                                               \
1499                 int offset = 0;                                                 \
1500         int i, j, k;                                                    \
1501                                                                         \
1502                 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,                    \
1503                                                 sizeof(type_) * (tot_quad_) * 4, NULL,                  \
1504                                                 GL_STATIC_DRAW_ARB);                            \
1505                                                                         \
1506                 /* Fill the quad buffer */                                      \
1507                 quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,         \
1508                                                                    GL_WRITE_ONLY_ARB);                  \
1509                 if(quad_data) {                                                 \
1510                         for(i = 0; i < totgrid; ++i) {                                                          \
1511                                 BLI_bitmap gh = NULL;                                                                   \
1512                                 if(grid_hidden)                                                                                 \
1513                                         gh = grid_hidden[(grid_indices)[i]];                            \
1514                                                                                                                                                 \
1515                                 for(j = 0; j < gridsize-1; ++j) {                       \
1516                                         for(k = 0; k < gridsize-1; ++k) {                   \
1517                                                 /* Skip hidden grid face */                                             \
1518                                                 if(gh &&                                                                                \
1519                                                    paint_is_grid_face_hidden(gh,                                \
1520                                                                                                          gridsize, k, j))       \
1521                                                         continue;                                                                       \
1522                                                                                                                                                 \
1523                                                 *(quad_data++)= offset + j*gridsize + k+1;      \
1524                                                 *(quad_data++)= offset + j*gridsize + k;        \
1525                                                 *(quad_data++)= offset + (j+1)*gridsize + k;    \
1526                                                 *(quad_data++)= offset + (j+1)*gridsize + k+1;  \
1527                                         }                                                   \
1528                                 }                                                       \
1529                                                                                                                                                 \
1530                                 offset += gridsize*gridsize;                            \
1531                         }                                                           \
1532                         glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);              \
1533                 }                                                               \
1534                 else {                                                          \
1535                         glDeleteBuffersARB(1, &(buffer_));                                                      \
1536                         (buffer_) = 0;                                                                                          \
1537                 }                                                               \
1538         }
1539 /* end FILL_QUAD_BUFFER */
1540
1541 static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad)
1542 {
1543         static int prev_gridsize = -1;
1544         static GLenum prev_index_type = 0;
1545         static GLuint buffer = 0;
1546         static unsigned prev_totquad;
1547
1548         /* used in the FILL_QUAD_BUFFER macro */
1549         const BLI_bitmap *grid_hidden = NULL;
1550         int *grid_indices = NULL;
1551         int totgrid = 1;
1552
1553         /* VBO is disabled; delete the previous buffer (if it exists) and
1554            return an invalid handle */
1555         if(!GLEW_ARB_vertex_buffer_object || (U.gameflags & USER_DISABLE_VBO)) {
1556                 if(buffer)
1557                         glDeleteBuffersARB(1, &buffer);
1558                 return 0;
1559         }
1560
1561         /* VBO is already built */
1562         if(buffer && prev_gridsize == gridsize) {
1563                 *index_type = prev_index_type;
1564                 *totquad = prev_totquad;
1565                 return buffer;
1566         }
1567
1568         /* Build new VBO */
1569         glGenBuffersARB(1, &buffer);
1570         if(buffer) {
1571                 *totquad= (gridsize-1)*(gridsize-1);
1572
1573                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
1574
1575                 if(*totquad < USHRT_MAX) {
1576                         *index_type = GL_UNSIGNED_SHORT;
1577                         FILL_QUAD_BUFFER(unsigned short, *totquad, buffer);
1578                 }
1579                 else {
1580                         *index_type = GL_UNSIGNED_INT;
1581                         FILL_QUAD_BUFFER(unsigned int, *totquad, buffer);
1582                 }
1583
1584                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1585         }
1586
1587         prev_gridsize = gridsize;
1588         prev_index_type = *index_type;
1589         prev_totquad = *totquad;
1590         return buffer;
1591 }
1592
1593 GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid,
1594                                                                         BLI_bitmap *grid_hidden, int gridsize)
1595 {
1596         GPU_Buffers *buffers;
1597         int totquad;
1598         int fully_visible_totquad = (gridsize-1) * (gridsize-1) * totgrid;
1599
1600         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
1601         buffers->grid_hidden = grid_hidden;
1602         buffers->gridsize = gridsize;
1603         buffers->totgrid = totgrid;
1604
1605         /* Count the number of quads */
1606         totquad= gpu_count_grid_quads(grid_hidden, grid_indices, totgrid, gridsize);
1607
1608         if(totquad == fully_visible_totquad) {
1609                 buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad);
1610                 buffers->has_hidden = 0;
1611         }
1612         else if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO)) {
1613                 /* Build new VBO */
1614                 glGenBuffersARB(1, &buffers->index_buf);
1615                 if(buffers->index_buf) {
1616                         buffers->tot_quad= totquad;
1617
1618                         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
1619
1620                         if(totquad < USHRT_MAX) {
1621                                 buffers->index_type = GL_UNSIGNED_SHORT;
1622                                 FILL_QUAD_BUFFER(unsigned short, totquad, buffers->index_buf);
1623                         }
1624                         else {
1625                                 buffers->index_type = GL_UNSIGNED_INT;
1626                                 FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf);
1627                         }
1628
1629                         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1630                 }
1631
1632                 buffers->has_hidden = 1;
1633         }
1634
1635         /* Build coord/normal VBO */
1636         if(buffers->index_buf)
1637                 glGenBuffersARB(1, &buffers->vert_buf);
1638
1639         return buffers;
1640 }
1641
1642 #undef FILL_QUAD_BUFFER
1643
1644 static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers, int smooth)
1645 {
1646         const MVert *mvert = buffers->mvert;
1647         int i, j;
1648
1649         for(i = 0; i < buffers->totface; ++i) {
1650                 MFace *f = buffers->mface + buffers->face_indices[i];
1651                 int S = f->v4 ? 4 : 3;
1652                 unsigned int *fv = &f->v1;
1653
1654                 if(paint_is_face_hidden(f, buffers->mvert))
1655                         continue;
1656
1657                 glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
1658
1659                 if(smooth) {
1660                         for(j = 0; j < S; j++) {
1661                                 glNormal3sv(mvert[fv[j]].no);
1662                                 glVertex3fv(mvert[fv[j]].co);
1663                         }
1664                 }
1665                 else {
1666                         float fno[3];
1667
1668                         /* calculate face normal */
1669                         if(f->v4) {
1670                                 normal_quad_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co,
1671                                                            mvert[fv[2]].co, mvert[fv[3]].co);
1672                         }
1673                         else
1674                                 normal_tri_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co, mvert[fv[2]].co);
1675                         glNormal3fv(fno);
1676                         
1677                         for(j = 0; j < S; j++)
1678                                 glVertex3fv(mvert[fv[j]].co);
1679                 }
1680                 
1681                 glEnd();
1682         }
1683 }
1684
1685 static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers, int smooth)
1686 {
1687         int i, j, x, y, gridsize = buffers->gridsize;
1688
1689         for(i = 0; i < buffers->totgrid; ++i) {
1690                 int g = buffers->grid_indices[i];
1691                 const DMGridData *grid = buffers->grids[g];
1692                 BLI_bitmap gh = buffers->grid_hidden[g];
1693
1694                 /* TODO: could use strips with hiding as well */
1695
1696                 if(gh) {
1697                         glBegin(GL_QUADS);
1698                         
1699                         for(y = 0; y < gridsize-1; y++) {
1700                                 for(x = 0; x < gridsize-1; x++) {
1701                                         const DMGridData *e[4] = {
1702                                                 &grid[y*gridsize + x],
1703                                                 &grid[(y+1)*gridsize + x],
1704                                                 &grid[(y+1)*gridsize + x+1],
1705                                                 &grid[y*gridsize + x+1]
1706                                         };
1707
1708                                         /* skip face if any of its corners are hidden */
1709                                         if(paint_is_grid_face_hidden(gh, gridsize, x, y))
1710                                                 continue;
1711
1712                                         if(smooth) {
1713                                                 for(j = 0; j < 4; j++) {
1714                                                         glNormal3fv(e[j]->no);
1715                                                         glVertex3fv(e[j]->co);
1716                                                 }
1717                                         }
1718                                         else {
1719                                                 float fno[3];
1720                                                 normal_quad_v3(fno, e[0]->co, e[1]->co, e[2]->co, e[3]->co);
1721                                                 glNormal3fv(fno);
1722
1723                                                 for(j = 0; j < 4; j++)
1724                                                         glVertex3fv(e[j]->co);
1725                                         }
1726                                 }
1727                         }
1728
1729                         glEnd();
1730                 }
1731                 else if(smooth) {
1732                         for(y = 0; y < gridsize-1; y++) {
1733                                 glBegin(GL_QUAD_STRIP);
1734                                 for(x = 0; x < gridsize; x++) {
1735                                         const DMGridData *a = &grid[y*gridsize + x];
1736                                         const DMGridData *b = &grid[(y+1)*gridsize + x];
1737
1738                                         glNormal3fv(a->no);
1739                                         glVertex3fv(a->co);
1740                                         glNormal3fv(b->no);
1741                                         glVertex3fv(b->co);
1742                                 }
1743                                 glEnd();
1744                         }
1745                 }
1746                 else {
1747                         for(y = 0; y < gridsize-1; y++) {
1748                                 glBegin(GL_QUAD_STRIP);
1749                                 for(x = 0; x < gridsize; x++) {
1750                                         const DMGridData *a = &grid[y*gridsize + x];
1751                                         const DMGridData *b = &grid[(y+1)*gridsize + x];
1752
1753                                         if(x > 0) {
1754                                                 const DMGridData *c = &grid[y*gridsize + x-1];
1755                                                 const DMGridData *d = &grid[(y+1)*gridsize + x-1];
1756                                                 float fno[3];
1757                                                 normal_quad_v3(fno, d->co, b->co, a->co, c->co);
1758                                                 glNormal3fv(fno);
1759                                         }
1760
1761                                         glVertex3fv(a->co);
1762                                         glVertex3fv(b->co);
1763                                 }
1764                                 glEnd();
1765                         }
1766                 }
1767         }
1768 }
1769
1770 void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial)
1771 {
1772         int smooth = 0;
1773
1774         if(buffers->totface) {
1775                 const MFace *f = &buffers->mface[buffers->face_indices[0]];
1776                 if(!setMaterial(f->mat_nr+1, NULL))
1777                         return;
1778
1779                 smooth = f->flag & ME_SMOOTH;
1780                 glShadeModel(smooth ? GL_SMOOTH: GL_FLAT);
1781         }
1782         else if(buffers->totgrid) {
1783                 const DMFlagMat *f = &buffers->grid_flag_mats[buffers->grid_indices[0]];
1784                 if(!setMaterial(f->mat_nr+1, NULL))
1785                         return;
1786
1787                 smooth = f->flag & ME_SMOOTH;
1788                 glShadeModel(smooth ? GL_SMOOTH: GL_FLAT);
1789         }
1790
1791         if(buffers->vert_buf && buffers->index_buf) {
1792                 glEnableClientState(GL_VERTEX_ARRAY);
1793                 glEnableClientState(GL_NORMAL_ARRAY);
1794
1795                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
1796                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
1797
1798                 if(buffers->tot_quad) {
1799                         unsigned offset = 0;
1800                         int i, last = buffers->has_hidden ? 1 : buffers->totgrid;
1801                         for(i = 0; i < last; i++) {
1802                                 glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), offset + (char*)offsetof(DMGridData, co));
1803                                 glNormalPointer(GL_FLOAT, sizeof(DMGridData), offset + (char*)offsetof(DMGridData, no));
1804                                 
1805                                 glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0);
1806
1807                                 offset += buffers->gridsize * buffers->gridsize * sizeof(DMGridData);
1808                         }
1809                 }
1810                 else {
1811                         glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, co));
1812                         glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
1813
1814                         glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
1815                 }
1816
1817                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1818                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1819
1820                 glDisableClientState(GL_VERTEX_ARRAY);
1821                 glDisableClientState(GL_NORMAL_ARRAY);
1822         }
1823         /* fallbacks if we are out of memory or VBO is disabled */
1824         else if(buffers->totface) {
1825                 gpu_draw_buffers_legacy_mesh(buffers, smooth);
1826         }
1827         else if(buffers->totgrid) {
1828                 gpu_draw_buffers_legacy_grids(buffers, smooth);
1829         }
1830 }
1831
1832 void GPU_free_buffers(GPU_Buffers *buffers)
1833 {
1834         if(buffers) {
1835                 if(buffers->vert_buf)
1836                         glDeleteBuffersARB(1, &buffers->vert_buf);
1837                 if(buffers->index_buf && (buffers->tot_tri || buffers->has_hidden))
1838                         glDeleteBuffersARB(1, &buffers->index_buf);
1839
1840                 MEM_freeN(buffers);
1841         }
1842 }