From c1272e4849f43abafecd41b29dd97e01858a7b75 Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 21 Mar 2006 06:49:25 +0000 Subject: [PATCH] modified Q1BSP loader to generate lightmap fragments on its own, rather than relying on the texture manager, this greatly shortens r_texturestats reports and reduces memory usage a bit (less gltexture_t structures), and modified R_UpdateTexture to be able to update fragments git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6155 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_video.c | 2 +- gl_draw.c | 2 +- gl_rsurf.c | 10 +++---- gl_textures.c | 38 +++++++++++-------------- model_brush.c | 76 +++++++++++++++++++++++++++++++++++++------------- model_shared.h | 3 +- r_textures.h | 11 ++------ 7 files changed, 84 insertions(+), 58 deletions(-) diff --git a/cl_video.c b/cl_video.c index 3bbe315a..5f56b889 100644 --- a/cl_video.c +++ b/cl_video.c @@ -205,7 +205,7 @@ static void VideoFrame( clvideo_t *video ) return; } } while( video->framenum < destframe ); - R_UpdateTexture( video->cpif.tex, (unsigned char *)video->imagedata ); + R_UpdateTexture( video->cpif.tex, (unsigned char *)video->imagedata, 0, 0, video->cpif.width, video->cpif.height ); } } diff --git a/gl_draw.c b/gl_draw.c index 50f472d4..66a5cd19 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -405,7 +405,7 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u { if (pic->tex && pic->width == width && pic->height == height) { - R_UpdateTexture(pic->tex, pixels); + R_UpdateTexture(pic->tex, pixels, 0, 0, width, height); return pic; } } diff --git a/gl_rsurf.c b/gl_rsurf.c index fc04f244..5bcf8fb3 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -50,7 +50,7 @@ Combine and scale multiple lightmaps into the 8.8 format in blocklights */ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) { - int smax, tmax, i, j, size, size3, maps, stride, l; + int smax, tmax, i, j, size, size3, maps, l; unsigned int *bl, scale; unsigned char *lightmap, *out, *stain; static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting @@ -96,8 +96,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) // (0 = 0.0, 128 = 1.0, 256 = 2.0) if (ent->model->brushq1.lightmaprgba) { - stride = (surface->lightmapinfo->lightmaptexturestride - smax) * 4; - for (i = 0;i < tmax;i++, out += stride) + for (i = 0;i < tmax;i++) { for (j = 0;j < smax;j++) { @@ -110,8 +109,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) } else { - stride = (surface->lightmapinfo->lightmaptexturestride - smax) * 3; - for (i = 0;i < tmax;i++, out += stride) + for (i = 0;i < tmax;i++) { for (j = 0;j < smax;j++) { @@ -122,7 +120,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) } } - R_UpdateTexture(surface->lightmaptexture, templight); + R_UpdateTexture(surface->lightmaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax); } void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radius, const float fcolor[8]) diff --git a/gl_textures.c b/gl_textures.c index 0e5812bd..c23980f1 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -683,7 +683,7 @@ static void GL_SetupTextureParameters(int flags, int texturetype) CHECKGLERROR } -static void R_Upload(gltexture_t *glt, unsigned char *data) +static void R_Upload(gltexture_t *glt, unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth) { int i, mip, width, height, depth; GLint oldbindtexnum; @@ -699,7 +699,7 @@ static void R_Upload(gltexture_t *glt, unsigned char *data) CHECKGLERROR glt->flags &= ~GLTEXF_UPLOAD; - if (glt->flags & TEXF_FRAGMENT) + if ((glt->flags & TEXF_FRAGMENT) || (glt->image->flags & (TEXF_MIPMAP | TEXF_PICMIP | GLTEXF_UPLOAD)) == 0) { if (glt->image->flags & GLTEXF_UPLOAD) { @@ -730,31 +730,31 @@ static void R_Upload(gltexture_t *glt, unsigned char *data) if (prevbuffer == NULL) { - R_MakeResizeBufferBigger(glt->image->width * glt->image->height * glt->image->depth * glt->image->bytesperpixel); - memset(resizebuffer, 0, glt->width * glt->height * glt->image->depth * glt->image->bytesperpixel); + R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->image->bytesperpixel); + memset(resizebuffer, 0, fragwidth * fragheight * fragdepth * glt->image->bytesperpixel); prevbuffer = resizebuffer; } else if (glt->textype->textype == TEXTYPE_PALETTE) { // promote paletted to RGBA, so we only have to worry about RGB and // RGBA in the rest of this code - R_MakeResizeBufferBigger(glt->image->width * glt->image->height * glt->image->depth * glt->image->sides * glt->image->bytesperpixel); - Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, glt->width * glt->height * glt->depth, glt->palette); + R_MakeResizeBufferBigger(fragwidth * fragheight * fragdepth * glt->image->sides * glt->image->bytesperpixel); + Image_Copy8bitRGBA(prevbuffer, colorconvertbuffer, fragwidth * fragheight * fragdepth, glt->palette); prevbuffer = colorconvertbuffer; } switch(glt->image->texturetype) { case GLTEXTURETYPE_1D: - qglTexSubImage1D(GL_TEXTURE_1D, 0, glt->x, glt->width, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer); + qglTexSubImage1D(GL_TEXTURE_1D, 0, glt->x + fragx, fragwidth, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer); CHECKGLERROR break; case GLTEXTURETYPE_2D: - qglTexSubImage2D(GL_TEXTURE_2D, 0, glt->x, glt->y, glt->width, glt->height, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer); + qglTexSubImage2D(GL_TEXTURE_2D, 0, glt->x + fragx, glt->y + fragy, fragwidth, fragheight, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer); CHECKGLERROR break; case GLTEXTURETYPE_3D: - qglTexSubImage3D(GL_TEXTURE_3D, 0, glt->x, glt->y, glt->z, glt->width, glt->height, glt->depth, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer); + qglTexSubImage3D(GL_TEXTURE_3D, 0, glt->x + fragx, glt->y + fragy, glt->z + fragz, fragwidth, fragheight, fragdepth, glt->image->glformat, GL_UNSIGNED_BYTE, prevbuffer); CHECKGLERROR break; default: @@ -1020,7 +1020,7 @@ static void R_UploadTexture (gltexture_t *glt) if (!(glt->flags & GLTEXF_UPLOAD)) return; - R_Upload(glt, glt->inputtexels); + R_Upload(glt, glt->inputtexels, 0, 0, 0, glt->width, glt->height, glt->depth); if (glt->inputtexels) { Mem_Free(glt->inputtexels); @@ -1267,12 +1267,7 @@ void R_FragmentLocation(rtexture_t *rt, int *x, int *y, float *fx1, float *fy1, R_FragmentLocation3D(rt, x, y, NULL, fx1, fy1, NULL, fx2, fy2, NULL); } -int R_CompatibleFragmentWidth(int width, int textype, int flags) -{ - return width; -} - -void R_UpdateTexture(rtexture_t *rt, unsigned char *data) +void R_UpdateTexture(rtexture_t *rt, unsigned char *data, int x, int y, int width, int height) { gltexture_t *glt; if (rt == NULL) @@ -1281,10 +1276,11 @@ void R_UpdateTexture(rtexture_t *rt, unsigned char *data) Host_Error("R_UpdateTexture: no data supplied"); glt = (gltexture_t *)rt; - // if it has not been uploaded yet, update the data that will be used when it is - if (glt->inputtexels) - memcpy(glt->inputtexels, data, glt->inputdatasize); - else - R_Upload(glt, data); + // we need it to be uploaded before we can update a part of it + if (glt->flags & GLTEXF_UPLOAD) + R_UploadTexture(glt); + + // update part of the texture + R_Upload(glt, data, x, y, 0, width, height, 1); } diff --git a/model_brush.c b/model_brush.c index d69bfe85..d53885e2 100644 --- a/model_brush.c +++ b/model_brush.c @@ -30,7 +30,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"}; cvar_t mcbsp = {0, "mcbsp", "0", "indicates the current map is mcbsp format (useful to know because of different bounding box sizes)"}; cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"}; -cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0", "mipmaps lightmaps on upload, also expanding them to power of 2 sizes, this runs slower"}; cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1", "whether to use RGBA (32bit) or RGB (24bit) lightmaps"}; cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"}; cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"}; @@ -51,7 +50,6 @@ void Mod_BrushInit(void) Cvar_RegisterVariable(&halflifebsp); Cvar_RegisterVariable(&mcbsp); Cvar_RegisterVariable(&r_novis); - Cvar_RegisterVariable(&r_miplightmaps); Cvar_RegisterVariable(&r_lightmaprgba); Cvar_RegisterVariable(&r_nosurftextures); Cvar_RegisterVariable(&r_subdivisions_tolerance); @@ -1912,12 +1910,46 @@ static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface) } #endif +static qboolean Mod_Q1BSP_AllocLightmapBlock(int *lineused, int totalwidth, int totalheight, int blockwidth, int blockheight, int *outx, int *outy) +{ + int y, x2, y2; + int bestx = totalwidth, besty = 0; + // find the left-most space we can find + for (y = 0;y <= totalheight - blockheight;y++) + { + x2 = 0; + for (y2 = 0;y2 < blockheight;y2++) + x2 = max(x2, lineused[y+y2]); + if (bestx > x2) + { + bestx = x2; + besty = y; + } + } + // if the best was not good enough, return failure + if (bestx > totalwidth - blockwidth) + return false; + // we found a good spot + if (outx) + *outx = bestx; + if (outy) + *outy = besty; + // now mark the space used + for (y2 = 0;y2 < blockheight;y2++) + lineused[besty+y2] = bestx + blockwidth; + // return success + return true; +} + static void Mod_Q1BSP_LoadFaces(lump_t *l) { dface_t *in; msurface_t *surface; - int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris; - float texmins[2], texmaxs[2], val; + int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber; + float texmins[2], texmaxs[2], val, lightmaptexcoordscale; +#define LIGHTMAPSIZE 256 + rtexture_t *lightmaptexture; + int lightmap_lineused[LIGHTMAPSIZE]; in = (dface_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -1943,6 +1975,10 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *)); loadmodel->meshlist[0] = Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false); + lightmaptexture = NULL; + lightmapnumber = 1; + lightmaptexcoordscale = 1.0f / (float)LIGHTMAPSIZE; + totalverts = 0; totaltris = 0; for (surfacenum = 0, in = (dface_t *)(mod_base + l->fileofs), surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, in++, surface++) @@ -2032,7 +2068,6 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) // lighting info for (i = 0;i < MAXLIGHTMAPS;i++) surface->lightmapinfo->styles[i] = in->styles[i]; - surface->lightmapinfo->lightmaptexturestride = 0; surface->lightmaptexture = NULL; surface->deluxemaptexture = r_texture_blanknormalmap; i = LittleLong(in->lightofs); @@ -2055,7 +2090,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) // check if we should apply a lightmap to this if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples) { - int i, iu, iv; + int i, iu, iv, lightmapx, lightmapy; float u, v, ubase, vbase, uscale, vscale; if (ssize > 256 || tsize > 256) @@ -2067,21 +2102,24 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) // clear to white memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3); - if (r_miplightmaps.integer) - { - surface->lightmapinfo->lightmaptexturestride = ssize; - surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL); - surface->deluxemaptexture = r_texture_blanknormalmap; - } - else + // find a place for this lightmap + if (!lightmaptexture || !Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy)) { - surface->lightmapinfo->lightmaptexturestride = R_CompatibleFragmentWidth(ssize, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0); - surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL); - surface->deluxemaptexture = r_texture_blanknormalmap; + // could not find room, make a new lightmap + lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%i", lightmapnumber++), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL); + memset(lightmap_lineused, 0, sizeof(lightmap_lineused)); + Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy); } - R_FragmentLocation(surface->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale); - uscale = (uscale - ubase) / ssize; - vscale = (vscale - vbase) / tsize; + + surface->lightmaptexture = lightmaptexture; + surface->deluxemaptexture = r_texture_blanknormalmap; + surface->lightmapinfo->lightmaporigin[0] = lightmapx; + surface->lightmapinfo->lightmaporigin[1] = lightmapy; + + ubase = lightmapx * lightmaptexcoordscale; + vbase = lightmapy * lightmaptexcoordscale; + uscale = lightmaptexcoordscale; + vscale = lightmaptexcoordscale; for (i = 0;i < surface->num_vertices;i++) { diff --git a/model_shared.h b/model_shared.h index 4d47eecd..85c6d970 100644 --- a/model_shared.h +++ b/model_shared.h @@ -248,10 +248,9 @@ typedef struct msurface_lightmapinfo_s unsigned char *samples; // q1bsp // stain to apply on lightmap (soot/dirt/blood/whatever) unsigned char *stainsamples; // q1bsp - // the stride when building lightmaps to comply with fragment update - int lightmaptexturestride; // q1bsp int texturemins[2]; // q1bsp int extents[2]; // q1bsp + int lightmaporigin[2]; // q1bsp } msurface_lightmapinfo_t; diff --git a/r_textures.h b/r_textures.h index 080aa314..ace83017 100644 --- a/r_textures.h +++ b/r_textures.h @@ -53,11 +53,6 @@ rtexturepool_t *R_AllocTexturePool(void); // free a texture pool (textures can not be freed individually) void R_FreeTexturePool(rtexturepool_t **rtexturepool); -// important technical note: -// fragment textures must have a width that is compatible with the fragment -// update system, to get a compliant size, use R_CompatibleFragmentWidth -int R_CompatibleFragmentWidth(int width, int textype, int flags); - // add a texture to a pool and optionally precache (upload) it // (note: data == NULL is perfectly acceptable) // (note: palette must not be NULL if using TEXTYPE_PALETTE) @@ -69,9 +64,9 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident // free a texture void R_FreeTexture(rtexture_t *rt); -// update the image data of a texture, used by lightmap updates and -// procedural textures. -void R_UpdateTexture(rtexture_t *rt, unsigned char *data); +// update a portion of the image data of a texture, used by lightmap updates +// and procedural textures such as video playback. +void R_UpdateTexture(rtexture_t *rt, unsigned char *data, int x, int y, int width, int height); // location of the fragment in the texture (note: any parameter except rt can // be NULL) -- 2.39.2