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 );
}
}
{
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;
}
}
*/
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
// (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++)
{
}
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++)
{
}
}
- 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])
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;
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)
{
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:
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);
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)
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);
}
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)"};
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);
}
#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))
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++)
// 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);
// 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)
// 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++)
{
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;
// 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)
// 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)