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