Blender  V2.59
gpu_buffers.c
Go to the documentation of this file.
00001 /*
00002  * $Id: gpu_buffers.c 38866 2011-07-31 02:24:06Z nicholasbishop $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. The Blender
00010  * Foundation also sells licenses for use in proprietary software under
00011  * the Blender License.  See http://www.blender.org/BL/ for information
00012  * about this.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software Foundation,
00021  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  *
00023  * The Original Code is Copyright (C) 2005 Blender Foundation.
00024  * All rights reserved.
00025  *
00026  * The Original Code is: all of this file.
00027  *
00028  * Contributor(s): Brecht Van Lommel.
00029  *
00030  * ***** END GPL LICENSE BLOCK *****
00031  */
00032 
00038 #include <limits.h>
00039 #include <stddef.h>
00040 #include <string.h>
00041 
00042 #include "GL/glew.h"
00043 
00044 #include "MEM_guardedalloc.h"
00045 
00046 #include "BLI_math.h"
00047 #include "BLI_utildefines.h"
00048 #include "BLI_ghash.h"
00049 #include "BLI_threads.h"
00050 
00051 #include "DNA_meshdata_types.h"
00052 
00053 #include "BKE_DerivedMesh.h"
00054 
00055 #include "DNA_userdef_types.h"
00056 
00057 #include "GPU_buffers.h"
00058 
00059 typedef enum {
00060         GPU_BUFFER_VERTEX_STATE = 1,
00061         GPU_BUFFER_NORMAL_STATE = 2,
00062         GPU_BUFFER_TEXCOORD_STATE = 4,
00063         GPU_BUFFER_COLOR_STATE = 8,
00064         GPU_BUFFER_ELEMENT_STATE = 16,
00065 } GPUBufferState;
00066 
00067 #define MAX_GPU_ATTRIB_DATA 32
00068 
00069 /* material number is an 16-bit short and the range of short is from -16383 to 16383 (assume material number is non-negative) */
00070 #define MAX_MATERIALS 16384
00071 
00072 /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
00073 static int useVBOs = -1;
00074 static GPUBufferState GLStates = 0;
00075 static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
00076 
00077 /* stores recently-deleted buffers so that new buffers won't have to
00078    be recreated as often
00079 
00080    only one instance of this pool is created, stored in
00081    gpu_buffer_pool
00082 
00083    note that the number of buffers in the pool is usually limited to
00084    MAX_FREE_GPU_BUFFERS, but this limit may be exceeded temporarily
00085    when a GPUBuffer is released outside the main thread; due to OpenGL
00086    restrictions it cannot be immediately released
00087  */
00088 typedef struct GPUBufferPool {
00089         /* number of allocated buffers stored */
00090         int totbuf;
00091         /* actual allocated length of the array */
00092         int maxsize;
00093         GPUBuffer **buffers;
00094 } GPUBufferPool;
00095 #define MAX_FREE_GPU_BUFFERS 8
00096 
00097 /* create a new GPUBufferPool */
00098 static GPUBufferPool *gpu_buffer_pool_new(void)
00099 {
00100         GPUBufferPool *pool;
00101 
00102         /* enable VBOs if supported */
00103         if(useVBOs == -1)
00104                 useVBOs = (GLEW_ARB_vertex_buffer_object ? 1 : 0);
00105 
00106         pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer");
00107 
00108         pool->maxsize = MAX_FREE_GPU_BUFFERS;
00109         pool->buffers = MEM_callocN(sizeof(GPUBuffer*)*pool->maxsize,
00110                                     "GPUBuffer.buffers");
00111 
00112         return pool;
00113 }
00114 
00115 /* remove a GPUBuffer from the pool (does not free the GPUBuffer) */
00116 static void gpu_buffer_pool_remove_index(GPUBufferPool *pool, int index)
00117 {
00118         int i;
00119 
00120         if(!pool || index < 0 || index >= pool->totbuf)
00121                 return;
00122 
00123         /* shift entries down, overwriting the buffer at `index' */
00124         for(i = index; i < pool->totbuf - 1; i++)
00125                 pool->buffers[i] = pool->buffers[i+1];
00126 
00127         /* clear the last entry */
00128         if(pool->totbuf > 0)
00129                 pool->buffers[pool->totbuf - 1] = NULL;
00130 
00131         pool->totbuf--;
00132 }
00133 
00134 /* delete the last entry in the pool */
00135 static void gpu_buffer_pool_delete_last(GPUBufferPool *pool)
00136 {
00137         GPUBuffer *last;
00138 
00139         if(pool->totbuf <= 0)
00140                 return;
00141 
00142         /* get the last entry */
00143         if(!(last = pool->buffers[pool->totbuf - 1]))
00144                 return;
00145 
00146         /* delete the buffer's data */
00147         if(useVBOs)
00148                 glDeleteBuffersARB(1, &last->id);
00149         else
00150                 MEM_freeN(last->pointer);
00151 
00152         /* delete the buffer and remove from pool */
00153         MEM_freeN(last);
00154         pool->totbuf--;
00155         pool->buffers[pool->totbuf] = NULL;
00156 }
00157 
00158 /* free a GPUBufferPool; also frees the data in the pool's
00159    GPUBuffers */
00160 static void gpu_buffer_pool_free(GPUBufferPool *pool)
00161 {
00162         if(!pool)
00163                 return;
00164         
00165         while(pool->totbuf)
00166                 gpu_buffer_pool_delete_last(pool);
00167 
00168         MEM_freeN(pool->buffers);
00169         MEM_freeN(pool);
00170 }
00171 
00172 static GPUBufferPool *gpu_buffer_pool = NULL;
00173 static GPUBufferPool *gpu_get_global_buffer_pool(void)
00174 {
00175         /* initialize the pool */
00176         if(!gpu_buffer_pool)
00177                 gpu_buffer_pool = gpu_buffer_pool_new();
00178 
00179         return gpu_buffer_pool;
00180 }
00181 
00182 void GPU_global_buffer_pool_free(void)
00183 {
00184         gpu_buffer_pool_free(gpu_buffer_pool);
00185         gpu_buffer_pool = NULL;
00186 }
00187 
00188 /* get a GPUBuffer of at least `size' bytes; uses one from the buffer
00189    pool if possible, otherwise creates a new one */
00190 GPUBuffer *GPU_buffer_alloc(int size)
00191 {
00192         GPUBufferPool *pool;
00193         GPUBuffer *buf;
00194         int i, bufsize, bestfit = -1;
00195 
00196         pool = gpu_get_global_buffer_pool();
00197 
00198         /* not sure if this buffer pool code has been profiled much,
00199            seems to me that the graphics driver and system memory
00200            management might do this stuff anyway. --nicholas
00201         */
00202 
00203         /* check the global buffer pool for a recently-deleted buffer
00204            that is at least as big as the request, but not more than
00205            twice as big */
00206         for(i = 0; i < pool->totbuf; i++) {
00207                 bufsize = pool->buffers[i]->size;
00208 
00209                 /* check for an exact size match */
00210                 if(bufsize == size) {
00211                         bestfit = i;
00212                         break;
00213                 }
00214                 /* smaller buffers won't fit data and buffers at least
00215                    twice as big are a waste of memory */
00216                 else if(bufsize > size && size > (bufsize / 2)) {
00217                         /* is it closer to the required size than the
00218                            last appropriate buffer found. try to save
00219                            memory */
00220                         if(bestfit == -1 || pool->buffers[bestfit]->size > bufsize) {
00221                                 bestfit = i;
00222                         }
00223                 }
00224         }
00225 
00226         /* if an acceptable buffer was found in the pool, remove it
00227            from the pool and return it */
00228         if(bestfit != -1) {
00229                 buf = pool->buffers[bestfit];
00230                 gpu_buffer_pool_remove_index(pool, bestfit);
00231                 return buf;
00232         }
00233 
00234         /* no acceptable buffer found in the pool, create a new one */
00235         buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer");
00236         buf->size = size;
00237 
00238         if(useVBOs == 1) {
00239                 /* create a new VBO and initialize it to the requested
00240                    size */
00241                 glGenBuffersARB(1, &buf->id);
00242                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buf->id);
00243                 glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB);
00244                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
00245         }
00246         else {
00247                 buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
00248                 
00249                 /* purpose of this seems to be dealing with
00250                    out-of-memory errors? looks a bit iffy to me
00251                    though, at least on Linux I expect malloc() would
00252                    just overcommit. --nicholas */
00253                 while(!buf->pointer && pool->totbuf > 0) {
00254                         gpu_buffer_pool_delete_last(pool);
00255                         buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
00256                 }
00257                 if(!buf->pointer)
00258                         return NULL;
00259         }
00260 
00261         return buf;
00262 }
00263 
00264 /* release a GPUBuffer; does not free the actual buffer or its data,
00265    but rather moves it to the pool of recently-free'd buffers for
00266    possible re-use*/
00267 void GPU_buffer_free(GPUBuffer *buffer)
00268 {
00269         GPUBufferPool *pool;
00270         int i;
00271 
00272         if(!buffer)
00273                 return;
00274 
00275         pool = gpu_get_global_buffer_pool();
00276 
00277         /* free the last used buffer in the queue if no more space, but only
00278            if we are in the main thread. for e.g. rendering or baking it can
00279            happen that we are in other thread and can't call OpenGL, in that
00280            case cleanup will be done GPU_buffer_pool_free_unused */
00281         if(BLI_thread_is_main()) {
00282                 /* in main thread, safe to decrease size of pool back
00283                    down to MAX_FREE_GPU_BUFFERS */
00284                 while(pool->totbuf >= MAX_FREE_GPU_BUFFERS)
00285                         gpu_buffer_pool_delete_last(pool);
00286         }
00287         else {
00288                 /* outside of main thread, can't safely delete the
00289                    buffer, so increase pool size */
00290                 if(pool->maxsize == pool->totbuf) {
00291                         pool->maxsize += MAX_FREE_GPU_BUFFERS;
00292                         pool->buffers = MEM_reallocN(pool->buffers,
00293                                                      sizeof(GPUBuffer*) * pool->maxsize);
00294                 }
00295         }
00296 
00297         /* shift pool entries up by one */
00298         for(i = pool->totbuf; i > 0; i--)
00299                 pool->buffers[i] = pool->buffers[i-1];
00300 
00301         /* insert the buffer into the beginning of the pool */
00302         pool->buffers[0] = buffer;
00303         pool->totbuf++;
00304 }
00305 
00306 typedef struct GPUVertPointLink {
00307         struct GPUVertPointLink *next;
00308         /* -1 means uninitialized */
00309         int point_index;
00310 } GPUVertPointLink;
00311 
00312 /* add a new point to the list of points related to a particular
00313    vertex */
00314 static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
00315 {
00316         GPUVertPointLink *lnk;
00317 
00318         lnk = &gdo->vert_points[vert_index];
00319 
00320         /* if first link is in use, add a new link at the end */
00321         if(lnk->point_index != -1) {
00322                 /* get last link */
00323                 for(; lnk->next; lnk = lnk->next);
00324 
00325                 /* add a new link from the pool */
00326                 lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
00327                 gdo->vert_points_usage++;
00328         }
00329 
00330         lnk->point_index = point_index;
00331 }
00332 
00333 /* update the vert_points and triangle_to_mface fields with a new
00334    triangle */
00335 static void gpu_drawobject_add_triangle(GPUDrawObject *gdo,
00336                                         int base_point_index,
00337                                         int face_index,
00338                                         int v1, int v2, int v3)
00339 {
00340         int i, v[3] = {v1, v2, v3};
00341         for(i = 0; i < 3; i++)
00342                 gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i);
00343         gdo->triangle_to_mface[base_point_index / 3] = face_index;
00344 }
00345 
00346 /* for each vertex, build a list of points related to it; these lists
00347    are stored in an array sized to the number of vertices */
00348 static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface)
00349 {
00350         GPUBufferMaterial *mat;
00351         int i, mat_orig_to_new[MAX_MATERIALS];
00352 
00353         /* allocate the array and space for links */
00354         gdo->vert_points = MEM_callocN(sizeof(GPUVertPointLink) * gdo->totvert,
00355                                        "GPUDrawObject.vert_points");
00356         gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point,
00357                                               "GPUDrawObject.vert_points_mem");
00358         gdo->vert_points_usage = 0;
00359 
00360         /* build a map from the original material indices to the new
00361            GPUBufferMaterial indices */
00362         for(i = 0; i < gdo->totmaterial; i++)
00363                 mat_orig_to_new[gdo->materials[i].mat_nr] = i;
00364 
00365         /* -1 indicates the link is not yet used */
00366         for(i = 0; i < gdo->totvert; i++)
00367                 gdo->vert_points[i].point_index = -1;
00368 
00369         for(i = 0; i < totface; i++, f++) {
00370                 mat = &gdo->materials[mat_orig_to_new[f->mat_nr]];
00371 
00372                 /* add triangle */
00373                 gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
00374                                             i, f->v1, f->v2, f->v3);
00375                 mat->totpoint += 3;
00376 
00377                 /* add second triangle for quads */
00378                 if(f->v4) {
00379                         gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
00380                                                     i, f->v3, f->v4, f->v1);
00381                         mat->totpoint += 3;
00382                 }
00383         }
00384 
00385         /* map any unused vertices to loose points */
00386         for(i = 0; i < gdo->totvert; i++) {
00387                 if(gdo->vert_points[i].point_index == -1) {
00388                         gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point;
00389                         gdo->tot_loose_point++;
00390                 }
00391         }
00392 }
00393 
00394 /* see GPUDrawObject's structure definition for a description of the
00395    data being initialized here */
00396 GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
00397 {
00398         GPUDrawObject *gdo;
00399         MFace *mface;
00400         int points_per_mat[MAX_MATERIALS];
00401         int i, curmat, curpoint, totface;
00402 
00403         mface = dm->getFaceArray(dm);
00404         totface= dm->getNumFaces(dm);
00405 
00406         /* get the number of points used by each material, treating
00407            each quad as two triangles */
00408         memset(points_per_mat, 0, sizeof(int)*MAX_MATERIALS);
00409         for(i = 0; i < totface; i++)
00410                 points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3;
00411 
00412         /* create the GPUDrawObject */
00413         gdo = MEM_callocN(sizeof(GPUDrawObject),"GPUDrawObject");
00414         gdo->totvert = dm->getNumVerts(dm);
00415         gdo->totedge = dm->getNumEdges(dm);
00416 
00417         /* count the number of materials used by this DerivedMesh */
00418         for(i = 0; i < MAX_MATERIALS; i++) {
00419                 if(points_per_mat[i] > 0)
00420                         gdo->totmaterial++;
00421         }
00422 
00423         /* allocate an array of materials used by this DerivedMesh */
00424         gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
00425                                      "GPUDrawObject.materials");
00426 
00427         /* initialize the materials array */
00428         for(i = 0, curmat = 0, curpoint = 0; i < MAX_MATERIALS; i++) {
00429                 if(points_per_mat[i] > 0) {
00430                         gdo->materials[curmat].start = curpoint;
00431                         gdo->materials[curmat].totpoint = 0;
00432                         gdo->materials[curmat].mat_nr = i;
00433 
00434                         curpoint += points_per_mat[i];
00435                         curmat++;
00436                 }
00437         }
00438 
00439         /* store total number of points used for triangles */
00440         gdo->tot_triangle_point = curpoint;
00441 
00442         gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3),
00443                                      "GPUDrawObject.triangle_to_mface");
00444 
00445         gpu_drawobject_init_vert_points(gdo, mface, totface);
00446 
00447         return gdo;
00448 }
00449 
00450 void GPU_drawobject_free(DerivedMesh *dm)
00451 {
00452         GPUDrawObject *gdo;
00453 
00454         if(!dm || !(gdo = dm->drawObject))
00455                 return;
00456 
00457         MEM_freeN(gdo->materials);
00458         MEM_freeN(gdo->triangle_to_mface);
00459         MEM_freeN(gdo->vert_points);
00460         MEM_freeN(gdo->vert_points_mem);
00461         GPU_buffer_free(gdo->points);
00462         GPU_buffer_free(gdo->normals);
00463         GPU_buffer_free(gdo->uv);
00464         GPU_buffer_free(gdo->colors);
00465         GPU_buffer_free(gdo->edges);
00466         GPU_buffer_free(gdo->uvedges);
00467 
00468         MEM_freeN(gdo);
00469         dm->drawObject = NULL;
00470 }
00471 
00472 typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
00473                                   int *mat_orig_to_new, void *user_data);
00474 
00475 static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
00476                                    int vector_size, int size, GLenum target,
00477                                    void *user, GPUBufferCopyFunc copy_f)
00478 {
00479         GPUBufferPool *pool;
00480         GPUBuffer *buffer;
00481         float *varray;
00482         int mat_orig_to_new[MAX_MATERIALS];
00483         int *cur_index_per_mat;
00484         int i;
00485         int success;
00486         GLboolean uploaded;
00487 
00488         pool = gpu_get_global_buffer_pool();
00489 
00490         /* alloc a GPUBuffer; fall back to legacy mode on failure */
00491         if(!(buffer = GPU_buffer_alloc(size)))
00492                 dm->drawObject->legacy = 1;
00493 
00494         /* nothing to do for legacy mode */
00495         if(dm->drawObject->legacy)
00496                 return 0;
00497 
00498         cur_index_per_mat = MEM_mallocN(sizeof(int)*object->totmaterial,
00499                                         "GPU_buffer_setup.cur_index_per_mat");
00500         for(i = 0; i < object->totmaterial; i++) {
00501                 /* for each material, the current index to copy data to */
00502                 cur_index_per_mat[i] = object->materials[i].start * vector_size;
00503 
00504                 /* map from original material index to new
00505                    GPUBufferMaterial index */
00506                 mat_orig_to_new[object->materials[i].mat_nr] = i;
00507         }
00508 
00509         if(useVBOs) {
00510                 success = 0;
00511 
00512                 while(!success) {
00513                         /* bind the buffer and discard previous data,
00514                            avoids stalling gpu */
00515                         glBindBufferARB(target, buffer->id);
00516                         glBufferDataARB(target, buffer->size, 0, GL_STATIC_DRAW_ARB);
00517 
00518                         /* attempt to map the buffer */
00519                         if(!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) {
00520                                 /* failed to map the buffer; delete it */
00521                                 GPU_buffer_free(buffer);
00522                                 gpu_buffer_pool_delete_last(pool);
00523                                 buffer= NULL;
00524 
00525                                 /* try freeing an entry from the pool
00526                                    and reallocating the buffer */
00527                                 if(pool->totbuf > 0) {
00528                                         gpu_buffer_pool_delete_last(pool);
00529                                         buffer = GPU_buffer_alloc(size);
00530                                 }
00531 
00532                                 /* allocation still failed; fall back
00533                                    to legacy mode */
00534                                 if(!buffer) {
00535                                         dm->drawObject->legacy = 1;
00536                                         success = 1;
00537                                 }
00538                         }
00539                         else {
00540                                 success = 1;
00541                         }
00542                 }
00543 
00544                 /* check legacy fallback didn't happen */
00545                 if(dm->drawObject->legacy == 0) {
00546                         uploaded = GL_FALSE;
00547                         /* attempt to upload the data to the VBO */
00548                         while(uploaded == GL_FALSE) {
00549                                 (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
00550                                 /* glUnmapBuffer returns GL_FALSE if
00551                                    the data store is corrupted; retry
00552                                    in that case */
00553                                 uploaded = glUnmapBufferARB(target);
00554                         }
00555                 }
00556                 glBindBufferARB(target, 0);
00557         }
00558         else {
00559                 /* VBO not supported, use vertex array fallback */
00560                 if(buffer->pointer) {
00561                         varray = buffer->pointer;
00562                         (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
00563                 }
00564                 else {
00565                         dm->drawObject->legacy = 1;
00566                 }
00567         }
00568 
00569         MEM_freeN(cur_index_per_mat);
00570 
00571         return buffer;
00572 }
00573 
00574 static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
00575 {
00576         MVert *mvert;
00577         MFace *f;
00578         int i, j, start, totface;
00579 
00580         mvert = dm->getVertArray(dm);
00581         f = dm->getFaceArray(dm);
00582 
00583         totface= dm->getNumFaces(dm);
00584         for(i = 0; i < totface; i++, f++) {
00585                 start = index[mat_orig_to_new[f->mat_nr]];
00586 
00587                 /* v1 v2 v3 */
00588                 copy_v3_v3(&varray[start], mvert[f->v1].co);
00589                 copy_v3_v3(&varray[start+3], mvert[f->v2].co);
00590                 copy_v3_v3(&varray[start+6], mvert[f->v3].co);
00591                 index[mat_orig_to_new[f->mat_nr]] += 9;
00592 
00593                 if(f->v4) {
00594                         /* v3 v4 v1 */
00595                         copy_v3_v3(&varray[start+9], mvert[f->v3].co);
00596                         copy_v3_v3(&varray[start+12], mvert[f->v4].co);
00597                         copy_v3_v3(&varray[start+15], mvert[f->v1].co);
00598                         index[mat_orig_to_new[f->mat_nr]] += 9;
00599                 }
00600         }
00601 
00602         /* copy loose points */
00603         j = dm->drawObject->tot_triangle_point*3;
00604         for(i = 0; i < dm->drawObject->totvert; i++) {
00605                 if(dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) {
00606                         copy_v3_v3(&varray[j],mvert[i].co);
00607                         j+=3;
00608                 }
00609         }
00610 }
00611 
00612 static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
00613 {
00614         int i, totface;
00615         int start;
00616         float f_no[3];
00617 
00618         float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
00619         MVert *mvert = dm->getVertArray(dm);
00620         MFace *f = dm->getFaceArray(dm);
00621 
00622         totface= dm->getNumFaces(dm);
00623         for(i = 0; i < totface; i++, f++) {
00624                 const int smoothnormal = (f->flag & ME_SMOOTH);
00625 
00626                 start = index[mat_orig_to_new[f->mat_nr]];
00627                 index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9;
00628 
00629                 if(smoothnormal) {
00630                         /* copy vertex normal */
00631                         normal_short_to_float_v3(&varray[start], mvert[f->v1].no);
00632                         normal_short_to_float_v3(&varray[start+3], mvert[f->v2].no);
00633                         normal_short_to_float_v3(&varray[start+6], mvert[f->v3].no);
00634 
00635                         if(f->v4) {
00636                                 normal_short_to_float_v3(&varray[start+9], mvert[f->v3].no);
00637                                 normal_short_to_float_v3(&varray[start+12], mvert[f->v4].no);
00638                                 normal_short_to_float_v3(&varray[start+15], mvert[f->v1].no);
00639                         }
00640                 }
00641                 else if(nors) {
00642                         /* copy cached face normal */
00643                         copy_v3_v3(&varray[start], &nors[i*3]);
00644                         copy_v3_v3(&varray[start+3], &nors[i*3]);
00645                         copy_v3_v3(&varray[start+6], &nors[i*3]);
00646 
00647                         if(f->v4) {
00648                                 copy_v3_v3(&varray[start+9], &nors[i*3]);
00649                                 copy_v3_v3(&varray[start+12], &nors[i*3]);
00650                                 copy_v3_v3(&varray[start+15], &nors[i*3]);
00651                         }
00652                 }
00653                 else {
00654                         /* calculate face normal */
00655                         if(f->v4)
00656                                 normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co);
00657                         else
00658                                 normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co);
00659 
00660                         copy_v3_v3(&varray[start], f_no);
00661                         copy_v3_v3(&varray[start+3], f_no);
00662                         copy_v3_v3(&varray[start+6], f_no);
00663 
00664                         if(f->v4) {
00665                                 copy_v3_v3(&varray[start+9], f_no);
00666                                 copy_v3_v3(&varray[start+12], f_no);
00667                                 copy_v3_v3(&varray[start+15], f_no);
00668                         }
00669                 }
00670         }
00671 }
00672 
00673 static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
00674 {
00675         int start;
00676         int i, totface;
00677 
00678         MTFace *mtface;
00679         MFace *f;
00680 
00681         if(!(mtface = DM_get_face_data_layer(dm, CD_MTFACE)))
00682                 return;
00683         f = dm->getFaceArray(dm);
00684                 
00685         totface = dm->getNumFaces(dm);
00686         for(i = 0; i < totface; i++, f++) {
00687                 start = index[mat_orig_to_new[f->mat_nr]];
00688 
00689                 /* v1 v2 v3 */
00690                 copy_v2_v2(&varray[start],mtface[i].uv[0]);
00691                 copy_v2_v2(&varray[start+2],mtface[i].uv[1]);
00692                 copy_v2_v2(&varray[start+4],mtface[i].uv[2]);
00693                 index[mat_orig_to_new[f->mat_nr]] += 6;
00694 
00695                 if(f->v4) {
00696                         /* v3 v4 v1 */
00697                         copy_v2_v2(&varray[start+6],mtface[i].uv[2]);
00698                         copy_v2_v2(&varray[start+8],mtface[i].uv[3]);
00699                         copy_v2_v2(&varray[start+10],mtface[i].uv[0]);
00700                         index[mat_orig_to_new[f->mat_nr]] += 6;
00701                 }
00702         }
00703 }
00704 
00705 
00706 static void GPU_buffer_copy_color3(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
00707 {
00708         int i, totface;
00709         unsigned char *varray = (unsigned char *)varray_;
00710         unsigned char *mcol = (unsigned char *)user;
00711         MFace *f = dm->getFaceArray(dm);
00712 
00713         totface= dm->getNumFaces(dm);
00714         for(i=0; i < totface; i++, f++) {
00715                 int start = index[mat_orig_to_new[f->mat_nr]];
00716 
00717                 /* v1 v2 v3 */
00718                 VECCOPY(&varray[start], &mcol[i*12]);
00719                 VECCOPY(&varray[start+3], &mcol[i*12+3]);
00720                 VECCOPY(&varray[start+6], &mcol[i*12+6]);
00721                 index[mat_orig_to_new[f->mat_nr]] += 9;
00722 
00723                 if(f->v4) {
00724                         /* v3 v4 v1 */
00725                         VECCOPY(&varray[start+9], &mcol[i*12+6]);
00726                         VECCOPY(&varray[start+12], &mcol[i*12+9]);
00727                         VECCOPY(&varray[start+15], &mcol[i*12]);
00728                         index[mat_orig_to_new[f->mat_nr]] += 9;
00729                 }
00730         }
00731 }
00732 
00733 static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
00734 {
00735         v[0] = col[3];
00736         v[1] = col[2];
00737         v[2] = col[1];
00738 }
00739 
00740 /* treat varray_ as an array of MCol, four MCol's per face */
00741 static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
00742 {
00743         int i, totface;
00744         unsigned char *varray = (unsigned char *)varray_;
00745         unsigned char *mcol = (unsigned char *)user;
00746         MFace *f = dm->getFaceArray(dm);
00747 
00748         totface= dm->getNumFaces(dm);
00749         for(i=0; i < totface; i++, f++) {
00750                 int start = index[mat_orig_to_new[f->mat_nr]];
00751 
00752                 /* v1 v2 v3 */
00753                 copy_mcol_uc3(&varray[start], &mcol[i*16]);
00754                 copy_mcol_uc3(&varray[start+3], &mcol[i*16+4]);
00755                 copy_mcol_uc3(&varray[start+6], &mcol[i*16+8]);
00756                 index[mat_orig_to_new[f->mat_nr]] += 9;
00757 
00758                 if(f->v4) {
00759                         /* v3 v4 v1 */
00760                         copy_mcol_uc3(&varray[start+9], &mcol[i*16+8]);
00761                         copy_mcol_uc3(&varray[start+12], &mcol[i*16+12]);
00762                         copy_mcol_uc3(&varray[start+15], &mcol[i*16]);
00763                         index[mat_orig_to_new[f->mat_nr]] += 9;
00764                 }
00765         }
00766 }
00767 
00768 static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
00769 {
00770         MEdge *medge;
00771         unsigned int *varray = (unsigned int *)varray_;
00772         int i, totedge;
00773  
00774         medge = dm->getEdgeArray(dm);
00775         totedge = dm->getNumEdges(dm);
00776 
00777         for(i = 0; i < totedge; i++, medge++) {
00778                 varray[i*2] = dm->drawObject->vert_points[medge->v1].point_index;
00779                 varray[i*2+1] = dm->drawObject->vert_points[medge->v2].point_index;
00780         }
00781 }
00782 
00783 static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
00784 {
00785         MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
00786         int i, j=0;
00787 
00788         if(!tf)
00789                 return;
00790 
00791         for(i = 0; i < dm->numFaceData; i++, tf++) {
00792                 MFace mf;
00793                 dm->getFace(dm,i,&mf);
00794 
00795                 copy_v2_v2(&varray[j],tf->uv[0]);
00796                 copy_v2_v2(&varray[j+2],tf->uv[1]);
00797 
00798                 copy_v2_v2(&varray[j+4],tf->uv[1]);
00799                 copy_v2_v2(&varray[j+6],tf->uv[2]);
00800 
00801                 if(!mf.v4) {
00802                         copy_v2_v2(&varray[j+8],tf->uv[2]);
00803                         copy_v2_v2(&varray[j+10],tf->uv[0]);
00804                         j+=12;
00805                 } else {
00806                         copy_v2_v2(&varray[j+8],tf->uv[2]);
00807                         copy_v2_v2(&varray[j+10],tf->uv[3]);
00808 
00809                         copy_v2_v2(&varray[j+12],tf->uv[3]);
00810                         copy_v2_v2(&varray[j+14],tf->uv[0]);
00811                         j+=16;
00812                 }
00813         }
00814 }
00815 
00816 /* get the DerivedMesh's MCols; choose (in decreasing order of
00817    preference) from CD_ID_MCOL, CD_WEIGHT_MCOL, or CD_MCOL */
00818 static MCol *gpu_buffer_color_type(DerivedMesh *dm)
00819 {
00820         MCol *c;
00821         int type;
00822 
00823         type = CD_ID_MCOL;
00824         c = DM_get_face_data_layer(dm, type);
00825         if(!c) {
00826                 type = CD_WEIGHT_MCOL;
00827                 c = DM_get_face_data_layer(dm, type);
00828                 if(!c) {
00829                         type = CD_MCOL;
00830                         c = DM_get_face_data_layer(dm, type);
00831                 }
00832         }
00833 
00834         dm->drawObject->colType = type;
00835         return c;
00836 }
00837 
00838 typedef enum {
00839         GPU_BUFFER_VERTEX = 0,
00840         GPU_BUFFER_NORMAL,
00841         GPU_BUFFER_COLOR,
00842         GPU_BUFFER_UV,
00843         GPU_BUFFER_EDGE,
00844         GPU_BUFFER_UVEDGE,
00845 } GPUBufferType;
00846 
00847 typedef struct {
00848         GPUBufferCopyFunc copy;
00849         GLenum gl_buffer_type;
00850         int vector_size;
00851 } GPUBufferTypeSettings;
00852 
00853 const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
00854         {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3},
00855         {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3},
00856         {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3},
00857         {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2},
00858         {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
00859         {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
00860 };
00861 
00862 /* get the GPUDrawObject buffer associated with a type */
00863 static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type)
00864 {
00865         switch(type) {
00866         case GPU_BUFFER_VERTEX:
00867                 return &gdo->points;
00868         case GPU_BUFFER_NORMAL:
00869                 return &gdo->normals;
00870         case GPU_BUFFER_COLOR:
00871                 return &gdo->colors;
00872         case GPU_BUFFER_UV:
00873                 return &gdo->uv;
00874         case GPU_BUFFER_EDGE:
00875                 return &gdo->edges;
00876         case GPU_BUFFER_UVEDGE:
00877                 return &gdo->uvedges;
00878         default:
00879                 return NULL;
00880         }
00881 }
00882 
00883 /* get the amount of space to allocate for a buffer of a particular type */
00884 static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
00885 {
00886         switch(type) {
00887         case GPU_BUFFER_VERTEX:
00888                 return sizeof(float)*3 * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point);
00889         case GPU_BUFFER_NORMAL:
00890                 return sizeof(float)*3*dm->drawObject->tot_triangle_point;
00891         case GPU_BUFFER_COLOR:
00892                 return sizeof(char)*3*dm->drawObject->tot_triangle_point;
00893         case GPU_BUFFER_UV:
00894                 return sizeof(float)*2*dm->drawObject->tot_triangle_point;
00895         case GPU_BUFFER_EDGE:
00896                 return sizeof(int)*2*dm->drawObject->totedge;
00897         case GPU_BUFFER_UVEDGE:
00898                 /* each face gets 3 points, 3 edges per triangle, and
00899                    each edge has its own, non-shared coords, so each
00900                    tri corner needs minimum of 4 floats, quads used
00901                    less so here we can over allocate and assume all
00902                    tris. */
00903                 return sizeof(float) * dm->drawObject->tot_triangle_point;
00904         default:
00905                 return -1;
00906         }
00907 }
00908 
00909 /* call gpu_buffer_setup with settings for a particular type of buffer */
00910 static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
00911 {
00912         const GPUBufferTypeSettings *ts;
00913         void *user_data = NULL;
00914         GPUBuffer *buf;
00915 
00916         ts = &gpu_buffer_type_settings[type];
00917 
00918         /* special handling for MCol and UV buffers */
00919         if(type == GPU_BUFFER_COLOR) {
00920                 if(!(user_data = gpu_buffer_color_type(dm)))
00921                         return NULL;
00922         }
00923         else if(type == GPU_BUFFER_UV) {
00924                 if(!DM_get_face_data_layer(dm, CD_MTFACE))
00925                         return NULL;
00926         }
00927 
00928         buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size,
00929                                gpu_buffer_size_from_type(dm, type),
00930                                ts->gl_buffer_type, user_data, ts->copy);
00931 
00932         return buf;
00933 }
00934 
00935 /* get the buffer of `type', initializing the GPUDrawObject and
00936    buffer if needed */
00937 static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
00938 {
00939         GPUBuffer **buf;
00940         
00941         if(!dm->drawObject)
00942                 dm->drawObject = GPU_drawobject_new(dm);
00943 
00944         buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
00945         if(!(*buf))
00946                 *buf = gpu_buffer_setup_type(dm, type);
00947 
00948         return *buf;
00949 }
00950 
00951 void GPU_vertex_setup(DerivedMesh *dm)
00952 {
00953         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
00954                 return;
00955 
00956         glEnableClientState(GL_VERTEX_ARRAY);
00957         if(useVBOs) {
00958                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
00959                 glVertexPointer(3, GL_FLOAT, 0, 0);
00960         }
00961         else {
00962                 glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
00963         }
00964         
00965         GLStates |= GPU_BUFFER_VERTEX_STATE;
00966 }
00967 
00968 void GPU_normal_setup(DerivedMesh *dm)
00969 {
00970         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL))
00971                 return;
00972 
00973         glEnableClientState(GL_NORMAL_ARRAY);
00974         if(useVBOs) {
00975                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id);
00976                 glNormalPointer(GL_FLOAT, 0, 0);
00977         }
00978         else {
00979                 glNormalPointer(GL_FLOAT, 0, dm->drawObject->normals->pointer);
00980         }
00981 
00982         GLStates |= GPU_BUFFER_NORMAL_STATE;
00983 }
00984 
00985 void GPU_uv_setup(DerivedMesh *dm)
00986 {
00987         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_UV))
00988                 return;
00989 
00990         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00991         if(useVBOs) {
00992                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id);
00993                 glTexCoordPointer(2, GL_FLOAT, 0, 0);
00994         }
00995         else {
00996                 glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer);
00997         }
00998 
00999         GLStates |= GPU_BUFFER_TEXCOORD_STATE;
01000 }
01001 
01002 void GPU_color_setup(DerivedMesh *dm)
01003 {
01004         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR))
01005                 return;
01006 
01007         glEnableClientState(GL_COLOR_ARRAY);
01008         if(useVBOs) {
01009                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id);
01010                 glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
01011         }
01012         else {
01013                 glColorPointer(3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer);
01014         }
01015 
01016         GLStates |= GPU_BUFFER_COLOR_STATE;
01017 }
01018 
01019 void GPU_edge_setup(DerivedMesh *dm)
01020 {
01021         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE))
01022                 return;
01023 
01024         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
01025                 return;
01026 
01027         glEnableClientState(GL_VERTEX_ARRAY);
01028         if(useVBOs) {
01029                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
01030                 glVertexPointer(3, GL_FLOAT, 0, 0);
01031         }
01032         else {
01033                 glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
01034         }
01035         
01036         GLStates |= GPU_BUFFER_VERTEX_STATE;
01037 
01038         if(useVBOs)
01039                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id);
01040 
01041         GLStates |= GPU_BUFFER_ELEMENT_STATE;
01042 }
01043 
01044 void GPU_uvedge_setup(DerivedMesh *dm)
01045 {
01046         if(!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE))
01047                 return;
01048 
01049         glEnableClientState(GL_VERTEX_ARRAY);
01050         if(useVBOs) {
01051                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id);
01052                 glVertexPointer(2, GL_FLOAT, 0, 0);
01053         }
01054         else {
01055                 glVertexPointer(2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer);
01056         }
01057         
01058         GLStates |= GPU_BUFFER_VERTEX_STATE;
01059 }
01060 
01061 static int GPU_typesize(int type) {
01062         switch(type) {
01063         case GL_FLOAT:
01064                 return sizeof(float);
01065         case GL_INT:
01066                 return sizeof(int);
01067         case GL_UNSIGNED_INT:
01068                 return sizeof(unsigned int);
01069         case GL_BYTE:
01070                 return sizeof(char);
01071         case GL_UNSIGNED_BYTE:
01072                 return sizeof(unsigned char);
01073         default:
01074                 return 0;
01075         }
01076 }
01077 
01078 int GPU_attrib_element_size(GPUAttrib data[], int numdata) {
01079         int i, elementsize = 0;
01080 
01081         for(i = 0; i < numdata; i++) {
01082                 int typesize = GPU_typesize(data[i].type);
01083                 if(typesize != 0)
01084                         elementsize += typesize*data[i].size;
01085         }
01086         return elementsize;
01087 }
01088 
01089 void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata) {
01090         int i;
01091         int elementsize;
01092         intptr_t offset = 0;
01093 
01094         for(i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
01095                 if(attribData[i].index != -1) {
01096                         glDisableVertexAttribArrayARB(attribData[i].index);
01097                 }
01098                 else
01099                         break;
01100         }
01101         elementsize = GPU_attrib_element_size(data, numdata);
01102 
01103         if(useVBOs) {
01104                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
01105                 for(i = 0; i < numdata; i++) {
01106                         glEnableVertexAttribArrayARB(data[i].index);
01107                         glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
01108                                                  GL_FALSE, elementsize, (void *)offset);
01109                         offset += data[i].size*GPU_typesize(data[i].type);
01110 
01111                         attribData[i].index = data[i].index;
01112                         attribData[i].size = data[i].size;
01113                         attribData[i].type = data[i].type;
01114                 }
01115                 attribData[numdata].index = -1;
01116         }
01117         else {
01118                 for(i = 0; i < numdata; i++) {
01119                         glEnableVertexAttribArrayARB(data[i].index);
01120                         glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
01121                                                  GL_FALSE, elementsize, (char *)buffer->pointer + offset);
01122                         offset += data[i].size*GPU_typesize(data[i].type);
01123                 }
01124         }
01125 }
01126 
01127 
01128 void GPU_buffer_unbind(void)
01129 {
01130         int i;
01131 
01132         if(GLStates & GPU_BUFFER_VERTEX_STATE)
01133                 glDisableClientState(GL_VERTEX_ARRAY);
01134         if(GLStates & GPU_BUFFER_NORMAL_STATE)
01135                 glDisableClientState(GL_NORMAL_ARRAY);
01136         if(GLStates & GPU_BUFFER_TEXCOORD_STATE)
01137                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
01138         if(GLStates & GPU_BUFFER_COLOR_STATE)
01139                 glDisableClientState(GL_COLOR_ARRAY);
01140         if(GLStates & GPU_BUFFER_ELEMENT_STATE) {
01141                 if(useVBOs) {
01142                         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
01143                 }
01144         }
01145         GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE |
01146                       GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE |
01147                       GPU_BUFFER_ELEMENT_STATE);
01148 
01149         for(i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
01150                 if(attribData[i].index != -1) {
01151                         glDisableVertexAttribArrayARB(attribData[i].index);
01152                 }
01153                 else
01154                         break;
01155         }
01156 
01157         if(useVBOs)
01158                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
01159 }
01160 
01161 /* confusion: code in cdderivedmesh calls both GPU_color_setup and
01162    GPU_color3_upload; both of these set the `colors' buffer, so seems
01163    like it will just needlessly overwrite? --nicholas */
01164 void GPU_color3_upload(DerivedMesh *dm, unsigned char *data)
01165 {
01166         if(dm->drawObject == 0)
01167                 dm->drawObject = GPU_drawobject_new(dm);
01168         GPU_buffer_free(dm->drawObject->colors);
01169 
01170         dm->drawObject->colors = gpu_buffer_setup(dm, dm->drawObject, 3,
01171                                                   sizeof(char)*3*dm->drawObject->tot_triangle_point,
01172                                                   GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3);
01173 }
01174 
01175 /* this is used only in cdDM_drawFacesColored, which I think is no
01176    longer used, so can probably remove this --nicholas */
01177 void GPU_color4_upload(DerivedMesh *UNUSED(dm), unsigned char *UNUSED(data))
01178 {
01179         /*if(dm->drawObject == 0)
01180                 dm->drawObject = GPU_drawobject_new(dm);
01181         GPU_buffer_free(dm->drawObject->colors);
01182         dm->drawObject->colors = gpu_buffer_setup(dm, dm->drawObject, 3,
01183                                                   sizeof(char)*3*dm->drawObject->tot_triangle_point,
01184                                                   GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4);*/
01185 }
01186 
01187 void GPU_color_switch(int mode)
01188 {
01189         if(mode) {
01190                 if(!(GLStates & GPU_BUFFER_COLOR_STATE))
01191                         glEnableClientState(GL_COLOR_ARRAY);
01192                 GLStates |= GPU_BUFFER_COLOR_STATE;
01193         }
01194         else {
01195                 if(GLStates & GPU_BUFFER_COLOR_STATE)
01196                         glDisableClientState(GL_COLOR_ARRAY);
01197                 GLStates &= (!GPU_BUFFER_COLOR_STATE);
01198         }
01199 }
01200 
01201 /* return 1 if drawing should be done using old immediate-mode
01202    code, 0 otherwise */
01203 int GPU_buffer_legacy(DerivedMesh *dm)
01204 {
01205         int test= (U.gameflags & USER_DISABLE_VBO);
01206         if(test)
01207                 return 1;
01208 
01209         if(dm->drawObject == 0)
01210                 dm->drawObject = GPU_drawobject_new(dm);
01211         return dm->drawObject->legacy;
01212 }
01213 
01214 void *GPU_buffer_lock(GPUBuffer *buffer)
01215 {
01216         float *varray;
01217 
01218         if(!buffer)
01219                 return 0;
01220 
01221         if(useVBOs) {
01222                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
01223                 varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01224                 return varray;
01225         }
01226         else {
01227                 return buffer->pointer;
01228         }
01229 }
01230 
01231 void *GPU_buffer_lock_stream(GPUBuffer *buffer)
01232 {
01233         float *varray;
01234 
01235         if(!buffer)
01236                 return 0;
01237 
01238         if(useVBOs) {
01239                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
01240                 /* discard previous data, avoid stalling gpu */
01241                 glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB);
01242                 varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01243                 return varray;
01244         }
01245         else {
01246                 return buffer->pointer;
01247         }
01248 }
01249 
01250 void GPU_buffer_unlock(GPUBuffer *buffer)
01251 {
01252         if(useVBOs) {
01253                 if(buffer) {
01254                         /* note: this operation can fail, could return
01255                            an error code from this function? */
01256                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
01257                 }
01258                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
01259         }
01260 }
01261 
01262 /* used for drawing edges */
01263 void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count)
01264 {
01265         glDrawElements(mode, count, GL_UNSIGNED_INT,
01266                        (useVBOs ?
01267                         (void*)(start * sizeof(unsigned int)) :
01268                         ((int*)elements->pointer) + start));
01269 }
01270 
01271 
01272 /* XXX: the rest of the code in this file is used for optimized PBVH
01273    drawing and doesn't interact at all with the buffer code above */
01274 
01275 /* Convenience struct for building the VBO. */
01276 typedef struct {
01277         float co[3];
01278         short no[3];
01279 } VertexBufferFormat;
01280 
01281 typedef struct {
01282         /* opengl buffer handles */
01283         GLuint vert_buf, index_buf;
01284         GLenum index_type;
01285 
01286         /* mesh pointers in case buffer allocation fails */
01287         MFace *mface;
01288         MVert *mvert;
01289         int *face_indices;
01290         int totface;
01291 
01292         /* grid pointers */
01293         DMGridData **grids;
01294         int *grid_indices;
01295         int totgrid;
01296         int gridsize;
01297 
01298         unsigned int tot_tri, tot_quad;
01299 } GPU_Buffers;
01300 
01301 void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert,
01302                         int *vert_indices, int totvert)
01303 {
01304         GPU_Buffers *buffers = buffers_v;
01305         VertexBufferFormat *vert_data;
01306         int i;
01307 
01308         if(buffers->vert_buf) {
01309                 /* Build VBO */
01310                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
01311                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
01312                                  sizeof(VertexBufferFormat) * totvert,
01313                                  NULL, GL_STATIC_DRAW_ARB);
01314                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01315 
01316                 if(vert_data) {
01317                         for(i = 0; i < totvert; ++i) {
01318                                 MVert *v = mvert + vert_indices[i];
01319                                 VertexBufferFormat *out = vert_data + i;
01320 
01321                                 copy_v3_v3(out->co, v->co);
01322                                 memcpy(out->no, v->no, sizeof(short) * 3);
01323                         }
01324 
01325                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
01326                 }
01327                 else {
01328                         glDeleteBuffersARB(1, &buffers->vert_buf);
01329                         buffers->vert_buf = 0;
01330                 }
01331 
01332                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
01333         }
01334 
01335         buffers->mvert = mvert;
01336 }
01337 
01338 void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
01339                         int *face_indices, int totface,
01340                         int *vert_indices, int tot_uniq_verts,
01341                         int totvert)
01342 {
01343         GPU_Buffers *buffers;
01344         unsigned short *tri_data;
01345         int i, j, k, tottri;
01346 
01347         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
01348         buffers->index_type = GL_UNSIGNED_SHORT;
01349 
01350         /* Count the number of triangles */
01351         for(i = 0, tottri = 0; i < totface; ++i)
01352                 tottri += mface[face_indices[i]].v4 ? 2 : 1;
01353         
01354         if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
01355                 glGenBuffersARB(1, &buffers->index_buf);
01356 
01357         if(buffers->index_buf) {
01358                 /* Generate index buffer object */
01359                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
01360                 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
01361                                  sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB);
01362 
01363                 /* Fill the triangle buffer */
01364                 tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01365                 if(tri_data) {
01366                         for(i = 0; i < totface; ++i) {
01367                                 MFace *f = mface + face_indices[i];
01368                                 int v[3];
01369 
01370                                 v[0]= f->v1;
01371                                 v[1]= f->v2;
01372                                 v[2]= f->v3;
01373 
01374                                 for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
01375                                         for(k = 0; k < 3; ++k) {
01376                                                 void *value, *key = SET_INT_IN_POINTER(v[k]);
01377                                                 int vbo_index;
01378 
01379                                                 value = BLI_ghash_lookup(map, key);
01380                                                 vbo_index = GET_INT_FROM_POINTER(value);
01381 
01382                                                 if(vbo_index < 0) {
01383                                                         vbo_index = -vbo_index +
01384                                                                 tot_uniq_verts - 1;
01385                                                 }
01386 
01387                                                 *tri_data = vbo_index;
01388                                                 ++tri_data;
01389                                         }
01390                                         v[0] = f->v4;
01391                                         v[1] = f->v1;
01392                                         v[2] = f->v3;
01393                                 }
01394                         }
01395                         glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
01396                 }
01397                 else {
01398                         glDeleteBuffersARB(1, &buffers->index_buf);
01399                         buffers->index_buf = 0;
01400                 }
01401 
01402                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
01403         }
01404 
01405         if(buffers->index_buf)
01406                 glGenBuffersARB(1, &buffers->vert_buf);
01407         GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert);
01408 
01409         buffers->tot_tri = tottri;
01410 
01411         buffers->mface = mface;
01412         buffers->face_indices = face_indices;
01413         buffers->totface = totface;
01414 
01415         return buffers;
01416 }
01417 
01418 void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
01419         int *grid_indices, int totgrid, int gridsize, int smooth)
01420 {
01421         GPU_Buffers *buffers = buffers_v;
01422         DMGridData *vert_data;
01423         int i, j, k, totvert;
01424 
01425         totvert= gridsize*gridsize*totgrid;
01426 
01427         /* Build VBO */
01428         if(buffers->vert_buf) {
01429                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
01430                 glBufferDataARB(GL_ARRAY_BUFFER_ARB,
01431                                  sizeof(DMGridData) * totvert,
01432                                  NULL, GL_STATIC_DRAW_ARB);
01433                 vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01434                 if(vert_data) {
01435                         for(i = 0; i < totgrid; ++i) {
01436                                 DMGridData *grid= grids[grid_indices[i]];
01437                                 memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize);
01438 
01439                                 if(!smooth) {
01440                                         /* for flat shading, recalc normals and set the last vertex of
01441                                            each quad in the index buffer to have the flat normal as
01442                                            that is what opengl will use */
01443                                         for(j = 0; j < gridsize-1; ++j) {
01444                                                 for(k = 0; k < gridsize-1; ++k) {
01445                                                         normal_quad_v3(vert_data[(j+1)*gridsize + (k+1)].no,
01446                                                                 vert_data[(j+1)*gridsize + k].co,
01447                                                                 vert_data[(j+1)*gridsize + k+1].co,
01448                                                                 vert_data[j*gridsize + k+1].co,
01449                                                                 vert_data[j*gridsize + k].co);
01450                                                 }
01451                                         }
01452                                 }
01453 
01454                                 vert_data += gridsize*gridsize;
01455                         }
01456                         glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
01457                 }
01458                 else {
01459                         glDeleteBuffersARB(1, &buffers->vert_buf);
01460                         buffers->vert_buf = 0;
01461                 }
01462                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
01463         }
01464 
01465         buffers->grids = grids;
01466         buffers->grid_indices = grid_indices;
01467         buffers->totgrid = totgrid;
01468         buffers->gridsize = gridsize;
01469 
01470         //printf("node updated %p\n", buffers_v);
01471 }
01472 
01473 void *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
01474                                 int totgrid, int gridsize)
01475 {
01476         GPU_Buffers *buffers;
01477         int i, j, k, totquad, offset= 0;
01478 
01479         buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
01480 
01481         /* Count the number of quads */
01482         totquad= (gridsize-1)*(gridsize-1)*totgrid;
01483 
01484         /* Generate index buffer object */
01485         if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
01486                 glGenBuffersARB(1, &buffers->index_buf);
01487 
01488         if(buffers->index_buf) {
01489                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
01490 
01491                 if(totquad < USHRT_MAX) {
01492                         unsigned short *quad_data;
01493 
01494                         buffers->index_type = GL_UNSIGNED_SHORT;
01495                         glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
01496                                          sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
01497 
01498                         /* Fill the quad buffer */
01499                         quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01500                         if(quad_data) {
01501                                 for(i = 0; i < totgrid; ++i) {
01502                                         for(j = 0; j < gridsize-1; ++j) {
01503                                                 for(k = 0; k < gridsize-1; ++k) {
01504                                                         *(quad_data++)= offset + j*gridsize + k+1;
01505                                                         *(quad_data++)= offset + j*gridsize + k;
01506                                                         *(quad_data++)= offset + (j+1)*gridsize + k;
01507                                                         *(quad_data++)= offset + (j+1)*gridsize + k+1;
01508                                                 }
01509                                         }
01510 
01511                                         offset += gridsize*gridsize;
01512                                 }
01513                                 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
01514                         }
01515                         else {
01516                                 glDeleteBuffersARB(1, &buffers->index_buf);
01517                                 buffers->index_buf = 0;
01518                         }
01519                 }
01520                 else {
01521                         unsigned int *quad_data;
01522 
01523                         buffers->index_type = GL_UNSIGNED_INT;
01524                         glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
01525                                          sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
01526 
01527                         /* Fill the quad buffer */
01528                         quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
01529 
01530                         if(quad_data) {
01531                                 for(i = 0; i < totgrid; ++i) {
01532                                         for(j = 0; j < gridsize-1; ++j) {
01533                                                 for(k = 0; k < gridsize-1; ++k) {
01534                                                         *(quad_data++)= offset + j*gridsize + k+1;
01535                                                         *(quad_data++)= offset + j*gridsize + k;
01536                                                         *(quad_data++)= offset + (j+1)*gridsize + k;
01537                                                         *(quad_data++)= offset + (j+1)*gridsize + k+1;
01538                                                 }
01539                                         }
01540 
01541                                         offset += gridsize*gridsize;
01542                                 }
01543                                 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
01544                         }
01545                         else {
01546                                 glDeleteBuffersARB(1, &buffers->index_buf);
01547                                 buffers->index_buf = 0;
01548                         }
01549                 }
01550 
01551                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
01552         }
01553 
01554         /* Build VBO */
01555         if(buffers->index_buf)
01556                 glGenBuffersARB(1, &buffers->vert_buf);
01557 
01558         buffers->tot_quad = totquad;
01559 
01560         return buffers;
01561 }
01562 
01563 void GPU_draw_buffers(void *buffers_v)
01564 {
01565         GPU_Buffers *buffers = buffers_v;
01566 
01567         if(buffers->vert_buf && buffers->index_buf) {
01568                 glEnableClientState(GL_VERTEX_ARRAY);
01569                 glEnableClientState(GL_NORMAL_ARRAY);
01570 
01571                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
01572                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
01573 
01574                 if(buffers->tot_quad) {
01575                         glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, co));
01576                         glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no));
01577 
01578                         glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0);
01579                 }
01580                 else {
01581                         glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, co));
01582                         glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
01583 
01584                         glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
01585                 }
01586 
01587                 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
01588                 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
01589 
01590                 glDisableClientState(GL_VERTEX_ARRAY);
01591                 glDisableClientState(GL_NORMAL_ARRAY);
01592         }
01593         else if(buffers->totface) {
01594                 /* fallback if we are out of memory */
01595                 int i;
01596 
01597                 for(i = 0; i < buffers->totface; ++i) {
01598                         MFace *f = buffers->mface + buffers->face_indices[i];
01599 
01600                         glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
01601                         glNormal3sv(buffers->mvert[f->v1].no);
01602                         glVertex3fv(buffers->mvert[f->v1].co);
01603                         glNormal3sv(buffers->mvert[f->v2].no);
01604                         glVertex3fv(buffers->mvert[f->v2].co);
01605                         glNormal3sv(buffers->mvert[f->v3].no);
01606                         glVertex3fv(buffers->mvert[f->v3].co);
01607                         if(f->v4) {
01608                                 glNormal3sv(buffers->mvert[f->v4].no);
01609                                 glVertex3fv(buffers->mvert[f->v4].co);
01610                         }
01611                         glEnd();
01612                 }
01613         }
01614         else if(buffers->totgrid) {
01615                 int i, x, y, gridsize = buffers->gridsize;
01616 
01617                 for(i = 0; i < buffers->totgrid; ++i) {
01618                         DMGridData *grid = buffers->grids[buffers->grid_indices[i]];
01619 
01620                         for(y = 0; y < gridsize-1; y++) {
01621                                 glBegin(GL_QUAD_STRIP);
01622                                 for(x = 0; x < gridsize; x++) {
01623                                         DMGridData *a = &grid[y*gridsize + x];
01624                                         DMGridData *b = &grid[(y+1)*gridsize + x];
01625 
01626                                         glNormal3fv(a->no);
01627                                         glVertex3fv(a->co);
01628                                         glNormal3fv(b->no);
01629                                         glVertex3fv(b->co);
01630                                 }
01631                                 glEnd();
01632                         }
01633                 }
01634         }
01635 }
01636 
01637 void GPU_free_buffers(void *buffers_v)
01638 {
01639         if(buffers_v) {
01640                 GPU_Buffers *buffers = buffers_v;
01641                 
01642                 if(buffers->vert_buf)
01643                         glDeleteBuffersARB(1, &buffers->vert_buf);
01644                 if(buffers->index_buf)
01645                         glDeleteBuffersARB(1, &buffers->index_buf);
01646 
01647                 MEM_freeN(buffers);
01648         }
01649 }
01650