mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-13 10:12:19 +00:00
Make them stronger by the same factor as acceleration is weakened. This feels a lot more natural, since your top speed tends to be higher on ice, which was making them feel strangely easier to climb ... even though driving on ice is hard mode (even in real life) Also fixes an oversight where P_SpawnFriction was using the outdated movefactor constants from SRB2 instead of the ones from SRB2Kart that the rest of the codebase was using, by unifying it into one function.
1259 lines
34 KiB
C
1259 lines
34 KiB
C
// DR. ROBOTNIK'S RING RACERS
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2024 by Kart Krew.
|
|
// Copyright (C) 2020 by Sonic Team Junior.
|
|
// Copyright (C) 2000 by DooM Legacy Team.
|
|
// Copyright (C) 1996 by id Software, Inc.
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file r_data.c
|
|
/// \brief Preparation of data for rendering, generation of lookups, caching, retrieval by name
|
|
|
|
#include "doomdef.h"
|
|
#include "g_game.h"
|
|
#include "i_video.h"
|
|
#include "r_local.h"
|
|
#include "r_sky.h"
|
|
#include "p_local.h"
|
|
#include "m_misc.h"
|
|
#include "r_data.h"
|
|
#include "r_textures.h"
|
|
#include "r_patch.h"
|
|
#include "r_picformats.h"
|
|
#include "w_wad.h"
|
|
#include "z_zone.h"
|
|
#include "p_setup.h" // levelflats
|
|
#include "v_video.h" // pMasterPalette
|
|
#include "f_finale.h" // wipes
|
|
#include "byteptr.h"
|
|
#include "dehacked.h"
|
|
|
|
// DRRR
|
|
#include "k_brightmap.h"
|
|
|
|
//
|
|
// Graphics.
|
|
// SRB2 graphics for walls and sprites
|
|
// is stored in vertical runs of opaque pixels (posts).
|
|
// A column is composed of zero or more posts,
|
|
// a patch or sprite is composed of zero or more columns.
|
|
//
|
|
|
|
size_t numspritelumps, max_spritelumps;
|
|
|
|
// needed for pre rendering
|
|
sprcache_t *spritecachedinfo;
|
|
|
|
lighttable_t *colormaps;
|
|
UINT8 *encoremap;
|
|
|
|
// for debugging/info purposes
|
|
size_t flatmemory, spritememory, texturememory;
|
|
|
|
// highcolor stuff
|
|
INT16 color8to16[256]; // remap color index to highcolor rgb value
|
|
INT16 *hicolormaps; // test a 32k colormap remaps high -> high
|
|
|
|
// Blends two pixels together, using the equation
|
|
// that matches the specified alpha style.
|
|
UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
|
|
{
|
|
RGBA_t output;
|
|
INT16 fullalpha = (alpha - (0xFF - foreground.s.alpha));
|
|
if (style == AST_TRANSLUCENT)
|
|
{
|
|
if (fullalpha <= 0)
|
|
output.rgba = background.rgba;
|
|
else
|
|
{
|
|
// don't go too high
|
|
if (fullalpha >= 0xFF)
|
|
fullalpha = 0xFF;
|
|
alpha = (UINT8)fullalpha;
|
|
|
|
// if the background pixel is empty,
|
|
// match software and don't blend anything
|
|
if (!background.s.alpha)
|
|
{
|
|
// ...unless the foreground pixel ISN'T actually translucent.
|
|
if (alpha == 0xFF)
|
|
output.rgba = foreground.rgba;
|
|
else
|
|
output.rgba = 0;
|
|
}
|
|
else
|
|
{
|
|
UINT8 beta = (0xFF - alpha);
|
|
output.s.red = ((background.s.red * beta) + (foreground.s.red * alpha)) / 0xFF;
|
|
output.s.green = ((background.s.green * beta) + (foreground.s.green * alpha)) / 0xFF;
|
|
output.s.blue = ((background.s.blue * beta) + (foreground.s.blue * alpha)) / 0xFF;
|
|
output.s.alpha = 0xFF;
|
|
}
|
|
}
|
|
return output.rgba;
|
|
}
|
|
#define clamp_rgb(c) max(min(c, 0xFF), 0x00);
|
|
else
|
|
{
|
|
float falpha = ((float)alpha / 255.0f);
|
|
float fr = ((float)foreground.s.red * falpha);
|
|
float fg = ((float)foreground.s.green * falpha);
|
|
float fb = ((float)foreground.s.blue * falpha);
|
|
if (style == AST_ADD)
|
|
{
|
|
output.s.red = clamp_rgb((int)(background.s.red + fr));
|
|
output.s.green = clamp_rgb((int)(background.s.green + fg));
|
|
output.s.blue = clamp_rgb((int)(background.s.blue + fb));
|
|
}
|
|
else if (style == AST_SUBTRACT)
|
|
{
|
|
output.s.red = clamp_rgb((int)(background.s.red - fr));
|
|
output.s.green = clamp_rgb((int)(background.s.green - fg));
|
|
output.s.blue = clamp_rgb((int)(background.s.blue - fb));
|
|
}
|
|
else if (style == AST_REVERSESUBTRACT)
|
|
{
|
|
output.s.red = clamp_rgb((int)((-background.s.red) + fr));
|
|
output.s.green = clamp_rgb((int)((-background.s.green) + fg));
|
|
output.s.blue = clamp_rgb((int)((-background.s.blue) + fb));
|
|
}
|
|
else if (style == AST_MODULATE)
|
|
{
|
|
fr = ((float)foreground.s.red / 256.0f);
|
|
fg = ((float)foreground.s.green / 256.0f);
|
|
fb = ((float)foreground.s.blue / 256.0f);
|
|
output.s.red = clamp_rgb((int)(background.s.red * fr));
|
|
output.s.green = clamp_rgb((int)(background.s.green * fg));
|
|
output.s.blue = clamp_rgb((int)(background.s.blue * fb));
|
|
}
|
|
// just copy the pixel
|
|
else if (style == AST_COPY)
|
|
output.rgba = foreground.rgba;
|
|
|
|
output.s.alpha = 0xFF;
|
|
return output.rgba;
|
|
}
|
|
#undef clamp_rgb
|
|
return 0;
|
|
}
|
|
|
|
INT32 ASTTextureBlendingThreshold[2] = {255/11, (10*255/11)};
|
|
|
|
// Blends a pixel for a texture patch.
|
|
UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
|
|
{
|
|
// Alpha style set to translucent?
|
|
if (style == AST_TRANSLUCENT)
|
|
{
|
|
// Is the alpha small enough for translucency?
|
|
if (alpha <= ASTTextureBlendingThreshold[1])
|
|
{
|
|
// Is the patch way too translucent? Don't blend then.
|
|
if (alpha < ASTTextureBlendingThreshold[0])
|
|
return background.rgba;
|
|
|
|
return ASTBlendPixel(background, foreground, style, alpha);
|
|
}
|
|
else // just copy the pixel
|
|
return foreground.rgba;
|
|
}
|
|
else
|
|
return ASTBlendPixel(background, foreground, style, alpha);
|
|
}
|
|
|
|
// Blends two palette indexes for a texture patch, then
|
|
// finds the nearest palette index from the blended output.
|
|
UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha)
|
|
{
|
|
// Alpha style set to translucent?
|
|
if (style == AST_TRANSLUCENT)
|
|
{
|
|
// Is the alpha small enough for translucency?
|
|
if (alpha <= ASTTextureBlendingThreshold[1])
|
|
{
|
|
UINT8 *mytransmap;
|
|
INT32 trans;
|
|
|
|
// Is the patch way too translucent? Don't blend then.
|
|
if (alpha < ASTTextureBlendingThreshold[0])
|
|
return background;
|
|
|
|
// The equation's not exact but it works as intended. I'll call it a day for now.
|
|
trans = (8*(alpha) + 255/8)/(255 - 255/11);
|
|
mytransmap = R_GetTranslucencyTable(trans + 1);
|
|
if (background != 0xFF)
|
|
return *(mytransmap + (background<<8) + foreground);
|
|
}
|
|
else // just copy the pixel
|
|
return foreground;
|
|
}
|
|
// just copy the pixel
|
|
else if (style == AST_COPY)
|
|
return foreground;
|
|
// use ASTBlendPixel for all other blend modes
|
|
// and find the nearest colour in the palette
|
|
else if (style != AST_TRANSLUCENT)
|
|
{
|
|
RGBA_t texel;
|
|
RGBA_t bg = V_GetMasterColor(background);
|
|
RGBA_t fg = V_GetMasterColor(foreground);
|
|
texel.rgba = ASTBlendPixel(bg, fg, style, alpha);
|
|
return NearestColor(texel.s.red, texel.s.green, texel.s.blue);
|
|
}
|
|
// fallback if all above fails, somehow
|
|
// return the background pixel
|
|
return background;
|
|
}
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
static lumplist_t *colormaplumps = NULL; ///\todo free leak
|
|
static size_t numcolormaplumps = 0;
|
|
|
|
static inline lumpnum_t R_CheckNumForNameList(const char *name, lumplist_t *list, size_t listsize)
|
|
{
|
|
size_t i;
|
|
UINT16 lump;
|
|
|
|
for (i = listsize - 1; i < INT16_MAX; i--)
|
|
{
|
|
lump = W_CheckNumForNamePwad(name, list[i].wadfile, list[i].firstlump);
|
|
if (lump == INT16_MAX || lump > (list[i].firstlump + list[i].numlumps))
|
|
continue;
|
|
else
|
|
return (list[i].wadfile<<16)+lump;
|
|
}
|
|
return LUMPERROR;
|
|
}
|
|
|
|
static void R_InitExtraColormaps(void)
|
|
{
|
|
lumpnum_t startnum, endnum;
|
|
UINT16 cfile, clump;
|
|
static size_t maxcolormaplumps = 16;
|
|
|
|
for (cfile = clump = 0; cfile < numwadfiles; cfile++, clump = 0)
|
|
{
|
|
startnum = W_CheckNumForNamePwad("C_START", cfile, clump);
|
|
if (startnum == INT16_MAX)
|
|
continue;
|
|
|
|
endnum = W_CheckNumForNamePwad("C_END", cfile, clump);
|
|
|
|
if (endnum == INT16_MAX)
|
|
I_Error("R_InitExtraColormaps: C_START without C_END\n");
|
|
|
|
// This shouldn't be possible when you use the Pwad function, silly
|
|
//if (WADFILENUM(startnum) != WADFILENUM(endnum))
|
|
//I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
|
|
|
|
if (numcolormaplumps >= maxcolormaplumps)
|
|
maxcolormaplumps *= 2;
|
|
colormaplumps = Z_Realloc(colormaplumps,
|
|
sizeof (*colormaplumps) * maxcolormaplumps, PU_STATIC, NULL);
|
|
colormaplumps[numcolormaplumps].wadfile = cfile;
|
|
colormaplumps[numcolormaplumps].firstlump = startnum+1;
|
|
colormaplumps[numcolormaplumps].numlumps = endnum - (startnum + 1);
|
|
numcolormaplumps++;
|
|
}
|
|
CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// R_InitColormaps
|
|
//
|
|
void R_InitColormaps(void)
|
|
{
|
|
size_t len;
|
|
lumpnum_t lump;
|
|
|
|
// Load in the light tables
|
|
lump = W_GetNumForName("COLORMAP");
|
|
len = W_LumpLength(lump);
|
|
if (len < COLORMAP_SIZE*2) // accomodate encore mode later
|
|
len = COLORMAP_SIZE*2;
|
|
colormaps = Z_MallocAlign(len, PU_STATIC, NULL, 8);
|
|
W_ReadLump(lump, colormaps);
|
|
// no need to init encoremap at this stage
|
|
|
|
// Init Boom colormaps.
|
|
R_ClearColormaps();
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
R_InitExtraColormaps();
|
|
#endif
|
|
}
|
|
|
|
void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize)
|
|
{
|
|
char colormap[9] = "COLORMAP";
|
|
lumpnum_t lump;
|
|
const lumpnum_t basecolormaplump = W_GetNumForName(colormap);
|
|
if (num > 0 && num <= 10000)
|
|
snprintf(colormap, 8, "CLM%04u", num-1);
|
|
|
|
// Load in the light tables, now 64k aligned for smokie...
|
|
lump = W_GetNumForName(colormap);
|
|
if (lump == LUMPERROR)
|
|
lump = basecolormaplump;
|
|
else
|
|
{
|
|
if (W_LumpLength(lump) != W_LumpLength(basecolormaplump))
|
|
{
|
|
CONS_Alert(CONS_WARNING, "%s lump size does not match COLORMAP, results may be unexpected.\n", colormap);
|
|
}
|
|
}
|
|
|
|
W_ReadLumpHeader(lump, colormaps, W_LumpLength(basecolormaplump), 0U);
|
|
|
|
// Encore mode.
|
|
if (newencoremap)
|
|
{
|
|
lighttable_t *colormap_p, *colormap_p2;
|
|
size_t p, i;
|
|
|
|
I_Assert(encoremapsize == 256);
|
|
|
|
encoremap = Z_MallocAlign(256 + 10, PU_LEVEL, NULL, 8);
|
|
M_Memcpy(encoremap, newencoremap, encoremapsize);
|
|
colormap_p = colormap_p2 = colormaps;
|
|
colormap_p += COLORMAP_REMAPOFFSET;
|
|
|
|
for (p = 0; p < LIGHTLEVELS; p++)
|
|
{
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
*colormap_p = colormap_p2[encoremap[i]];
|
|
colormap_p++;
|
|
}
|
|
colormap_p2 += 256;
|
|
}
|
|
}
|
|
else
|
|
encoremap = NULL;
|
|
|
|
// Init Boom colormaps.
|
|
R_ClearColormaps();
|
|
}
|
|
|
|
//
|
|
// R_ClearColormaps
|
|
//
|
|
// Clears out extra colormaps between levels.
|
|
//
|
|
void R_ClearColormaps(void)
|
|
{
|
|
// Purged by PU_LEVEL, just overwrite the pointer
|
|
extra_colormaps = R_CreateDefaultColormap(true);
|
|
}
|
|
|
|
//
|
|
// R_CreateDefaultColormap()
|
|
// NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself!
|
|
//
|
|
extracolormap_t *R_CreateDefaultColormap(boolean lighttable)
|
|
{
|
|
extracolormap_t *exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
|
|
exc->fadestart = 0;
|
|
exc->fadeend = 31;
|
|
exc->flags = 0;
|
|
exc->rgba = 0;
|
|
exc->fadergba = 0x19000000;
|
|
exc->colormap = lighttable ? R_CreateLightTable(exc) : NULL;
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
exc->lump = LUMPERROR;
|
|
exc->lumpname[0] = 0;
|
|
#endif
|
|
exc->next = exc->prev = NULL;
|
|
return exc;
|
|
}
|
|
|
|
//
|
|
// R_GetDefaultColormap()
|
|
//
|
|
extracolormap_t *R_GetDefaultColormap(void)
|
|
{
|
|
#ifdef COLORMAPREVERSELIST
|
|
extracolormap_t *exc;
|
|
#endif
|
|
|
|
if (!extra_colormaps)
|
|
return (extra_colormaps = R_CreateDefaultColormap(true));
|
|
|
|
#ifdef COLORMAPREVERSELIST
|
|
for (exc = extra_colormaps; exc->next; exc = exc->next);
|
|
return exc;
|
|
#else
|
|
return extra_colormaps;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// R_CopyColormap()
|
|
// NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself!
|
|
//
|
|
extracolormap_t *R_CopyColormap(extracolormap_t *extra_colormap, boolean lighttable)
|
|
{
|
|
extracolormap_t *exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
|
|
|
|
if (!extra_colormap)
|
|
extra_colormap = R_GetDefaultColormap();
|
|
|
|
*exc = *extra_colormap;
|
|
exc->next = exc->prev = NULL;
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
strncpy(exc->lumpname, extra_colormap->lumpname, 9);
|
|
|
|
if (exc->lump != LUMPERROR && lighttable)
|
|
{
|
|
// aligned on 8 bit for asm code
|
|
exc->colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16);
|
|
W_ReadLump(lump, exc->colormap);
|
|
}
|
|
else
|
|
#endif
|
|
if (lighttable)
|
|
exc->colormap = R_CreateLightTable(exc);
|
|
else
|
|
exc->colormap = NULL;
|
|
|
|
return exc;
|
|
}
|
|
|
|
//
|
|
// R_AddColormapToList
|
|
//
|
|
// Sets prev/next chain for extra_colormaps var
|
|
// Copypasta from P_AddFFloorToList
|
|
//
|
|
void R_AddColormapToList(extracolormap_t *extra_colormap)
|
|
{
|
|
#ifndef COLORMAPREVERSELIST
|
|
extracolormap_t *exc;
|
|
#endif
|
|
|
|
if (!extra_colormaps)
|
|
{
|
|
extra_colormaps = extra_colormap;
|
|
extra_colormap->next = 0;
|
|
extra_colormap->prev = 0;
|
|
return;
|
|
}
|
|
|
|
#ifdef COLORMAPREVERSELIST
|
|
extra_colormaps->prev = extra_colormap;
|
|
extra_colormap->next = extra_colormaps;
|
|
extra_colormaps = extra_colormap;
|
|
extra_colormap->prev = 0;
|
|
#else
|
|
for (exc = extra_colormaps; exc->next; exc = exc->next);
|
|
|
|
exc->next = extra_colormap;
|
|
extra_colormap->prev = exc;
|
|
extra_colormap->next = 0;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// R_CheckDefaultColormapByValues()
|
|
//
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
|
|
INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags, lumpnum_t lump)
|
|
#else
|
|
boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
|
|
INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags)
|
|
#endif
|
|
{
|
|
return (
|
|
(!checkparams ? true :
|
|
(fadestart == 0
|
|
&& fadeend == 31
|
|
&& !flags)
|
|
)
|
|
&& (!checkrgba ? true : rgba == 0)
|
|
&& (!checkfadergba ? true : fadergba == 0x19000000)
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
&& lump == LUMPERROR
|
|
&& extra_colormap->lumpname[0] == 0
|
|
#endif
|
|
);
|
|
}
|
|
|
|
boolean R_CheckDefaultColormap(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams)
|
|
{
|
|
if (!extra_colormap)
|
|
return true;
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags, extra_colormap->lump);
|
|
#else
|
|
return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags);
|
|
#endif
|
|
}
|
|
|
|
boolean R_CheckEqualColormaps(extracolormap_t *exc_a, extracolormap_t *exc_b, boolean checkrgba, boolean checkfadergba, boolean checkparams)
|
|
{
|
|
// Treat NULL as default colormap
|
|
// We need this because what if one exc is a default colormap, and the other is NULL? They're really both equal.
|
|
if (!exc_a)
|
|
exc_a = R_GetDefaultColormap();
|
|
if (!exc_b)
|
|
exc_b = R_GetDefaultColormap();
|
|
|
|
if (exc_a == exc_b)
|
|
return true;
|
|
|
|
return (
|
|
(!checkparams ? true :
|
|
(exc_a->fadestart == exc_b->fadestart
|
|
&& exc_a->fadeend == exc_b->fadeend
|
|
&& exc_a->flags == exc_b->flags)
|
|
)
|
|
&& (!checkrgba ? true : exc_a->rgba == exc_b->rgba)
|
|
&& (!checkfadergba ? true : exc_a->fadergba == exc_b->fadergba)
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
&& exc_a->lump == exc_b->lump
|
|
&& !strncmp(exc_a->lumpname, exc_b->lumpname, 9)
|
|
#endif
|
|
);
|
|
}
|
|
|
|
//
|
|
// R_GetColormapFromListByValues()
|
|
// NOTE: Returns NULL if no match is found
|
|
//
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags, lumpnum_t lump)
|
|
#else
|
|
extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags)
|
|
#endif
|
|
{
|
|
extracolormap_t *exc;
|
|
UINT32 dbg_i = 0;
|
|
|
|
for (exc = extra_colormaps; exc; exc = exc->next)
|
|
{
|
|
if (rgba == exc->rgba
|
|
&& fadergba == exc->fadergba
|
|
&& fadestart == exc->fadestart
|
|
&& fadeend == exc->fadeend
|
|
&& flags == exc->flags
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
&& (lump != LUMPERROR && lump == exc->lump)
|
|
#endif
|
|
)
|
|
{
|
|
CONS_Debug(DBG_RENDER, "Found Colormap %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
|
|
dbg_i, R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba),
|
|
R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba));
|
|
return exc;
|
|
}
|
|
dbg_i++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap)
|
|
{
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags, extra_colormap->lump);
|
|
#else
|
|
return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->flags);
|
|
#endif
|
|
}
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
extracolormap_t *R_ColormapForName(char *name)
|
|
{
|
|
lumpnum_t lump;
|
|
extracolormap_t *exc;
|
|
|
|
lump = R_CheckNumForNameList(name, colormaplumps, numcolormaplumps);
|
|
if (lump == LUMPERROR)
|
|
I_Error("R_ColormapForName: Cannot find colormap lump %.8s\n", name);
|
|
|
|
exc = R_GetColormapFromListByValues(0, 0x19000000, 0, 31, 0, lump);
|
|
if (exc)
|
|
return exc;
|
|
|
|
exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
|
|
|
|
exc->lump = lump;
|
|
strncpy(exc->lumpname, name, 9);
|
|
exc->lumpname[8] = 0;
|
|
|
|
// aligned on 8 bit for asm code
|
|
exc->colormap = Z_MallocAlign(W_LumpLength(lump), PU_LEVEL, NULL, 16);
|
|
W_ReadLump(lump, exc->colormap);
|
|
|
|
// We set all params of the colormap to normal because there
|
|
// is no real way to tell how GL should handle a colormap lump anyway..
|
|
exc->fadestart = 0;
|
|
exc->fadeend = 31;
|
|
exc->flags = 0;
|
|
exc->rgba = 0;
|
|
exc->fadergba = 0x19000000;
|
|
|
|
R_AddColormapToList(exc);
|
|
|
|
return exc;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// R_CreateColormapFromLinedef
|
|
//
|
|
// This is a more GL friendly way of doing colormaps: Specify colormap
|
|
// data in a special linedef's texture areas and use that to generate
|
|
// custom colormaps at runtime. NOTE: For GL mode, we only need to color
|
|
// data and not the colormap data.
|
|
//
|
|
static double brightChange[256], map[256][3];
|
|
|
|
static int RoundUp(double number);
|
|
|
|
lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
|
|
{
|
|
double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb, cdestbright;
|
|
double maskamt = 0, othermask = 0;
|
|
double fmaskamt = 0, fothermask = 0;
|
|
|
|
UINT8 cr = R_GetRgbaR(extra_colormap->rgba),
|
|
cg = R_GetRgbaG(extra_colormap->rgba),
|
|
cb = R_GetRgbaB(extra_colormap->rgba),
|
|
ca = R_GetRgbaA(extra_colormap->rgba),
|
|
cfr = R_GetRgbaR(extra_colormap->fadergba),
|
|
cfg = R_GetRgbaG(extra_colormap->fadergba),
|
|
cfb = R_GetRgbaB(extra_colormap->fadergba),
|
|
cfa = R_GetRgbaA(extra_colormap->fadergba);
|
|
|
|
UINT8 fadestart = extra_colormap->fadestart,
|
|
fadedist = extra_colormap->fadeend - extra_colormap->fadestart;
|
|
|
|
lighttable_t *lighttable = NULL;
|
|
size_t i;
|
|
|
|
/////////////////////
|
|
// Calc the RGBA mask
|
|
/////////////////////
|
|
cmaskr = cr;
|
|
cmaskg = cg;
|
|
cmaskb = cb;
|
|
|
|
maskamt = (double)(ca/24.0l);
|
|
othermask = 1 - maskamt;
|
|
maskamt /= 0xff;
|
|
|
|
cmaskr *= maskamt;
|
|
cmaskg *= maskamt;
|
|
cmaskb *= maskamt;
|
|
|
|
/////////////////////
|
|
// Calc the RGBA fade mask
|
|
/////////////////////
|
|
cdestr = cfr;
|
|
cdestg = cfg;
|
|
cdestb = cfb;
|
|
cdestbright = sqrt((cfr*cfr) + (cfg*cfg) + (cfb*cfb));
|
|
|
|
fmaskamt = (double)(cfa/24.0l);
|
|
fothermask = 1 - fmaskamt;
|
|
//fmaskamt /= 0xff;
|
|
|
|
(void)fothermask; // unused, but don't feel like commenting it out
|
|
|
|
/////////////////////
|
|
// This code creates the colormap array used by software renderer
|
|
/////////////////////
|
|
{
|
|
double r, g, b, cbrightness, cbest, cdist;
|
|
int p;
|
|
lighttable_t *colormap_p;
|
|
|
|
// Initialise the map and delta arrays
|
|
// map[i] stores an RGB color (as double) for index i,
|
|
// which is then converted to SRB2's palette later
|
|
// brightChange[i] is the value added/subtracted every step for the fade;
|
|
// map[i]'s values are in/decremented by it after each use
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
r = pMasterPalette[i].s.red;
|
|
g = pMasterPalette[i].s.green;
|
|
b = pMasterPalette[i].s.blue;
|
|
cbrightness = sqrt((r*r) + (g*g) + (b*b));
|
|
|
|
map[i][0] = (cbrightness * cmaskr) + (r * othermask);
|
|
if (map[i][0] > 255.0l)
|
|
map[i][0] = 255.0l;
|
|
|
|
map[i][1] = (cbrightness * cmaskg) + (g * othermask);
|
|
if (map[i][1] > 255.0l)
|
|
map[i][1] = 255.0l;
|
|
|
|
map[i][2] = (cbrightness * cmaskb) + (b * othermask);
|
|
if (map[i][2] > 255.0l)
|
|
map[i][2] = 255.0l;
|
|
|
|
// Get the "best" color.
|
|
// Our brightest color's value, if we're fading to a darker color,
|
|
// or our (inverted) darkest color's value, if we're fading to a brighter color.
|
|
if (cbrightness < cdestbright)
|
|
{
|
|
cbest = 255.0l - min(r, min(g, b));
|
|
cdist = 255.0l - max(cdestr, max(cdestg, cdestb));
|
|
}
|
|
else
|
|
{
|
|
cbest = max(r, max(g, b));
|
|
cdist = min(cdestr, min(cdestg, cdestb));
|
|
}
|
|
|
|
// Add/subtract this value during fading.
|
|
brightChange[i] = (fabs(cbest - cdist) / (double)fadedist) * fmaskamt;
|
|
}
|
|
|
|
// Now allocate memory for the actual colormap array itself!
|
|
// aligned on 8 bit for asm code
|
|
colormap_p = Z_MallocAlign((COLORMAP_SIZE * (encoremap ? 2 : 1)) + 10, PU_LEVEL, NULL, 8);
|
|
lighttable = (UINT8 *)colormap_p;
|
|
|
|
// Calculate the palette index for each palette index, for each light level
|
|
// (as well as the two unused colormap lines we inherited from Doom)
|
|
for (p = 0; p < LIGHTLEVELS; p++)
|
|
{
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
*colormap_p = NearestColor((UINT8)RoundUp(map[i][0]),
|
|
(UINT8)RoundUp(map[i][1]),
|
|
(UINT8)RoundUp(map[i][2]));
|
|
colormap_p++;
|
|
|
|
if ((UINT32)p < fadestart)
|
|
continue;
|
|
|
|
// Add/subtract towards the destination color.
|
|
if (fabs(map[i][0] - cdestr) <= brightChange[i])
|
|
map[i][0] = cdestr;
|
|
else if (map[i][0] > cdestr)
|
|
map[i][0] -= brightChange[i];
|
|
else
|
|
map[i][0] += brightChange[i];
|
|
|
|
if (fabs(map[i][1] - cdestg) <= brightChange[i])
|
|
map[i][1] = cdestg;
|
|
else if (map[i][1] > cdestg)
|
|
map[i][1] -= brightChange[i];
|
|
else
|
|
map[i][1] += brightChange[i];
|
|
|
|
if (fabs(map[i][2] - cdestb) <= brightChange[i])
|
|
map[i][2] = cdestb;
|
|
else if (map[i][2] > cdestb)
|
|
map[i][2] -= brightChange[i];
|
|
else
|
|
map[i][2] += brightChange[i];
|
|
}
|
|
}
|
|
|
|
if (encoremap)
|
|
{
|
|
lighttable_t *colormap_p2 = lighttable;
|
|
|
|
for (p = 0; p < LIGHTLEVELS; p++)
|
|
{
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
*colormap_p = colormap_p2[encoremap[i]];
|
|
colormap_p++;
|
|
}
|
|
colormap_p2 += 256;
|
|
}
|
|
}
|
|
}
|
|
|
|
return lighttable;
|
|
}
|
|
|
|
extracolormap_t *R_CreateColormapFromLinedef(char *p1, char *p2, char *p3)
|
|
{
|
|
// default values
|
|
UINT8 cr = 0, cg = 0, cb = 0, ca = 0, cfr = 0, cfg = 0, cfb = 0, cfa = 25;
|
|
UINT32 fadestart = 0, fadeend = 31;
|
|
UINT8 flags = 0;
|
|
INT32 rgba = 0, fadergba = 0x19000000;
|
|
|
|
#define HEX2INT(x) (UINT32)(x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0)
|
|
#define ALPHA2INT(x) (x >= 'a' && x <= 'z' ? x - 'a' : x >= 'A' && x <= 'Z' ? x - 'A' : x >= '0' && x <= '9' ? 25 : 0)
|
|
|
|
// Get base colormap value
|
|
// First alpha-only, then full value
|
|
if (p1[0] >= 'a' && p1[0] <= 'z' && !p1[1])
|
|
ca = (p1[0] - 'a');
|
|
else if (p1[0] == '#' && p1[1] >= 'a' && p1[1] <= 'z' && !p1[2])
|
|
ca = (p1[1] - 'a');
|
|
else if (p1[0] >= 'A' && p1[0] <= 'Z' && !p1[1])
|
|
ca = (p1[0] - 'A');
|
|
else if (p1[0] == '#' && p1[1] >= 'A' && p1[1] <= 'Z' && !p1[2])
|
|
ca = (p1[1] - 'A');
|
|
else if (p1[0] == '#')
|
|
{
|
|
// For each subsequent value, the value before it must exist
|
|
// If we don't get every value, then set alpha to max
|
|
if (p1[1] && p1[2])
|
|
{
|
|
cr = ((HEX2INT(p1[1]) * 16) + HEX2INT(p1[2]));
|
|
if (p1[3] && p1[4])
|
|
{
|
|
cg = ((HEX2INT(p1[3]) * 16) + HEX2INT(p1[4]));
|
|
if (p1[5] && p1[6])
|
|
{
|
|
cb = ((HEX2INT(p1[5]) * 16) + HEX2INT(p1[6]));
|
|
|
|
if (p1[7] >= 'a' && p1[7] <= 'z')
|
|
ca = (p1[7] - 'a');
|
|
else if (p1[7] >= 'A' && p1[7] <= 'Z')
|
|
ca = (p1[7] - 'A');
|
|
else
|
|
ca = 25;
|
|
}
|
|
else
|
|
ca = 25;
|
|
}
|
|
else
|
|
ca = 25;
|
|
}
|
|
else
|
|
ca = 25;
|
|
}
|
|
|
|
#define NUMFROMCHAR(c) (c >= '0' && c <= '9' ? c - '0' : 0)
|
|
|
|
// Get parameters like fadestart, fadeend, and flags
|
|
if (p2[0] == '#')
|
|
{
|
|
if (p2[1])
|
|
{
|
|
flags = NUMFROMCHAR(p2[1]);
|
|
if (p2[2] && p2[3])
|
|
{
|
|
fadestart = NUMFROMCHAR(p2[3]) + (NUMFROMCHAR(p2[2]) * 10);
|
|
if (p2[4] && p2[5])
|
|
fadeend = NUMFROMCHAR(p2[5]) + (NUMFROMCHAR(p2[4]) * 10);
|
|
}
|
|
}
|
|
|
|
if (fadestart > 30)
|
|
fadestart = 0;
|
|
if (fadeend > 31 || fadeend < 1)
|
|
fadeend = 31;
|
|
}
|
|
|
|
#undef NUMFROMCHAR
|
|
|
|
// Get fade (dark) colormap value
|
|
// First alpha-only, then full value
|
|
if (p3[0] >= 'a' && p3[0] <= 'z' && !p3[1])
|
|
cfa = (p3[0] - 'a');
|
|
else if (p3[0] == '#' && p3[1] >= 'a' && p3[1] <= 'z' && !p3[2])
|
|
cfa = (p3[1] - 'a');
|
|
else if (p3[0] >= 'A' && p3[0] <= 'Z' && !p3[1])
|
|
cfa = (p3[0] - 'A');
|
|
else if (p3[0] == '#' && p3[1] >= 'A' && p3[1] <= 'Z' && !p3[2])
|
|
cfa = (p3[1] - 'A');
|
|
else if (p3[0] == '#')
|
|
{
|
|
// For each subsequent value, the value before it must exist
|
|
// If we don't get every value, then set alpha to max
|
|
if (p3[1] && p3[2])
|
|
{
|
|
cfr = ((HEX2INT(p3[1]) * 16) + HEX2INT(p3[2]));
|
|
if (p3[3] && p3[4])
|
|
{
|
|
cfg = ((HEX2INT(p3[3]) * 16) + HEX2INT(p3[4]));
|
|
if (p3[5] && p3[6])
|
|
{
|
|
cfb = ((HEX2INT(p3[5]) * 16) + HEX2INT(p3[6]));
|
|
|
|
if (p3[7] >= 'a' && p3[7] <= 'z')
|
|
cfa = (p3[7] - 'a');
|
|
else if (p3[7] >= 'A' && p3[7] <= 'Z')
|
|
cfa = (p3[7] - 'A');
|
|
else
|
|
cfa = 25;
|
|
}
|
|
else
|
|
cfa = 25;
|
|
}
|
|
else
|
|
cfa = 25;
|
|
}
|
|
else
|
|
cfa = 25;
|
|
}
|
|
#undef ALPHA2INT
|
|
#undef HEX2INT
|
|
|
|
if (encoremap)
|
|
{
|
|
UINT8 j = encoremap[NearestColor((UINT8)cr, (UINT8)cg, (UINT8)cb)];
|
|
//CONS_Printf("R_CreateColormap: encoremap[%d] = %d\n", j, encoremap[j]);
|
|
cr = pLocalPalette[j].s.red;
|
|
cg = pLocalPalette[j].s.green;
|
|
cb = pLocalPalette[j].s.blue;
|
|
}
|
|
|
|
// Pack rgba values into combined var
|
|
// OpenGL also uses this instead of lighttables for rendering
|
|
rgba = R_PutRgbaRGBA(cr, cg, cb, ca);
|
|
fadergba = R_PutRgbaRGBA(cfr, cfg, cfb, cfa);
|
|
|
|
return R_CreateColormap(rgba, fadergba, fadestart, fadeend, flags);
|
|
}
|
|
|
|
extracolormap_t *R_CreateColormap(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags)
|
|
{
|
|
extracolormap_t *extra_colormap;
|
|
|
|
// Did we just make a default colormap?
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, flags, LUMPERROR))
|
|
return NULL;
|
|
#else
|
|
if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, flags))
|
|
return NULL;
|
|
#endif
|
|
|
|
// Look for existing colormaps
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
extra_colormap = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags, LUMPERROR);
|
|
#else
|
|
extra_colormap = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags);
|
|
#endif
|
|
if (extra_colormap)
|
|
return extra_colormap;
|
|
|
|
CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%x) fadergba(%x)\n", rgba, fadergba);
|
|
|
|
extra_colormap = Z_Calloc(sizeof(*extra_colormap), PU_LEVEL, NULL);
|
|
|
|
extra_colormap->fadestart = (UINT16)fadestart;
|
|
extra_colormap->fadeend = (UINT16)fadeend;
|
|
extra_colormap->flags = flags;
|
|
|
|
extra_colormap->rgba = rgba;
|
|
extra_colormap->fadergba = fadergba;
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
extra_colormap->lump = LUMPERROR;
|
|
extra_colormap->lumpname[0] = 0;
|
|
#endif
|
|
|
|
// Having lighttables for alpha-only entries is kind of pointless,
|
|
// but if there happens to be a matching rgba entry that is NOT alpha-only (but has same rgb values),
|
|
// then it needs this lighttable because we share matching entries.
|
|
extra_colormap->colormap = R_CreateLightTable(extra_colormap);
|
|
|
|
R_AddColormapToList(extra_colormap);
|
|
|
|
return extra_colormap;
|
|
}
|
|
|
|
//
|
|
// R_AddColormaps()
|
|
// NOTE: The result colormap is not added to the extra_colormaps chain. You must do that yourself!
|
|
//
|
|
extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend,
|
|
boolean subR, boolean subG, boolean subB, boolean subA,
|
|
boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA,
|
|
boolean subFadeStart, boolean subFadeEnd, boolean ignoreFlags,
|
|
boolean lighttable)
|
|
{
|
|
INT16 red, green, blue, alpha;
|
|
|
|
// exc_augend is added (or subtracted) onto by exc_addend
|
|
// In Rennaisance times, the first number was considered the augend, the second number the addend
|
|
// But since the commutative property was discovered, today they're both called addends!
|
|
// So let's be Olde English for a hot second.
|
|
|
|
exc_augend = R_CopyColormap(exc_augend, false);
|
|
if(!exc_addend)
|
|
exc_addend = R_GetDefaultColormap();
|
|
|
|
///////////////////
|
|
// base rgba
|
|
///////////////////
|
|
|
|
red = max(min(
|
|
R_GetRgbaR(exc_augend->rgba)
|
|
+ (subR ? -1 : 1) // subtract R
|
|
* R_GetRgbaR(exc_addend->rgba)
|
|
, 255), 0);
|
|
|
|
green = max(min(
|
|
R_GetRgbaG(exc_augend->rgba)
|
|
+ (subG ? -1 : 1) // subtract G
|
|
* R_GetRgbaG(exc_addend->rgba)
|
|
, 255), 0);
|
|
|
|
blue = max(min(
|
|
R_GetRgbaB(exc_augend->rgba)
|
|
+ (subB ? -1 : 1) // subtract B
|
|
* R_GetRgbaB(exc_addend->rgba)
|
|
, 255), 0);
|
|
|
|
alpha = R_GetRgbaA(exc_addend->rgba);
|
|
alpha = max(min(R_GetRgbaA(exc_augend->rgba) + (subA ? -1 : 1) * alpha, 25), 0);
|
|
|
|
exc_augend->rgba = R_PutRgbaRGBA(red, green, blue, alpha);
|
|
|
|
///////////////////
|
|
// fade/dark rgba
|
|
///////////////////
|
|
|
|
red = max(min(
|
|
R_GetRgbaR(exc_augend->fadergba)
|
|
+ (subFadeR ? -1 : 1) // subtract R
|
|
* R_GetRgbaR(exc_addend->fadergba)
|
|
, 255), 0);
|
|
|
|
green = max(min(
|
|
R_GetRgbaG(exc_augend->fadergba)
|
|
+ (subFadeG ? -1 : 1) // subtract G
|
|
* R_GetRgbaG(exc_addend->fadergba)
|
|
, 255), 0);
|
|
|
|
blue = max(min(
|
|
R_GetRgbaB(exc_augend->fadergba)
|
|
+ (subFadeB ? -1 : 1) // subtract B
|
|
* R_GetRgbaB(exc_addend->fadergba)
|
|
, 255), 0);
|
|
|
|
alpha = R_GetRgbaA(exc_addend->fadergba);
|
|
if (alpha == 25 && !R_GetRgbaRGB(exc_addend->fadergba))
|
|
alpha = 0; // HACK: fadergba A defaults at 25, so don't add anything in this case
|
|
alpha = max(min(R_GetRgbaA(exc_augend->fadergba) + (subFadeA ? -1 : 1) * alpha, 25), 0);
|
|
|
|
exc_augend->fadergba = R_PutRgbaRGBA(red, green, blue, alpha);
|
|
|
|
///////////////////
|
|
// parameters
|
|
///////////////////
|
|
|
|
exc_augend->fadestart = max(min(
|
|
exc_augend->fadestart
|
|
+ (subFadeStart ? -1 : 1) // subtract fadestart
|
|
* exc_addend->fadestart
|
|
, 31), 0);
|
|
|
|
exc_augend->fadeend = max(min(
|
|
exc_augend->fadeend
|
|
+ (subFadeEnd ? -1 : 1) // subtract fadeend
|
|
* (exc_addend->fadeend == 31 && !exc_addend->fadestart ? 0 : exc_addend->fadeend)
|
|
// HACK: fadeend defaults to 31, so don't add anything in this case
|
|
, 31), 0);
|
|
|
|
if (!ignoreFlags) // overwrite flags with new value
|
|
exc_augend->flags = exc_addend->flags;
|
|
|
|
///////////////////
|
|
// put it together
|
|
///////////////////
|
|
|
|
exc_augend->colormap = lighttable ? R_CreateLightTable(exc_augend) : NULL;
|
|
exc_augend->next = exc_augend->prev = NULL;
|
|
return exc_augend;
|
|
}
|
|
|
|
// Thanks to quake2 source!
|
|
// utils3/qdata/images.c
|
|
UINT8 NearestPaletteColor(UINT8 r, UINT8 g, UINT8 b, RGBA_t *palette)
|
|
{
|
|
int dr, dg, db;
|
|
int distortion, bestdistortion = 256 * 256 * 4, bestcolor = 0, i;
|
|
|
|
// Use master palette if none specified
|
|
if (palette == NULL)
|
|
palette = pMasterPalette;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
dr = r - palette[i].s.red;
|
|
dg = g - palette[i].s.green;
|
|
db = b - palette[i].s.blue;
|
|
distortion = dr*dr + dg*dg + db*db;
|
|
if (distortion < bestdistortion)
|
|
{
|
|
if (!distortion)
|
|
return (UINT8)i;
|
|
|
|
bestdistortion = distortion;
|
|
bestcolor = i;
|
|
}
|
|
}
|
|
|
|
return (UINT8)bestcolor;
|
|
}
|
|
|
|
// Rounds off floating numbers and checks for 0 - 255 bounds
|
|
static int RoundUp(double number)
|
|
{
|
|
if (number > 255.0l)
|
|
return 255;
|
|
if (number < 0.0l)
|
|
return 0;
|
|
|
|
if ((int)number <= (int)(number - 0.5f))
|
|
return (int)number + 1;
|
|
|
|
return (int)number;
|
|
}
|
|
|
|
#ifdef EXTRACOLORMAPLUMPS
|
|
const char *R_NameForColormap(extracolormap_t *extra_colormap)
|
|
{
|
|
if (!extra_colormap)
|
|
return "NONE";
|
|
|
|
if (extra_colormap->lump == LUMPERROR)
|
|
return "INLEVEL";
|
|
|
|
return extra_colormap->lumpname;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// R_InitTextureData
|
|
//
|
|
// Locates all the lumps that will be used by all views
|
|
// Must be called after W_Init.
|
|
//
|
|
void R_InitTextureData(void)
|
|
{
|
|
CONS_Printf("R_LoadTextures()...\n");
|
|
R_LoadTextures();
|
|
|
|
CONS_Printf("P_InitPicAnims()...\n");
|
|
P_InitPicAnims();
|
|
|
|
CONS_Printf("K_InitBrightmaps()...\n");
|
|
K_InitBrightmaps();
|
|
}
|
|
|
|
//
|
|
// R_PrecacheLevel
|
|
//
|
|
// Preloads all relevant graphics for the level.
|
|
//
|
|
void R_PrecacheLevel(void)
|
|
{
|
|
char *texturepresent, *spritepresent;
|
|
size_t i, j, k;
|
|
lumpnum_t lump;
|
|
|
|
thinker_t *th;
|
|
spriteframe_t *sf;
|
|
|
|
if (demo.playback)
|
|
return;
|
|
|
|
// do not flush the memory, Z_Malloc twice with same user will cause error in Z_CheckHeap()
|
|
if (rendermode != render_soft)
|
|
return;
|
|
|
|
// Precache flats.
|
|
flatmemory = P_PrecacheLevelFlats();
|
|
|
|
//
|
|
// Precache textures.
|
|
//
|
|
// no need to precache all software textures in 3D mode
|
|
// (note they are still used with the reference software view)
|
|
texturepresent = calloc(numtextures, sizeof (*texturepresent));
|
|
if (texturepresent == NULL) I_Error("%s: Out of memory looking up textures", "R_PrecacheLevel");
|
|
|
|
for (j = 0; j < numsides; j++)
|
|
{
|
|
// huh, a potential bug here????
|
|
if (sides[j].toptexture >= 0 && sides[j].toptexture < numtextures)
|
|
texturepresent[sides[j].toptexture] = 1;
|
|
if (sides[j].midtexture >= 0 && sides[j].midtexture < numtextures)
|
|
texturepresent[sides[j].midtexture] = 1;
|
|
if (sides[j].bottomtexture >= 0 && sides[j].bottomtexture < numtextures)
|
|
texturepresent[sides[j].bottomtexture] = 1;
|
|
}
|
|
|
|
// Sky texture is always present.
|
|
// Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat,
|
|
// while the sky texture is stored like a wall texture, with a texture name set by the map.
|
|
texturepresent[skytexture] = 1;
|
|
|
|
texturememory = 0;
|
|
for (j = 0; j < (unsigned)numtextures; j++)
|
|
{
|
|
if (!texturepresent[j])
|
|
continue;
|
|
|
|
if (!texturecache[j])
|
|
R_GenerateTexture(j);
|
|
// pre-caching individual patches that compose textures became obsolete,
|
|
// since we cache entire composite textures
|
|
}
|
|
free(texturepresent);
|
|
|
|
//
|
|
// Precache sprites.
|
|
//
|
|
spritepresent = calloc(numsprites, sizeof (*spritepresent));
|
|
if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel");
|
|
|
|
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
|
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
|
|
spritepresent[((mobj_t *)th)->sprite] = 1;
|
|
|
|
spritememory = 0;
|
|
for (i = 0; i < numsprites; i++)
|
|
{
|
|
if (!spritepresent[i])
|
|
continue;
|
|
|
|
for (j = 0; j < sprites[i].numframes; j++)
|
|
{
|
|
sf = &sprites[i].spriteframes[j];
|
|
#define cacheang(a) {\
|
|
lump = sf->lumppat[a];\
|
|
if (devparm)\
|
|
spritememory += W_LumpLength(lump);\
|
|
W_CachePatchNum(lump, PU_SPRITE);\
|
|
}
|
|
// see R_InitSprites for more about lumppat,lumpid
|
|
switch (sf->rotate)
|
|
{
|
|
case SRF_SINGLE:
|
|
cacheang(0);
|
|
break;
|
|
case SRF_2D:
|
|
cacheang(2);
|
|
cacheang(6);
|
|
break;
|
|
default:
|
|
k = (sf->rotate & SRF_3DGE ? 16 : 8);
|
|
while (k--)
|
|
cacheang(k);
|
|
break;
|
|
}
|
|
#undef cacheang
|
|
}
|
|
}
|
|
free(spritepresent);
|
|
|
|
// FIXME: this is no longer correct with OpenGL render mode
|
|
CONS_Debug(DBG_SETUP, "Precache level done:\n"
|
|
"flatmemory: %s k\n"
|
|
"texturememory: %s k\n"
|
|
"spritememory: %s k\n", sizeu1(flatmemory>>10), sizeu2(texturememory>>10), sizeu3(spritememory>>10));
|
|
}
|