static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
{
q3dlightmap_t *input_pointer;
- int i, j, k, count, power, power2, endlightmap, mergewidth, mergeheight;
+ int i;
+ int j;
+ int k;
+ int count;
+ int powerx;
+ int powery;
+ int powerxy;
+ int powerdxy;
+ int endlightmap;
+ int mergegoal;
+ int lightmapindex;
+ int realcount;
+ int realindex;
+ int mergedwidth;
+ int mergedheight;
+ int mergedcolumns;
+ int mergedrows;
+ int mergedrowsxcolumns;
+ int size;
+ int bytesperpixel;
+ int rgbmap[3];
unsigned char *c;
-
- unsigned char *convertedpixels;
+ unsigned char *mergedpixels;
+ unsigned char *mergeddeluxepixels;
+ unsigned char *mergebuf;
char mapname[MAX_QPATH];
- int size, bytesperpixel, rgbmap[3];
qboolean external;
unsigned char *inpixels[10000]; // max count q3map2 can output (it uses 4 digits)
}
}
- convertedpixels = (unsigned char *) Mem_Alloc(tempmempool, size*size*4);
loadmodel->brushq3.lightmapsize = size;
loadmodel->brushq3.num_originallightmaps = count;
// figure out what the most reasonable merge power is within limits
- loadmodel->brushq3.num_lightmapmergepower = 0;
-
- for(i = 0; (128 << i) < size; ++i)
- ;
- // i is now 0 for 128, 1 for 256, etc
-
- for (power = 1;power + i <= mod_q3bsp_lightmapmergepower.integer && (size << power) <= (int)vid.maxtexturesize_2d && (1 << (power * 2)) < 4 * (count >> (loadmodel->brushq3.deluxemapping ? 1 : 0)); power++)
- loadmodel->brushq3.num_lightmapmergepower = power;
-
- loadmodel->brushq3.num_lightmapmerge = 1 << loadmodel->brushq3.num_lightmapmergepower;
-
- loadmodel->brushq3.num_mergedlightmaps = ((count >> (loadmodel->brushq3.deluxemapping ? 1 : 0)) + (1 << (loadmodel->brushq3.num_lightmapmergepower * 2)) - 1) >> (loadmodel->brushq3.num_lightmapmergepower * 2);
+ // find the appropriate NxN dimensions to merge to, to avoid wasted space
+ realcount = count >> loadmodel->brushq3.deluxemapping;
+
+ // figure out how big the merged texture has to be
+ mergegoal = 128<<bound(0, mod_q3bsp_lightmapmergepower.integer, 6);
+ mergegoal = bound(size, mergegoal, (int)vid.maxtexturesize_2d);
+ while (mergegoal > size && mergegoal * mergegoal / 4 >= size * size * realcount)
+ mergegoal /= 2;
+ mergedwidth = mergegoal;
+ mergedheight = mergegoal;
+ // choose non-square size (2x1 aspect) if only half the space is used;
+ // this really only happens when the entire set fits in one texture, if
+ // there are multiple textures, we don't worry about shrinking the last
+ // one to fit, because the driver prefers the same texture size on
+ // consecutive draw calls...
+ if (mergedwidth * mergedheight / 2 >= size*size*realcount)
+ mergedheight /= 2;
+
+ loadmodel->brushq3.num_lightmapmergedwidthpower = 0;
+ loadmodel->brushq3.num_lightmapmergedheightpower = 0;
+ while (mergedwidth > size<<loadmodel->brushq3.num_lightmapmergedwidthpower)
+ loadmodel->brushq3.num_lightmapmergedwidthpower++;
+ while (mergedheight > size<<loadmodel->brushq3.num_lightmapmergedheightpower)
+ loadmodel->brushq3.num_lightmapmergedheightpower++;
+ loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower = loadmodel->brushq3.num_lightmapmergedwidthpower + loadmodel->brushq3.num_lightmapmergedheightpower + (loadmodel->brushq3.deluxemapping ? 1 : 0);
+
+ powerx = loadmodel->brushq3.num_lightmapmergedwidthpower;
+ powery = loadmodel->brushq3.num_lightmapmergedheightpower;
+ powerxy = powerx+powery;
+ powerdxy = loadmodel->brushq3.deluxemapping + powerxy;
+
+ mergedcolumns = 1 << powerx;
+ mergedrows = 1 << powery;
+ mergedrowsxcolumns = 1 << powerxy;
+
+ loadmodel->brushq3.num_mergedlightmaps = (realcount + (1 << powerxy) - 1) >> powerxy;
loadmodel->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
if (loadmodel->brushq3.deluxemapping)
loadmodel->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
if (loadmodel->texturepool == NULL && cls.state != ca_dedicated)
loadmodel->texturepool = R_AllocTexturePool();
- power = loadmodel->brushq3.num_lightmapmergepower;
- power2 = power * 2;
+ mergedpixels = (unsigned char *) Mem_Alloc(tempmempool, mergedwidth * mergedheight * 4);
+ mergeddeluxepixels = loadmodel->brushq3.deluxemapping ? (unsigned char *) Mem_Alloc(tempmempool, mergedwidth * mergedheight * 4) : NULL;
for (i = 0;i < count;i++)
{
// figure out which merged lightmap texture this fits into
- int lightmapindex = i >> (loadmodel->brushq3.deluxemapping + power2);
- for (k = 0;k < size*size;k++)
- {
- convertedpixels[k*4+0] = inpixels[i][k*bytesperpixel+rgbmap[0]];
- convertedpixels[k*4+1] = inpixels[i][k*bytesperpixel+rgbmap[1]];
- convertedpixels[k*4+2] = inpixels[i][k*bytesperpixel+rgbmap[2]];
- convertedpixels[k*4+3] = 255;
- }
- if (loadmodel->brushq3.num_lightmapmergepower > 0)
+ realindex = i >> loadmodel->brushq3.deluxemapping;
+ lightmapindex = i >> powerdxy;
+
+ // choose the destination address
+ mergebuf = (loadmodel->brushq3.deluxemapping && (i & 1)) ? mergeddeluxepixels : mergedpixels;
+ mergebuf += 4 * (realindex & (mergedcolumns-1))*size + 4 * ((realindex >> powerx) & (mergedrows-1))*mergedwidth*size;
+ if ((i & 1) == 0 || !loadmodel->brushq3.deluxemapping)
+ Con_Printf("copying original lightmap %i (%ix%i) to %i (at %i,%i)\n", i, size, size, lightmapindex, (realindex & (mergedcolumns-1))*size, ((realindex >> powerx) & (mergedrows-1))*size);
+
+ // convert pixels from RGB or BGRA while copying them into the destination rectangle
+ for (j = 0;j < size;j++)
+ for (k = 0;k < size;k++)
{
- // if the lightmap has not been allocated yet, create it
- if (!loadmodel->brushq3.data_lightmaps[lightmapindex])
- {
- // create a lightmap only as large as necessary to hold the
- // remaining size*size blocks
- // if there are multiple merged lightmap textures then they will
- // all be full size except the last one which may be smaller
- // because it only needs to the remaining blocks, and it will often
- // be odd sizes like 2048x512 due to only being 25% full or so.
- j = (count >> (loadmodel->brushq3.deluxemapping ? 1 : 0)) - (lightmapindex << power2);
- for (mergewidth = 1;mergewidth < j && mergewidth < (1 << power);mergewidth *= 2)
- ;
- for (mergeheight = 1;mergewidth*mergeheight < j && mergeheight < (1 << power);mergeheight *= 2)
- ;
- if (developer_loading.integer)
- Con_Printf("lightmap merge texture #%i is %ix%i (%i of %i used)\n", lightmapindex, mergewidth*size, mergeheight*size, min(j, mergewidth*mergeheight), mergewidth*mergeheight);
- loadmodel->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), mergewidth * size, mergeheight * size, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : TEXF_ALLOWUPDATES), -1, NULL);
- if (loadmodel->brushq3.data_deluxemaps)
- loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), mergewidth * size, mergeheight * size, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : TEXF_ALLOWUPDATES), -1, NULL);
- }
- mergewidth = R_TextureWidth(loadmodel->brushq3.data_lightmaps[lightmapindex]) / size;
- mergeheight = R_TextureHeight(loadmodel->brushq3.data_lightmaps[lightmapindex]) / size;
- j = (i >> (loadmodel->brushq3.deluxemapping ? 1 : 0)) & ((1 << power2) - 1);
- if (loadmodel->brushq3.deluxemapping && (i & 1))
- R_UpdateTexture(loadmodel->brushq3.data_deluxemaps[lightmapindex], convertedpixels, (j % mergewidth) * size, (j / mergewidth) * size, size, size);
- else
- R_UpdateTexture(loadmodel->brushq3.data_lightmaps [lightmapindex], convertedpixels, (j % mergewidth) * size, (j / mergewidth) * size, size, size);
+ mergebuf[(j*mergedwidth+k)*4+0] = inpixels[i][(j*size+k)*bytesperpixel+rgbmap[0]];
+ mergebuf[(j*mergedwidth+k)*4+1] = inpixels[i][(j*size+k)*bytesperpixel+rgbmap[1]];
+ mergebuf[(j*mergedwidth+k)*4+2] = inpixels[i][(j*size+k)*bytesperpixel+rgbmap[2]];
+ mergebuf[(j*mergedwidth+k)*4+3] = 255;
}
- else
+
+ // upload texture if this was the last tile being written to the texture
+ if (((realindex + 1) & (mergedrowsxcolumns - 1)) == 0 || (realindex + 1) == realcount)
{
- // figure out which merged lightmap texture this fits into
if (loadmodel->brushq3.deluxemapping && (i & 1))
- loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), size, size, convertedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : 0), -1, NULL);
+ loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), mergedwidth, mergedheight, mergeddeluxepixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : 0), -1, NULL);
else
- loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), size, size, convertedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL);
+ loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL);
}
}
- Mem_Free(convertedpixels);
+ if (mergeddeluxepixels)
+ Mem_Free(mergeddeluxepixels);
+ Mem_Free(mergedpixels);
if(external)
{
for(i = 0; i < count; ++i)
}
else
{
- out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n >> (loadmodel->brushq3.num_lightmapmergepower * 2 + loadmodel->brushq3.deluxemapping)];
+ out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n >> loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower];
if (loadmodel->brushq3.deluxemapping)
- out->deluxemaptexture = loadmodel->brushq3.data_deluxemaps[n >> (loadmodel->brushq3.num_lightmapmergepower * 2 + loadmodel->brushq3.deluxemapping)];
+ out->deluxemaptexture = loadmodel->brushq3.data_deluxemaps[n >> loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower];
}
}
char *argv[512];
char line[1024];
char materialname[MAX_QPATH];
- int i, j, l, numvertices, firstvertex, firsttriangle, elementindex, vertexindex, surfacevertices, surfacetriangles, surfaceelements, submodelindex;
+ int i, j, l, numvertices, firstvertex, firsttriangle, elementindex, vertexindex, surfacevertices, surfacetriangles, surfaceelements, submodelindex = 0;
int index1, index2, index3;
objvertex_t vfirst, vprev, vcurrent;
int argc;
// parse the OBJ text now
for(;;)
{
+ static char emptyarg[1] = "";
if (!*text)
break;
linenumber++;
line[linelen] = text[linelen];
line[linelen] = 0;
for (argc = 0;argc < 4;argc++)
- argv[argc] = "";
+ argv[argc] = emptyarg;
argc = 0;
s = line;
while (*s == ' ' || *s == '\t')
loadmodel->num_surfaces = 0;
// allocate storage for the worst case number of surfaces, later we resize
tempsurfaces = (msurface_t *)Mem_Alloc(loadmodel->mempool, numtextures * loadmodel->brush.numsubmodels * sizeof(msurface_t));
- submodelfirstsurface = Mem_Alloc(loadmodel->mempool, (loadmodel->brush.numsubmodels+1) * sizeof(int));
+ submodelfirstsurface = (int *)Mem_Alloc(loadmodel->mempool, (loadmodel->brush.numsubmodels+1) * sizeof(int));
surface = tempsurfaces;
for (submodelindex = 0;submodelindex < loadmodel->brush.numsubmodels;submodelindex++)
{