mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-16 15:31:30 +00:00
3637c878cd
when explicitly giving them. - Changed 'give weapon' cheat so that in single player it only gives weapons belonging to the current game or are placed in a weapon slot to avoid giving the Chex Quest weapons in Doom and vice versa. - Fixed: The texture manager must be the first thing to be initialized because MAPINFO and DECORATE both can reference textures and letting them create their own textures is not safe. SVN r1230 (trunk)
547 lines
14 KiB
C++
547 lines
14 KiB
C++
/*
|
|
** r_data.cpp
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 1998-2008 Randy Heit
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
**
|
|
*/
|
|
|
|
#include "i_system.h"
|
|
#include "w_wad.h"
|
|
#include "doomdef.h"
|
|
#include "r_local.h"
|
|
#include "r_sky.h"
|
|
#include "c_dispatch.h"
|
|
#include "r_data.h"
|
|
#include "sc_man.h"
|
|
#include "v_text.h"
|
|
#include "st_start.h"
|
|
#include "doomstat.h"
|
|
#include "r_bsp.h"
|
|
#include "r_segs.h"
|
|
#include "v_palette.h"
|
|
|
|
|
|
static int R_CountGroup (const char *start, const char *end);
|
|
static int R_CountTexturesX ();
|
|
static int R_CountLumpTextures (int lumpnum);
|
|
|
|
extern void R_DeinitBuildTiles();
|
|
extern int R_CountBuildTiles();
|
|
|
|
static struct FakeCmap
|
|
{
|
|
char name[8];
|
|
PalEntry blend;
|
|
} *fakecmaps;
|
|
|
|
size_t numfakecmaps;
|
|
int firstfakecmap;
|
|
BYTE *realcolormaps;
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_SetDefaultColormap
|
|
//
|
|
//==========================================================================
|
|
|
|
void R_SetDefaultColormap (const char *name)
|
|
{
|
|
if (strnicmp (fakecmaps[0].name, name, 8) != 0)
|
|
{
|
|
int lump, i, j;
|
|
BYTE map[256];
|
|
BYTE unremap[256];
|
|
BYTE remap[256];
|
|
|
|
// [RH] If using BUILD's palette, generate the colormap
|
|
if (Wads.CheckNumForFullName("palette.dat") >= 0 || Wads.CheckNumForFullName("blood.pal") >= 0)
|
|
{
|
|
Printf ("Make colormap\n");
|
|
FDynamicColormap foo;
|
|
|
|
foo.Color = 0xFFFFFF;
|
|
foo.Fade = 0;
|
|
foo.Maps = realcolormaps;
|
|
foo.Desaturate = 0;
|
|
foo.Next = NULL;
|
|
foo.BuildLights ();
|
|
}
|
|
else
|
|
{
|
|
lump = Wads.CheckNumForName (name, ns_colormaps);
|
|
if (lump == -1)
|
|
lump = Wads.CheckNumForName (name, ns_global);
|
|
FWadLump lumpr = Wads.OpenLumpNum (lump);
|
|
|
|
// [RH] The colormap may not have been designed for the specific
|
|
// palette we are using, so remap it to match the current palette.
|
|
memcpy (remap, GPalette.Remap, 256);
|
|
memset (unremap, 0, 256);
|
|
for (i = 0; i < 256; ++i)
|
|
{
|
|
unremap[remap[i]] = i;
|
|
}
|
|
// Mapping to color 0 is okay, because the colormap won't be used to
|
|
// produce a masked texture.
|
|
remap[0] = 0;
|
|
for (i = 0; i < NUMCOLORMAPS; ++i)
|
|
{
|
|
BYTE *map2 = &realcolormaps[i*256];
|
|
lumpr.Read (map, 256);
|
|
for (j = 0; j < 256; ++j)
|
|
{
|
|
map2[j] = remap[map[unremap[j]]];
|
|
}
|
|
}
|
|
}
|
|
|
|
uppercopy (fakecmaps[0].name, name);
|
|
fakecmaps[0].blend = 0;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_InitColormaps
|
|
//
|
|
//==========================================================================
|
|
|
|
void R_InitColormaps ()
|
|
{
|
|
// [RH] Try and convert BOOM colormaps into blending values.
|
|
// This is a really rough hack, but it's better than
|
|
// not doing anything with them at all (right?)
|
|
int lastfakecmap = Wads.CheckNumForName ("C_END");
|
|
firstfakecmap = Wads.CheckNumForName ("C_START");
|
|
|
|
if (firstfakecmap == -1 || lastfakecmap == -1)
|
|
numfakecmaps = 1;
|
|
else
|
|
numfakecmaps = lastfakecmap - firstfakecmap;
|
|
realcolormaps = new BYTE[256*NUMCOLORMAPS*numfakecmaps];
|
|
fakecmaps = new FakeCmap[numfakecmaps];
|
|
|
|
fakecmaps[0].name[0] = 0;
|
|
R_SetDefaultColormap ("COLORMAP");
|
|
|
|
if (numfakecmaps > 1)
|
|
{
|
|
BYTE unremap[256], remap[256], mapin[256];
|
|
int i;
|
|
size_t j;
|
|
|
|
memcpy (remap, GPalette.Remap, 256);
|
|
memset (unremap, 0, 256);
|
|
for (i = 0; i < 256; ++i)
|
|
{
|
|
unremap[remap[i]] = i;
|
|
}
|
|
remap[0] = 0;
|
|
for (i = ++firstfakecmap, j = 1; j < numfakecmaps; i++, j++)
|
|
{
|
|
if (Wads.LumpLength (i) >= (NUMCOLORMAPS+1)*256)
|
|
{
|
|
int k, r, g, b;
|
|
FWadLump lump = Wads.OpenLumpNum (i);
|
|
BYTE *const map = realcolormaps + NUMCOLORMAPS*256*j;
|
|
|
|
for (k = 0; k < NUMCOLORMAPS; ++k)
|
|
{
|
|
BYTE *map2 = &map[k*256];
|
|
lump.Read (mapin, 256);
|
|
map2[0] = 0;
|
|
for (r = 1; r < 256; ++r)
|
|
{
|
|
map2[r] = remap[mapin[unremap[r]]];
|
|
}
|
|
}
|
|
|
|
r = g = b = 0;
|
|
|
|
for (k = 0; k < 256; k++)
|
|
{
|
|
r += GPalette.BaseColors[map[k]].r;
|
|
g += GPalette.BaseColors[map[k]].g;
|
|
b += GPalette.BaseColors[map[k]].b;
|
|
}
|
|
Wads.GetLumpName (fakecmaps[j].name, i);
|
|
fakecmaps[j].blend = PalEntry (255, r/256, g/256, b/256);
|
|
}
|
|
}
|
|
}
|
|
NormalLight.Maps = realcolormaps;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_DeinitColormaps
|
|
//
|
|
//==========================================================================
|
|
|
|
void R_DeinitColormaps ()
|
|
{
|
|
if (fakecmaps != NULL)
|
|
{
|
|
delete[] fakecmaps;
|
|
fakecmaps = NULL;
|
|
}
|
|
if (realcolormaps != NULL)
|
|
{
|
|
delete[] realcolormaps;
|
|
realcolormaps = NULL;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// [RH] Returns an index into realcolormaps. Multiply it by
|
|
// 256*NUMCOLORMAPS to find the start of the colormap to use.
|
|
// WATERMAP is an exception and returns a blending value instead.
|
|
//
|
|
//==========================================================================
|
|
|
|
DWORD R_ColormapNumForName (const char *name)
|
|
{
|
|
int lump;
|
|
DWORD blend = 0;
|
|
|
|
if (strnicmp (name, "COLORMAP", 8))
|
|
{ // COLORMAP always returns 0
|
|
if (-1 != (lump = Wads.CheckNumForName (name, ns_colormaps)) )
|
|
blend = lump - firstfakecmap + 1;
|
|
else if (!strnicmp (name, "WATERMAP", 8))
|
|
blend = MAKEARGB (128,0,0x4f,0xa5);
|
|
}
|
|
|
|
return blend;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_BlendForColormap
|
|
//
|
|
//==========================================================================
|
|
|
|
DWORD R_BlendForColormap (DWORD map)
|
|
{
|
|
return APART(map) ? map :
|
|
map < numfakecmaps ? DWORD(fakecmaps[map].blend) : 0;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_InitData
|
|
// Locates all the lumps that will be used by all views
|
|
// Must be called after W_Init.
|
|
//
|
|
//==========================================================================
|
|
|
|
void R_InitData ()
|
|
{
|
|
StartScreen->Progress();
|
|
|
|
V_InitFonts();
|
|
StartScreen->Progress();
|
|
R_InitColormaps ();
|
|
StartScreen->Progress();
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// R_GuesstimateNumTextures
|
|
//
|
|
// Returns an estimate of the number of textures R_InitData will have to
|
|
// process. Used by D_DoomMain() when it calls ST_Init().
|
|
//
|
|
//===========================================================================
|
|
|
|
int R_GuesstimateNumTextures ()
|
|
{
|
|
int numtex;
|
|
|
|
numtex = R_CountGroup ("S_START", "S_END");
|
|
numtex += R_CountGroup ("F_START", "F_END");
|
|
numtex += R_CountGroup ("TX_START", "TX_END");
|
|
numtex += R_CountGroup ("HI_START", "HI_END");
|
|
numtex += R_CountBuildTiles ();
|
|
numtex += R_CountTexturesX ();
|
|
return numtex;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// R_CountGroup
|
|
//
|
|
//===========================================================================
|
|
|
|
static int R_CountGroup (const char *start, const char *end)
|
|
{
|
|
int startl = Wads.CheckNumForName (start);
|
|
int endl = Wads.CheckNumForName (end);
|
|
|
|
if (startl < 0 || endl < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return endl - startl - 1;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// R_CountTexturesX
|
|
//
|
|
// See R_InitTextures() for the logic in deciding what lumps to check.
|
|
//
|
|
//===========================================================================
|
|
|
|
static int R_CountTexturesX ()
|
|
{
|
|
int count = 0;
|
|
int wadcount = Wads.GetNumWads();
|
|
for (int wadnum = 0; wadnum < wadcount; wadnum++)
|
|
{
|
|
// Use the most recent PNAMES for this WAD.
|
|
// Multiple PNAMES in a WAD will be ignored.
|
|
int pnames = Wads.CheckNumForName("PNAMES", ns_global, wadnum, false);
|
|
|
|
// should never happen except for zdoom.pk3
|
|
if (pnames < 0) continue;
|
|
|
|
// Only count the patches if the PNAMES come from the current file
|
|
// Otherwise they have already been counted.
|
|
if (Wads.GetLumpFile(pnames) == wadnum)
|
|
{
|
|
count += R_CountLumpTextures (pnames);
|
|
}
|
|
|
|
int texlump1 = Wads.CheckNumForName ("TEXTURE1", ns_global, wadnum);
|
|
int texlump2 = Wads.CheckNumForName ("TEXTURE2", ns_global, wadnum);
|
|
|
|
count += R_CountLumpTextures (texlump1) - 1;
|
|
count += R_CountLumpTextures (texlump2) - 1;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// R_CountLumpTextures
|
|
//
|
|
// Returns the number of patches in a PNAMES/TEXTURE1/TEXTURE2 lump.
|
|
//
|
|
//===========================================================================
|
|
|
|
static int R_CountLumpTextures (int lumpnum)
|
|
{
|
|
if (lumpnum >= 0)
|
|
{
|
|
FWadLump file = Wads.OpenLumpNum (lumpnum);
|
|
DWORD numtex;
|
|
|
|
file >> numtex;
|
|
return numtex >= 0 ? numtex : 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// R_DeinitData
|
|
//
|
|
//===========================================================================
|
|
|
|
void R_DeinitData ()
|
|
{
|
|
R_DeinitColormaps ();
|
|
R_DeinitBuildTiles();
|
|
FCanvasTextureInfo::EmptyList();
|
|
|
|
// Free openings
|
|
if (openings != NULL)
|
|
{
|
|
M_Free (openings);
|
|
openings = NULL;
|
|
}
|
|
|
|
// Free drawsegs
|
|
if (drawsegs != NULL)
|
|
{
|
|
M_Free (drawsegs);
|
|
drawsegs = NULL;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// R_PrecacheLevel
|
|
//
|
|
// Preloads all relevant graphics for the level.
|
|
//
|
|
//===========================================================================
|
|
|
|
void R_PrecacheLevel (void)
|
|
{
|
|
BYTE *hitlist;
|
|
BYTE *spritelist;
|
|
int i;
|
|
|
|
if (demoplayback)
|
|
return;
|
|
|
|
hitlist = new BYTE[TexMan.NumTextures()];
|
|
spritelist = new BYTE[sprites.Size()];
|
|
|
|
// Precache textures (and sprites).
|
|
memset (hitlist, 0, TexMan.NumTextures());
|
|
memset (spritelist, 0, sprites.Size());
|
|
|
|
{
|
|
AActor *actor;
|
|
TThinkerIterator<AActor> iterator;
|
|
|
|
while ( (actor = iterator.Next ()) )
|
|
spritelist[actor->sprite] = 1;
|
|
}
|
|
|
|
for (i = (int)(sprites.Size () - 1); i >= 0; i--)
|
|
{
|
|
if (spritelist[i])
|
|
{
|
|
int j, k;
|
|
for (j = 0; j < sprites[i].numframes; j++)
|
|
{
|
|
const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j];
|
|
|
|
for (k = 0; k < 16; k++)
|
|
{
|
|
FTextureID pic = frame->Texture[k];
|
|
if (pic.isValid())
|
|
{
|
|
hitlist[pic.GetIndex()] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] spritelist;
|
|
|
|
for (i = numsectors - 1; i >= 0; i--)
|
|
{
|
|
hitlist[sectors[i].GetTexture(sector_t::floor).GetIndex()] =
|
|
hitlist[sectors[i].GetTexture(sector_t::ceiling).GetIndex()] |= 2;
|
|
}
|
|
|
|
for (i = numsides - 1; i >= 0; i--)
|
|
{
|
|
hitlist[sides[i].GetTexture(side_t::top).GetIndex()] =
|
|
hitlist[sides[i].GetTexture(side_t::mid).GetIndex()] =
|
|
hitlist[sides[i].GetTexture(side_t::bottom).GetIndex()] |= 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 an episode dependant
|
|
// name.
|
|
|
|
if (sky1texture.isValid())
|
|
{
|
|
hitlist[sky1texture.GetIndex()] |= 1;
|
|
}
|
|
if (sky2texture.isValid())
|
|
{
|
|
hitlist[sky2texture.GetIndex()] |= 1;
|
|
}
|
|
|
|
for (i = TexMan.NumTextures() - 1; i >= 0; i--)
|
|
{
|
|
screen->PrecacheTexture(TexMan.ByIndex(i), hitlist[i]);
|
|
}
|
|
|
|
delete[] hitlist;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_GetColumn
|
|
//
|
|
//==========================================================================
|
|
|
|
const BYTE *R_GetColumn (FTexture *tex, int col)
|
|
{
|
|
return tex->GetColumn (col, NULL);
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Debug stuff
|
|
//
|
|
//==========================================================================
|
|
|
|
#ifdef _DEBUG
|
|
// Prints the spans generated for a texture. Only needed for debugging.
|
|
CCMD (printspans)
|
|
{
|
|
if (argv.argc() != 2)
|
|
return;
|
|
|
|
FTextureID picnum = TexMan.CheckForTexture (argv[1], FTexture::TEX_Any);
|
|
if (!picnum.Exists())
|
|
{
|
|
Printf ("Unknown texture %s\n", argv[1]);
|
|
return;
|
|
}
|
|
FTexture *tex = TexMan[picnum];
|
|
for (int x = 0; x < tex->GetWidth(); ++x)
|
|
{
|
|
const FTexture::Span *spans;
|
|
Printf ("%4d:", x);
|
|
tex->GetColumn (x, &spans);
|
|
while (spans->Length != 0)
|
|
{
|
|
Printf (" (%4d,%4d)", spans->TopOffset, spans->TopOffset+spans->Length-1);
|
|
spans++;
|
|
}
|
|
Printf ("\n");
|
|
}
|
|
}
|
|
|
|
CCMD (picnum)
|
|
{
|
|
//int picnum = TexMan.GetTexture (argv[1], FTexture::TEX_Any);
|
|
//Printf ("%d: %s - %s\n", picnum, TexMan[picnum]->Name, TexMan(picnum)->Name);
|
|
}
|
|
#endif
|