|
Blender
V2.59
|
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