qzdoom/src/r_data.cpp
Christoph Oelckers b54b9bad7a - Fixed: A_VileAttack positioned the fire on the wrong side of the target.
- Reorganized the HackHack code so that the image creation was moved into
  MakeTexture. This was necessary because Unload deleted the pixel data
  and broke the whole thing.
- Fixed: FPatchTexture::HackHack and FDoomStatusbarTexture::DrawToBar used the
  obsolete and uninitialized variable Near255. 
- Removed the span creation code specific to FPatchTexture. It only has an
  advantage when the lump has already been loaded in memory but since that
  is no longer the case now the generic version in FTexture is actually better.
- Changed: FTexture::CopyToBlock no longer uses the spans but the pixel buffer
  directly. Since most patches in multipatch textures are non transparent
  the added overhead from creating the spans far outweighs any savings they
  might provide. It is also simpler to handle for mirrored or rotated patches now.
- Changed: Textures only create the spans when really needed. Flats and native
  textures, for example, do not and it only created needless overhead that they
  were always created along with the pixel buffer.
- Made use of player and actor variables consistent in a_hereticweaps.cpp.
- Fixed: A few calls to P_SpawnPlayerMissile passed 0 as angle



SVN r911 (trunk)
2008-04-14 12:10:45 +00:00

545 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 "m_alloc.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"
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 ()
{
FTexture::InitGrayMap();
StartScreen->Progress();
TexMan.Init();
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++)
{
int pic = frame->Texture[k];
if (pic != 0xFFFF)
{
hitlist[pic] = 1;
}
}
}
}
}
delete[] spritelist;
for (i = numsectors - 1; i >= 0; i--)
{
hitlist[sectors[i].floorpic] = hitlist[sectors[i].ceilingpic] |= 2;
}
for (i = numsides - 1; i >= 0; i--)
{
hitlist[sides[i].GetTexture(side_t::top)] =
hitlist[sides[i].GetTexture(side_t::mid)] =
hitlist[sides[i].GetTexture(side_t::bottom)] |= 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 >= 0)
{
hitlist[sky1texture] |= 1;
}
if (sky2texture >= 0)
{
hitlist[sky2texture] |= 1;
}
for (i = TexMan.NumTextures() - 1; i >= 0; i--)
{
screen->PrecacheTexture(TexMan[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;
int picnum = TexMan.CheckForTexture (argv[1], FTexture::TEX_Any);
if (picnum < 0)
{
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