8d72bd64e29bcea369b59301a142829413d9e564
[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. The Blender
8  * Foundation also sells licenses for use in proprietary software under
9  * the Blender License.  See http://www.blender.org/BL/ for information
10  * about this.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The Original Code is Copyright (C) 2005 Blender Foundation.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): Brecht Van Lommel.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 /** \file blender/gpu/intern/gpu_buffers.c
32  *  \ingroup gpu
33  */
34
35
36 #include <limits.h>
37 #include <stddef.h>
38 #include <string.h>
39
40 #include "GL/glew.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_math.h"
45 #include "BLI_utildefines.h"
46 #include "BLI_ghash.h"
47 #include "BLI_threads.h"
48
49 #include "DNA_meshdata_types.h"
50
51 #include "BKE_DerivedMesh.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-free'd 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->getFaceArray(dm);
402         totface= dm->getNumFaces(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->getFaceArray(dm);
580
581         totface= dm->getNumFaces(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->getFaceDataArray(dm, CD_NORMAL);
617         MVert *mvert = dm->getVertArray(dm);
618         MFace *f = dm->getFaceArray(dm);
619
620         totface= dm->getNumFaces(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_face_data_layer(dm, CD_MTFACE)))
680                 return;
681         f = dm->getFaceArray(dm);
682                 
683         totface = dm->getNumFaces(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         unsigned char *varray = (unsigned char *)varray_;
708         unsigned char *mcol = (unsigned char *)user;
709         MFace *f = dm->getFaceArray(dm);
710
711         totface= dm->getNumFaces(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                 VECCOPY(&varray[start], &mcol[i*12]);
717                 VECCOPY(&varray[start+3], &mcol[i*12+3]);
718                 VECCOPY(&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                         VECCOPY(&varray[start+9], &mcol[i*12+6]);
724                         VECCOPY(&varray[start+12], &mcol[i*12+9]);
725                         VECCOPY(&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->getFaceArray(dm);
745
746         totface= dm->getNumFaces(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_face_data_layer(dm, CD_MTFACE);
784         int i, j=0;
785
786         if(!tf)
787                 return;
788
789         for(i = 0; i < dm->numFaceData; i++, tf++) {
790                 MFace mf;
791                 dm->getFace(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_face_data_layer(dm, type);
823         if(!c) {
824                 type = CD_WEIGHT_MCOL;
825                 c = DM_get_face_data_layer(dm, type);
826                 if(!c) {
827                         type = CD_MCOL;
828                         c = DM_get_face_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_face_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 /* this is used only in cdDM_drawFacesColored, which I think is no
1177    longer used, so can probably remove this --nicholas */
1178 void GPU_color4_upload(DerivedMesh *UNUSED(dm), unsigned char *UNUSED(data))
1179 {
1180         /*if(dm->drawObject == 0)
1181                 dm->drawObject = GPU_drawobject_new(dm);
1182         GPU_buffer_free(dm->drawObject->colors);
1183         dm->drawObject->colors = gpu_buffer_setup(dm, dm->drawObject, 3,
1184                                                   sizeof(char)*3*dm->drawObject->tot_triangle_point,
1185                                                   GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4);*/
1186 }
1187
1188 void GPU_color_switch(int mode)
1189 {
1190         if(mode) {
1191                 if(!(GLStates & GPU_BUFFER_COLOR_STATE))
1192                         glEnableClientState(GL_COLOR_ARRAY);
1193                 GLStates |= GPU_BUFFER_COLOR_STATE;
1194         }
1195         else {
1196                 if(GLStates & GPU_BUFFER_COLOR_STATE)
1197                         glDisableClientState(GL_COLOR_ARRAY);
1198                 GLStates &= (!GPU_BUFFER_COLOR_STATE);
1199         }
1200 }
1201
1202 /* return 1 if drawing should be done using old immediate-mode
1203    code, 0 otherwise */
1204 int GPU_buffer_legacy(DerivedMesh *dm)
1205 {
1206         int test= (U.gameflags & USER_DISABLE_VBO);
1207         if(test)
1208                 return 1;
1209
1210         if(dm->drawObject == 0)
1211                 dm->drawObject = GPU_drawobject_new(dm);
1212         return dm->drawObject->legacy;
1213 }
1214
1215 void *GPU_buffer_lock(GPUBuffer *buffer)
1216 {
1217         float *varray;
1218
1219         if(!buffer)
1220                 return 0;
1221
1222         if(useVBOs) {
1223                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
1224                 varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1225                 return varray;
1226         }
1227         else {
1228                 return buffer->pointer;
1229         }
1230 }
1231
1232 void *GPU_buffer_lock_stream(GPUBuffer *buffer)
1233 {
1234         float *varray;
1235
1236         if(!buffer)
1237                 return 0;
1238
1239         if(useVBOs) {
1240                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
1241                 /* discard previous data, avoid stalling gpu */
1242                 glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB);
1243                 varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1244                 return varray;
1245         }
1246         else {
1247                 return buffer->pointer;
1248         }
1249 }
1250
1251 void GPU_buffer_unlock(GPUBuffer *buffer)
1252 {
1253         if(useVBOs) {
1254                 if(buffer) {
1255                         /* note: this operation can fail, could return
1256                            an error code from this function? */
1257                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
1258                 }
1259                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1260         }
1261 }
1262
1263 /* used for drawing edges */
1264 void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count)
1265 {
1266         glDrawElements(mode, count, GL_UNSIGNED_INT,
1267                        (useVBOs ?
1268                         (void*)(start * sizeof(unsigned int)) :
1269                         ((int*)elements->pointer) + start));
1270 }
1271
1272
1273 /* XXX: the rest of the code in this file is used for optimized PBVH
1274    drawing and doesn't interact at all with the buffer code above */
1275
1276 /* Convenience struct for building the VBO. */
1277 typedef struct {
1278         float co[3];
1279         short no[3];
1280 } VertexBufferFormat;
1281
1282 struct GPU_Buffers {
1283         /* opengl buffer handles */
1284         GLuint vert_buf, index_buf;
1285         GLenum index_type;
1286
1287         /* mesh pointers in case buffer allocation fails */
1288         MFace *mface;
1289         MVert *mvert;
1290         int *face_indices;
1291         int totface;
1292
1293         /* grid pointers */
1294         DMGridData **grids;
1295         int *grid_indices;
1296         int totgrid;
1297         int gridsize;
1298
1299         unsigned int tot_tri, tot_quad;
1300 };
1301
1302 void GPU_update_mesh_buffers(GPU_Buffers *buffers_v, MVert *mvert,
1303                         int *vert_indices, int totvert)
1304 {
1305         GPU_Buffers *buffers = buffers_v;
1306         VertexBufferFormat *vert_data;
1307         int i;
1308
1309         if(buffers->vert_buf) {
1310                 /* Build VBO */
1311                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
1312                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
1313                                 sizeof(VertexBufferFormat) * totvert,
1314                                 NULL, GL_STATIC_DRAW_ARB);
1315                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1316
1317                 if(vert_data) {
1318                         for(i = 0; i < totvert; ++i) {
1319                                 MVert *v = mvert + vert_indices[i];
1320                                 VertexBufferFormat *out = vert_data + i;
1321
1322                                 copy_v3_v3(out->co, v->co);
1323                                 memcpy(out->no, v->no, sizeof(short) * 3);
1324                         }
1325
1326                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
1327                 }
1328                 else {
1329                         glDeleteBuffersARB(1, &buffers->vert_buf);
1330                         buffers->vert_buf = 0;
1331                 }
1332
1333                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1334         }
1335
1336         buffers->mvert = mvert;
1337 }
1338
1339 GPU_Buffers *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
1340                         int *face_indices, int totface,
1341                         int *vert_indices, int tot_uniq_verts,
1342                         int totvert)
1343 {
1344         GPU_Buffers *buffers;
1345         unsigned short *tri_data;
1346         int i, j, k, tottri;
1347
1348         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
1349         buffers->index_type = GL_UNSIGNED_SHORT;
1350
1351         /* Count the number of triangles */
1352         for(i = 0, tottri = 0; i < totface; ++i)
1353                 tottri += mface[face_indices[i]].v4 ? 2 : 1;
1354         
1355         if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
1356                 glGenBuffersARB(1, &buffers->index_buf);
1357
1358         if(buffers->index_buf) {
1359                 /* Generate index buffer object */
1360                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
1361                 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
1362                                 sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB);
1363
1364                 /* Fill the triangle buffer */
1365                 tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1366                 if(tri_data) {
1367                         for(i = 0; i < totface; ++i) {
1368                                 MFace *f = mface + face_indices[i];
1369                                 int v[3];
1370
1371                                 v[0]= f->v1;
1372                                 v[1]= f->v2;
1373                                 v[2]= f->v3;
1374
1375                                 for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
1376                                         for(k = 0; k < 3; ++k) {
1377                                                 void *value, *key = SET_INT_IN_POINTER(v[k]);
1378                                                 int vbo_index;
1379
1380                                                 value = BLI_ghash_lookup(map, key);
1381                                                 vbo_index = GET_INT_FROM_POINTER(value);
1382
1383                                                 if(vbo_index < 0) {
1384                                                         vbo_index = -vbo_index +
1385                                                                 tot_uniq_verts - 1;
1386                                                 }
1387
1388                                                 *tri_data = vbo_index;
1389                                                 ++tri_data;
1390                                         }
1391                                         v[0] = f->v4;
1392                                         v[1] = f->v1;
1393                                         v[2] = f->v3;
1394                                 }
1395                         }
1396                         glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
1397                 }
1398                 else {
1399                         glDeleteBuffersARB(1, &buffers->index_buf);
1400                         buffers->index_buf = 0;
1401                 }
1402
1403                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1404         }
1405
1406         if(buffers->index_buf)
1407                 glGenBuffersARB(1, &buffers->vert_buf);
1408         GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert);
1409
1410         buffers->tot_tri = tottri;
1411
1412         buffers->mface = mface;
1413         buffers->face_indices = face_indices;
1414         buffers->totface = totface;
1415
1416         return buffers;
1417 }
1418
1419 void GPU_update_grid_buffers(GPU_Buffers *buffers_v, DMGridData **grids,
1420         int *grid_indices, int totgrid, int gridsize, int smooth)
1421 {
1422         GPU_Buffers *buffers = buffers_v;
1423         DMGridData *vert_data;
1424         int i, j, k, totvert;
1425
1426         totvert= gridsize*gridsize*totgrid;
1427
1428         /* Build VBO */
1429         if(buffers->vert_buf) {
1430                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
1431                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
1432                                 sizeof(DMGridData) * totvert,
1433                                 NULL, GL_STATIC_DRAW_ARB);
1434                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1435                 if(vert_data) {
1436                         for(i = 0; i < totgrid; ++i) {
1437                                 DMGridData *grid= grids[grid_indices[i]];
1438                                 memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize);
1439
1440                                 if(!smooth) {
1441                                         /* for flat shading, recalc normals and set the last vertex of
1442                                            each quad in the index buffer to have the flat normal as
1443                                            that is what opengl will use */
1444                                         for(j = 0; j < gridsize-1; ++j) {
1445                                                 for(k = 0; k < gridsize-1; ++k) {
1446                                                         normal_quad_v3(vert_data[(j+1)*gridsize + (k+1)].no,
1447                                                                 vert_data[(j+1)*gridsize + k].co,
1448                                                                 vert_data[(j+1)*gridsize + k+1].co,
1449                                                                 vert_data[j*gridsize + k+1].co,
1450                                                                 vert_data[j*gridsize + k].co);
1451                                                 }
1452                                         }
1453                                 }
1454
1455                                 vert_data += gridsize*gridsize;
1456                         }
1457                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
1458                 }
1459                 else {
1460                         glDeleteBuffersARB(1, &buffers->vert_buf);
1461                         buffers->vert_buf = 0;
1462                 }
1463                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1464         }
1465
1466         buffers->grids = grids;
1467         buffers->grid_indices = grid_indices;
1468         buffers->totgrid = totgrid;
1469         buffers->gridsize = gridsize;
1470
1471         //printf("node updated %p\n", buffers_v);
1472 }
1473
1474 GPU_Buffers *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
1475                                 int totgrid, int gridsize)
1476 {
1477         GPU_Buffers *buffers;
1478         int i, j, k, totquad, offset= 0;
1479
1480         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
1481
1482         /* Count the number of quads */
1483         totquad= (gridsize-1)*(gridsize-1)*totgrid;
1484
1485         /* Generate index buffer object */
1486         if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
1487                 glGenBuffersARB(1, &buffers->index_buf);
1488
1489         if(buffers->index_buf) {
1490                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
1491
1492                 if(totquad < USHRT_MAX) {
1493                         unsigned short *quad_data;
1494
1495                         buffers->index_type = GL_UNSIGNED_SHORT;
1496                         glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
1497                                          sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
1498
1499                         /* Fill the quad buffer */
1500                         quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1501                         if(quad_data) {
1502                                 for(i = 0; i < totgrid; ++i) {
1503                                         for(j = 0; j < gridsize-1; ++j) {
1504                                                 for(k = 0; k < gridsize-1; ++k) {
1505                                                         *(quad_data++)= offset + j*gridsize + k+1;
1506                                                         *(quad_data++)= offset + j*gridsize + k;
1507                                                         *(quad_data++)= offset + (j+1)*gridsize + k;
1508                                                         *(quad_data++)= offset + (j+1)*gridsize + k+1;
1509                                                 }
1510                                         }
1511
1512                                         offset += gridsize*gridsize;
1513                                 }
1514                                 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
1515                         }
1516                         else {
1517                                 glDeleteBuffersARB(1, &buffers->index_buf);
1518                                 buffers->index_buf = 0;
1519                         }
1520                 }
1521                 else {
1522                         unsigned int *quad_data;
1523
1524                         buffers->index_type = GL_UNSIGNED_INT;
1525                         glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
1526                                          sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
1527
1528                         /* Fill the quad buffer */
1529                         quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
1530
1531                         if(quad_data) {
1532                                 for(i = 0; i < totgrid; ++i) {
1533                                         for(j = 0; j < gridsize-1; ++j) {
1534                                                 for(k = 0; k < gridsize-1; ++k) {
1535                                                         *(quad_data++)= offset + j*gridsize + k+1;
1536                                                         *(quad_data++)= offset + j*gridsize + k;
1537                                                         *(quad_data++)= offset + (j+1)*gridsize + k;
1538                                                         *(quad_data++)= offset + (j+1)*gridsize + k+1;
1539                                                 }
1540                                         }
1541
1542                                         offset += gridsize*gridsize;
1543                                 }
1544                                 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
1545                         }
1546                         else {
1547                                 glDeleteBuffersARB(1, &buffers->index_buf);
1548                                 buffers->index_buf = 0;
1549                         }
1550                 }
1551
1552                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1553         }
1554
1555         /* Build VBO */
1556         if(buffers->index_buf)
1557                 glGenBuffersARB(1, &buffers->vert_buf);
1558
1559         buffers->tot_quad = totquad;
1560
1561         return buffers;
1562 }
1563
1564 void GPU_draw_buffers(GPU_Buffers *buffers_v)
1565 {
1566         GPU_Buffers *buffers = buffers_v;
1567
1568         if(buffers->vert_buf && buffers->index_buf) {
1569                 glEnableClientState(GL_VERTEX_ARRAY);
1570                 glEnableClientState(GL_NORMAL_ARRAY);
1571
1572                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
1573                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
1574
1575                 if(buffers->tot_quad) {
1576                         glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, co));
1577                         glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no));
1578
1579                         glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0);
1580                 }
1581                 else {
1582                         glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, co));
1583                         glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
1584
1585                         glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
1586                 }
1587
1588                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1589                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1590
1591                 glDisableClientState(GL_VERTEX_ARRAY);
1592                 glDisableClientState(GL_NORMAL_ARRAY);
1593         }
1594         else if(buffers->totface) {
1595                 /* fallback if we are out of memory */
1596                 int i;
1597
1598                 for(i = 0; i < buffers->totface; ++i) {
1599                         MFace *f = buffers->mface + buffers->face_indices[i];
1600
1601                         glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
1602                         glNormal3sv(buffers->mvert[f->v1].no);
1603                         glVertex3fv(buffers->mvert[f->v1].co);
1604                         glNormal3sv(buffers->mvert[f->v2].no);
1605                         glVertex3fv(buffers->mvert[f->v2].co);
1606                         glNormal3sv(buffers->mvert[f->v3].no);
1607                         glVertex3fv(buffers->mvert[f->v3].co);
1608                         if(f->v4) {
1609                                 glNormal3sv(buffers->mvert[f->v4].no);
1610                                 glVertex3fv(buffers->mvert[f->v4].co);
1611                         }
1612                         glEnd();
1613                 }
1614         }
1615         else if(buffers->totgrid) {
1616                 int i, x, y, gridsize = buffers->gridsize;
1617
1618                 for(i = 0; i < buffers->totgrid; ++i) {
1619                         DMGridData *grid = buffers->grids[buffers->grid_indices[i]];
1620
1621                         for(y = 0; y < gridsize-1; y++) {
1622                                 glBegin(GL_QUAD_STRIP);
1623                                 for(x = 0; x < gridsize; x++) {
1624                                         DMGridData *a = &grid[y*gridsize + x];
1625                                         DMGridData *b = &grid[(y+1)*gridsize + x];
1626
1627                                         glNormal3fv(a->no);
1628                                         glVertex3fv(a->co);
1629                                         glNormal3fv(b->no);
1630                                         glVertex3fv(b->co);
1631                                 }
1632                                 glEnd();
1633                         }
1634                 }
1635         }
1636 }
1637
1638 void GPU_free_buffers(GPU_Buffers *buffers_v)
1639 {
1640         if(buffers_v) {
1641                 GPU_Buffers *buffers = buffers_v;
1642                 
1643                 if(buffers->vert_buf)
1644                         glDeleteBuffersARB(1, &buffers->vert_buf);
1645                 if(buffers->index_buf)
1646                         glDeleteBuffersARB(1, &buffers->index_buf);
1647
1648                 MEM_freeN(buffers);
1649         }
1650 }
1651