/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_surf.c: surface-related refresh code #include "quakedef.h" #if defined(GLQUAKE) #include "glquake.h" #include "shader.h" #include "renderque.h" #include extern cvar_t gl_bump; void GLBE_ClearVBO(vbo_t *vbo) { int vboh[7]; int i, j; vboh[0] = vbo->vboe; vboh[1] = vbo->vbocoord; vboh[2] = vbo->vbotexcoord; vboh[3] = vbo->vbolmcoord; vboh[4] = vbo->vbonormals; vboh[5] = vbo->vbosvector; vboh[6] = vbo->vbotvector; for (i = 0; i < 7; i++) { if (!vboh[i]) continue; for (j = 0; j < 7; j++) { if (vboh[j] == vboh[i]) break; //already freed by one of the other ones } if (j == 7) qglDeleteBuffersARB(1, &vboh[i]); } if (vbo->vertdata) BZ_Free(vbo->vertdata); BZ_Free(vbo->meshlist); memset(vbo, 0, sizeof(*vbo)); } static qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int elementsize) { unsigned int vbos[2]; if (!qglGenBuffersARB) return false; qglGenBuffersARB(1+(elementsize>0), vbos); GL_SelectVBO(vbos[0]); qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vsize, vdata, GL_STATIC_DRAW_ARB); if (elementsize>0) { GL_SelectEBO(vbos[1]); qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, elementsize, edata, GL_STATIC_DRAW_ARB); } if (qglGetError()) { GL_SelectVBO(0); GL_SelectEBO(0); qglDeleteBuffersARB(1+(elementsize>0), vbos); return false; } //opengl ate our data, fixup the vbo arrays to point to the vbo instead of the raw data if (vbo->indicies && elementsize) { vbo->vboe = vbos[1]; vbo->indicies = (index_t*)((char*)vbo->indicies - (char*)edata); } if (vbo->coord) { vbo->vbocoord = vbos[0]; vbo->coord = (vecV_t*)((char*)vbo->coord - (char*)vdata); } if (vbo->texcoord) { vbo->vbotexcoord = vbos[0]; vbo->texcoord = (vec2_t*)((char*)vbo->texcoord - (char*)vdata); } if (vbo->lmcoord) { vbo->vbolmcoord = vbos[0]; vbo->lmcoord = (vec2_t*)((char*)vbo->lmcoord - (char*)vdata); } if (vbo->normals) { vbo->vbonormals = vbos[0]; vbo->normals = (vec3_t*)((char*)vbo->normals - (char*)vdata); } if (vbo->svector) { vbo->vbosvector = vbos[0]; vbo->svector = (vec3_t*)((char*)vbo->svector - (char*)vdata); } if (vbo->tvector) { vbo->vbotvector = vbos[0]; vbo->tvector = (vec3_t*)((char*)vbo->tvector - (char*)vdata); } if (vbo->colours4f) { vbo->vbocolours = vbos[0]; vbo->colours4f = (vec4_t*)((char*)vbo->colours4f - (char*)vdata); } return true; } void *allocbuf(char **p, int elements, int elementsize) { void *ret; *p += elementsize - 1; *p -= (size_t)*p & (elementsize-1); ret = *p; *p += elements*elementsize; return ret; } void GLBE_GenBrushModelVBO(model_t *mod) { unsigned int maxvboverts; unsigned int maxvboelements; unsigned int t; unsigned int i; unsigned int v; unsigned int vcount, ecount; unsigned int pervertsize; //erm, that name wasn't intentional unsigned int meshes; vbo_t *vbo; mesh_t *m; char *p; if (!mod->numsurfaces) return; for (t = 0; t < mod->numtextures; t++) { if (!mod->textures[t]) continue; vbo = &mod->textures[t]->vbo; BE_ClearVBO(vbo); maxvboverts = 0; maxvboelements = 0; meshes = 0; for (i=0 ; inumsurfaces ; i++) { if (mod->surfaces[i].texinfo->texture != mod->textures[t]) continue; m = mod->surfaces[i].mesh; if (!m) continue; meshes++; maxvboelements += m->numindexes; maxvboverts += m->numvertexes; } #if sizeof_index_t == 2 if (maxvboverts > (1<<(sizeof(index_t)*8))-1) continue; #endif if (!maxvboverts) continue; //fixme: stop this from leaking! vcount = 0; ecount = 0; pervertsize = sizeof(vecV_t)+ //coord sizeof(vec2_t)+ //tex sizeof(vec2_t)+ //lm sizeof(vec3_t)+ //normal sizeof(vec3_t)+ //sdir sizeof(vec3_t)+ //tdir sizeof(vec4_t); //colours vbo->vertdata = BZ_Malloc((maxvboverts+1)*pervertsize + (maxvboelements+1)*sizeof(index_t)); p = vbo->vertdata; vbo->coord = allocbuf(&p, maxvboverts, sizeof(*vbo->coord)); vbo->texcoord = allocbuf(&p, maxvboverts, sizeof(*vbo->texcoord)); vbo->lmcoord = allocbuf(&p, maxvboverts, sizeof(*vbo->lmcoord)); vbo->normals = allocbuf(&p, maxvboverts, sizeof(*vbo->normals)); vbo->svector = allocbuf(&p, maxvboverts, sizeof(*vbo->svector)); vbo->tvector = allocbuf(&p, maxvboverts, sizeof(*vbo->tvector)); vbo->colours4f = allocbuf(&p, maxvboverts, sizeof(*vbo->colours4f)); vbo->indicies = allocbuf(&p, maxvboelements, sizeof(index_t)); vbo->meshcount = meshes; vbo->meshlist = BZ_Malloc(meshes*sizeof(*vbo->meshlist)); meshes = 0; for (i=0 ; inumsurfaces ; i++) { if (mod->surfaces[i].texinfo->texture != mod->textures[t]) continue; m = mod->surfaces[i].mesh; if (!m) continue; mod->surfaces[i].mark = &vbo->meshlist[meshes++]; *mod->surfaces[i].mark = NULL; m->vbofirstvert = vcount; m->vbofirstelement = ecount; for (v = 0; v < m->numindexes; v++) vbo->indicies[ecount++] = vcount + m->indexes[v]; for (v = 0; v < m->numvertexes; v++) { vbo->coord[vcount+v][0] = m->xyz_array[v][0]; vbo->coord[vcount+v][1] = m->xyz_array[v][1]; vbo->coord[vcount+v][2] = m->xyz_array[v][2]; if (m->st_array) { vbo->texcoord[vcount+v][0] = m->st_array[v][0]; vbo->texcoord[vcount+v][1] = m->st_array[v][1]; } if (m->lmst_array) { vbo->lmcoord[vcount+v][0] = m->lmst_array[v][0]; vbo->lmcoord[vcount+v][1] = m->lmst_array[v][1]; } if (m->normals_array) { vbo->normals[vcount+v][0] = m->normals_array[v][0]; vbo->normals[vcount+v][1] = m->normals_array[v][1]; vbo->normals[vcount+v][2] = m->normals_array[v][2]; } if (m->snormals_array) { vbo->svector[vcount+v][0] = m->snormals_array[v][0]; vbo->svector[vcount+v][1] = m->snormals_array[v][1]; vbo->svector[vcount+v][2] = m->snormals_array[v][2]; } if (m->tnormals_array) { vbo->tvector[vcount+v][0] = m->tnormals_array[v][0]; vbo->tvector[vcount+v][1] = m->tnormals_array[v][1]; vbo->tvector[vcount+v][2] = m->tnormals_array[v][2]; } if (m->colors4f_array) { vbo->colours4f[vcount+v][0] = m->colors4f_array[v][0]; vbo->colours4f[vcount+v][1] = m->colors4f_array[v][1]; vbo->colours4f[vcount+v][2] = m->colors4f_array[v][2]; vbo->colours4f[vcount+v][3] = m->colors4f_array[v][3]; } } vcount += v; } if (GL_BuildVBO(vbo, vbo->coord, vcount*pervertsize, vbo->indicies, ecount*sizeof(index_t))) { BZ_Free(vbo->vertdata); vbo->vertdata = NULL; } } /* for (i=0 ; inumsurfaces ; i++) { if (!mod->surfaces[i].mark) Host_EndGame("Surfaces with bad textures detected\n"); }*/ } void GLBE_UploadAllLightmaps(void) { int i; // // upload all lightmaps that were filled // for (i=0 ; irectchange.l = LMBLOCK_WIDTH; lightmap[i]->rectchange.t = LMBLOCK_HEIGHT; lightmap[i]->rectchange.w = 0; lightmap[i]->rectchange.h = 0; if (!lightmap[i]->modified) continue; lightmap[i]->modified = false; GL_MTBind(0, GL_TEXTURE_2D, lightmap_textures[i]); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); switch (lightmap_bytes) { case 4: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, LMBLOCK_WIDTH, LMBLOCK_WIDTH, 0, (lightmap_bgra?GL_BGRA_EXT:GL_RGBA), GL_UNSIGNED_INT_8_8_8_8_REV, lightmap[i]->lightmaps); break; case 3: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, LMBLOCK_WIDTH, LMBLOCK_WIDTH, 0, (lightmap_bgra?GL_BGR_EXT:GL_RGB), GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; case 1: qglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, LMBLOCK_WIDTH, LMBLOCK_WIDTH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; } if (gl_bump.ival) { lightmap[i]->deluxmodified = false; lightmap[i]->deluxrectchange.l = LMBLOCK_WIDTH; lightmap[i]->deluxrectchange.t = LMBLOCK_HEIGHT; lightmap[i]->deluxrectchange.w = 0; lightmap[i]->deluxrectchange.h = 0; GL_MTBind(0, GL_TEXTURE_2D, deluxmap_textures[i]); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexImage2D (GL_TEXTURE_2D, 0, 3 , LMBLOCK_WIDTH, LMBLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmap[i]->deluxmaps); } } } #endif