- Changed: Patch and IMGZ textures now initialize their dimensions upon creation.

The lump is open anyway at that time so deferring this action until the information
  is needed doesn't give any speed improvements. Now GetDimensions and all its
  associated overhead is gone.
- Added support for TGA textures. It can handle all of the common variations
  of this format.
- Changed: GI_PAGESARERAW is no longer checked. It wasn't really necessary before
  because the chance of texture misidentification is absolutely minimal.
  But raw pages are now restricted to textures of type TEX_MiscPatch only.
- Changed the automap parchment to use a regular texture. The previous 
  FAutomapTexture is only used as a last resort fallback now. If the code
  finds a recognizable graphic it will create a proper texture for it now.
- Fixed: Flats were only auto-scaled when in Doom flat format.
- Fixed: FMultiPatchTexture::CheckForHacks blindly assumed that all patches
  were FPstchTextures. Since the texture code does not have any type information
  I added a new flag bIsPatch for this purpose.
- Moved all texture classes into their own source files and created a new
  subdirectory 'textures' for that.
- Cleaned up the texture management code and added some stricter checks for
  the validity of Doom patches. The old code liked to crash when being passed
  some non-graphic data.

SVN r300 (trunk)
This commit is contained in:
Christoph Oelckers 2006-08-20 12:55:46 +00:00
parent ab947ce16b
commit 2536eca01d
23 changed files with 4099 additions and 2983 deletions

View file

@ -19,7 +19,7 @@ CFLAGS += -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DNEED_STRUPR
LDFLAGS += -lFLAC++ -lFLAC -lz -ljpeg -lfmod `sdl-config --libs`
NASMFLAGS += -f elf -DM_TARGET_LINUX
SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ sdl/)
SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ sdl/ textures/ )
VPATH = $(SRCDIRS)
INCLUDES = $(addprefix -I,$(SRCDIRS))
CFLAGS += $(INCLUDES)

View file

@ -52,7 +52,7 @@ ifeq ($(CONFIG),Release)
TARGET = $(RELEASETARGET)
endif
SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ win32/)
SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ win32/ textures/)
VPATH = $(SRCDIRS)
CPPSRCS = $(wildcard $(addsuffix *.cpp,$(SRCDIRS)))

View file

@ -1,3 +1,27 @@
August 20, 2006 (Changes by Graf Zahl)
- Changed: Patch and IMGZ textures now initialize their dimensions upon creation.
The lump is open anyway at that time so deferring this action until the information
is needed doesn't give any speed improvements. Now GetDimensions and all its
associated overhead is gone.
- Added support for TGA textures. It can handle all of the common variations
of this format.
- Changed: GI_PAGESARERAW is no longer checked. It wasn't really necessary before
because the chance of texture misidentification is absolutely minimal.
But raw pages are now restricted to textures of type TEX_MiscPatch only.
- Changed the automap parchment to use a regular texture. The previous
FAutomapTexture is only used as a last resort fallback now. If the code
finds a recognizable graphic it will create a proper texture for it now.
- Fixed: Flats were only auto-scaled when in Doom flat format.
- Fixed: FMultiPatchTexture::CheckForHacks blindly assumed that all patches
were FPstchTextures. Since the texture code does not have any type information
I added a new flag bIsPatch for this purpose.
- Moved all texture classes into their own source files and created a new
subdirectory 'textures' for that.
- Cleaned up the texture management code and added some stricter checks for
the validity of Doom patches. The old code liked to crash when being passed
some non-graphic data.
August 19, 2006 (Changes by Graf Zahl)
- Added custom fail messages to the puzzle items.

View file

@ -320,24 +320,7 @@ static int markpointnum = 0; // next point to be assigned
static int followplayer = 1; // specifies whether to follow the player around
class FAutomapTexture : public FTexture
{
public:
FAutomapTexture (int lumpnum);
~FAutomapTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
void Unload ();
void MakeTexture ();
private:
BYTE *Pixels;
Span DummySpan[2];
int LumpNum;
};
static FAutomapTexture *mapback; // the automap background
static FTexture *mapback; // the automap background
static fixed_t mapystart=0; // y-value for the start of the map bitmap...used in the parallax stuff.
static fixed_t mapxstart=0; //x-value for the bitmap.
@ -784,7 +767,7 @@ void AM_loadPics ()
i = Wads.CheckNumForName ("AUTOPAGE");
if (i >= 0)
{
mapback = new FAutomapTexture (i);
mapback = FTexture::CreateTexture(i, FTexture::TEX_Autopage);
}
}
}
@ -2201,73 +2184,3 @@ void AM_Drawer ()
AM_drawMarks();
}
FAutomapTexture::FAutomapTexture (int lumpnum)
: Pixels(NULL), LumpNum(lumpnum)
{
UseType = TEX_MiscPatch;
Width = 320;
Height = Wads.LumpLength(lumpnum) / 320;
CalcBitSize ();
DummySpan[0].TopOffset = 0;
DummySpan[0].Length = Height;
DummySpan[1].TopOffset = 0;
DummySpan[1].Length = 0;
}
FAutomapTexture::~FAutomapTexture ()
{
Unload ();
}
void FAutomapTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
void FAutomapTexture::MakeTexture ()
{
int x, y;
FMemLump data = Wads.ReadLump (LumpNum);
const BYTE *indata = (const BYTE *)data.GetMem();
Pixels = new BYTE[Width * Height];
for (x = 0; x < Width; ++x)
{
for (y = 0; y < Height; ++y)
{
Pixels[x*Height+y] = indata[x+320*y];
}
}
}
const BYTE *FAutomapTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
const BYTE *FAutomapTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
column %= Width;
}
if (spans_out != NULL)
{
*spans_out = DummySpan;
}
return Pixels + column*Height;
}

View file

@ -148,7 +148,7 @@ void AHereticPlayer::GiveDefaultInventory ()
wand = player->mo->GiveInventoryType (PClass::FindClass ("GoldWand"));
// Adding the gold wand automatically adds its ammo
ammo = player->mo->FindInventory (PClass::FindClass ("GoldWandAmmo"));
ammo->Amount = 50;
if (ammo != NULL) ammo->Amount = 50;
player->ReadyWeapon = player->PendingWeapon = static_cast<AWeapon *> (wand);
}
}

File diff suppressed because it is too large Load diff

View file

@ -46,7 +46,6 @@ public:
class FPatchTexture : public FTexture
{
public:
FPatchTexture (int lumpnum, int usetype);
~FPatchTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -58,10 +57,14 @@ protected:
BYTE *Pixels;
Span **Spans;
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FPatchTexture (int lumpnum, patch_t *header);
virtual void MakeTexture ();
void HackHack (int newheight);
void GetDimensions ();
friend class FTexture;
friend class FMultiPatchTexture;
};
@ -108,7 +111,6 @@ private:
class FFlatTexture : public FTexture
{
public:
FFlatTexture (int lumpnum);
~FFlatTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -120,7 +122,13 @@ protected:
BYTE *Pixels;
Span DummySpans[2];
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FFlatTexture (int lumpnum);
void MakeTexture ();
friend class FTexture;
};
// A texture defined in a Build TILESxxx.ART file
@ -144,7 +152,6 @@ protected:
class FRawPageTexture : public FTexture
{
public:
FRawPageTexture (int lumpnum);
~FRawPageTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -152,19 +159,50 @@ public:
void Unload ();
protected:
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FRawPageTexture (int lumpnum);
int SourceLump;
BYTE *Pixels;
static const Span DummySpans[2];
void MakeTexture ();
friend class FTexture;
};
// A raw 320x? graphic used by Heretic and Hexen for the automap parchment
class FAutomapTexture : public FTexture
{
public:
~FAutomapTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
void Unload ();
void MakeTexture ();
private:
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FAutomapTexture (int lumpnum);
BYTE *Pixels;
Span DummySpan[2];
int LumpNum;
friend class FTexture;
};
// An IMGZ image (mostly just crosshairs)
class FIMGZTexture : public FTexture
{
public:
FIMGZTexture (int lumpnum);
~FIMGZTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -172,14 +210,19 @@ public:
void Unload ();
protected:
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FIMGZTexture (int lumpnum, WORD w, WORD h, SWORD l, SWORD t);
int SourceLump;
BYTE *Pixels;
Span **Spans;
void GetDimensions ();
void MakeTexture ();
struct ImageHeader;
friend class FTexture;
};
@ -187,7 +230,6 @@ protected:
class FPNGTexture : public FTexture
{
public:
FPNGTexture (int lumpnum, int width, int height, BYTE bitdepth, BYTE colortype, BYTE interlace);
~FPNGTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -195,6 +237,12 @@ public:
void Unload ();
protected:
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FPNGTexture (FileReader &lump, int lumpnum, int width, int height, BYTE bitdepth, BYTE colortype, BYTE interlace);
int SourceLump;
BYTE *Pixels;
Span **Spans;
@ -208,6 +256,8 @@ protected:
DWORD StartOfIDAT;
void MakeTexture ();
friend class FTexture;
};
@ -216,19 +266,50 @@ protected:
class FJPEGTexture : public FTexture
{
public:
FJPEGTexture (int lumpnum, int width, int height);
~FJPEGTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
void Unload ();
protected:
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FJPEGTexture (int lumpnum, int width, int height);
int SourceLump;
BYTE *Pixels;
Span DummySpans[2];
void MakeTexture ();
friend class FTexture;
};
// A texture that is just a single patch
class FTGATexture : public FTexture
{
public:
~FTGATexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
void Unload ();
protected:
int SourceLump;
BYTE *Pixels;
Span DummySpans[2];
Span **Spans;
void MakeTexture ();
static bool Check(FileReader & file);
static FTexture *Create(FileReader & file, int lumpnum);
FTGATexture (int lumpnum, int width, int height);
void ReadCompressed(FileReader &lump, BYTE * buffer, int bytesperpixel);
virtual void MakeTexture ();
friend class FTexture;
};
// A texture that returns a wiggly version of another texture.

View file

@ -586,11 +586,13 @@ struct patch_t
// the [0] is &columnofs[width]
};
class FileReader;
// Base texture class
class FTexture
{
public:
FTexture ();
static FTexture *CreateTexture(int lumpnum, int usetype);
virtual ~FTexture ();
SWORD LeftOffset, TopOffset;
@ -608,6 +610,7 @@ public:
BYTE bAlphaTexture:1; // Texture is an alpha channel without color information
BYTE bHasCanvas:1; // Texture is based off FCanvasTexture
BYTE bWarped:2; // This is a warped texture. Used to avoid multiple warps on one texture
BYTE bIsPatch:1; // 1 if an FPatchTexture. Required to fix FMultipatchTexture::CheckForHacks
WORD Rotations;
@ -624,6 +627,7 @@ public:
TEX_MiscPatch,
TEX_FontChar,
TEX_Override, // For patches between TX_START/TX_END
TEX_Autopage, // Automap background - used to enable the use of FAutomapTexture
TEX_Null,
};
@ -641,8 +645,8 @@ public:
virtual void Unload () = 0;
int GetWidth () { if (Width == 0xFFFF) { GetDimensions(); } return Width; }
int GetHeight () { if (Width == 0xFFFF) { GetDimensions(); } return Height; }
int GetWidth () { return Width; }
int GetHeight () { return Height; }
virtual void SetFrontSkyLayer();
@ -652,11 +656,13 @@ public:
// last call to GetPixels(). This should be considered valid only if a call to CheckModified()
// is immediately followed by a call to GetPixels().
virtual bool CheckModified ();
static void InitGrayMap();
protected:
WORD Width, Height, WidthMask;
static BYTE GrayMap[256];
virtual void GetDimensions ();
FTexture ();
Span **CreateSpans (const BYTE *pixels) const;
void FreeSpans (Span **spans) const;
@ -725,13 +731,10 @@ public:
void AddTexturesLump (const void *lumpdata, int lumpsize, int patcheslump, int firstdup=0, bool texture1=false);
void AddTexturesLumps (int lump1, int lump2, int patcheslump);
void AddFlats ();
void AddSprites ();
void AddGroup(const char * startlump, const char * endlump, int ns, int usetype);
void AddPatches (int lumpnum);
void AddTiles (void *tileFile);
void AddExtraTextures (); // Adds patches in the ns_newtextures namespace
static FTexture *DoCreateTexture (int lumpnum, int usetype=FTexture::TEX_Any);
int CreateTexture (int lumpnum, int usetype=FTexture::TEX_Any); // Also calls AddTexture
int AddTexture (FTexture *texture);
int AddPatch (const char *patchname, int namespc=0);
@ -749,6 +752,7 @@ public:
int NumTextures () const { return (int)Textures.Size(); }
private:
struct TextureHash
{
@ -760,6 +764,8 @@ private:
TArray<WORD> Translation;
WORD HashFirst[HASH_SIZE];
int DefaultTexture;
friend void R_InitData ();
};
extern FTextureManager TexMan;

View file

@ -0,0 +1,122 @@
/*
** automaptexture.cpp
** Texture class for Raven's automap parchment
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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.
**---------------------------------------------------------------------------
**
** This texture type is only used as a last resort when everything else has failed for creating
** the AUTOPAGE texture. That's because Raven used a raw lump of non-standard proportions to define it.
**
*/
#include "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "w_wad.h"
bool FAutomapTexture::Check(FileReader & data)
{
if (data.GetLength() < 320) return false;
return true;
}
FTexture *FAutomapTexture::Create(FileReader & file, int lumpnum)
{
return new FAutomapTexture(lumpnum);
}
FAutomapTexture::FAutomapTexture (int lumpnum)
: Pixels(NULL), LumpNum(lumpnum)
{
Width = 320;
Height = Wads.LumpLength(lumpnum) / 320;
CalcBitSize ();
DummySpan[0].TopOffset = 0;
DummySpan[0].Length = Height;
DummySpan[1].TopOffset = 0;
DummySpan[1].Length = 0;
}
FAutomapTexture::~FAutomapTexture ()
{
Unload ();
}
void FAutomapTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
void FAutomapTexture::MakeTexture ()
{
int x, y;
FMemLump data = Wads.ReadLump (LumpNum);
const BYTE *indata = (const BYTE *)data.GetMem();
Pixels = new BYTE[Width * Height];
for (x = 0; x < Width; ++x)
{
for (y = 0; y < Height; ++y)
{
Pixels[x*Height+y] = indata[x+320*y];
}
}
}
const BYTE *FAutomapTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
const BYTE *FAutomapTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
column %= Width;
}
if (spans_out != NULL)
{
*spans_out = DummySpan;
}
return Pixels + column*Height;
}

View file

@ -0,0 +1,288 @@
/*
** buildtexture.cpp
** Handling Build textures
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_local.h"
#include "w_wad.h"
#include "templates.h"
#include "cmdlib.h"
static TArray<BYTE *> BuildTileFiles;
FBuildTexture::FBuildTexture (int tilenum, const BYTE *pixels, int width, int height, int left, int top)
: Pixels (pixels), Spans (NULL)
{
Width = width;
Height = height;
LeftOffset = left;
TopOffset = top;
CalcBitSize ();
sprintf (Name, "BTIL%04d", tilenum);
UseType = TEX_Build;
}
FBuildTexture::~FBuildTexture ()
{
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
}
void FBuildTexture::Unload ()
{
// Nothing to do, since the pixels are accessed from memory-mapped files directly
}
const BYTE *FBuildTexture::GetPixels ()
{
return Pixels;
}
const BYTE *FBuildTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (column >= Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
static void AddTiles (void *tiles)
{
// int numtiles = LittleLong(((DWORD *)tiles)[1]); // This value is not reliable
int tilestart = LittleLong(((DWORD *)tiles)[2]);
int tileend = LittleLong(((DWORD *)tiles)[3]);
const WORD *tilesizx = &((const WORD *)tiles)[8];
const WORD *tilesizy = &tilesizx[tileend - tilestart + 1];
const DWORD *picanm = (const DWORD *)&tilesizy[tileend - tilestart + 1];
BYTE *tiledata = (BYTE *)&picanm[tileend - tilestart + 1];
for (int i = tilestart; i <= tileend; ++i)
{
int pic = i - tilestart;
int width = LittleShort(tilesizx[pic]);
int height = LittleShort(tilesizy[pic]);
DWORD anm = LittleLong(picanm[pic]);
int xoffs = (SBYTE)((anm >> 8) & 255) + width/2;
int yoffs = (SBYTE)((anm >> 16) & 255) + height/2;
int size = width*height;
int texnum;
FTexture *tex;
if (width <= 0 || height <= 0) continue;
tex = new FBuildTexture (i, tiledata, width, height, xoffs, yoffs);
texnum = TexMan.AddTexture (tex);
while (size > 0)
{
*tiledata = 255 - *tiledata;
tiledata++;
size--;
}
if ((picanm[pic] & 63) && (picanm[pic] & 192))
{
int type, speed;
switch (picanm[pic] & 192)
{
case 64: type = 2; break;
case 128: type = 0; break;
case 192: type = 1; break;
default: type = 0; break; // Won't happen, but GCC bugs me if I don't put this here.
}
speed = (anm >> 24) & 15;
speed = MAX (1, (1 << speed) * 1000 / 120); // Convert from 120 Hz to 1000 Hz.
R_AddSimpleAnim (texnum, picanm[pic] & 63, type, speed);
}
// Blood's rotation types:
// 0 - Single
// 1 - 5 Full
// 2 - 8 Full
// 3 - Bounce (looks no different from Single; seems to signal bouncy sprites)
// 4 - 5 Half (not used in game)
// 5 - 3 Flat (not used in game)
// 6 - Voxel
// 7 - Spin Voxel
int rotType = (anm >> 28) & 7;
if (rotType == 1)
{
spriteframe_t rot;
rot.Texture[0] = texnum;
rot.Texture[1] = texnum;
for (int j = 1; j < 4; ++j)
{
rot.Texture[j*2] = texnum + j;
rot.Texture[j*2+1] = texnum + j;
rot.Texture[16-j*2] = texnum + j;
rot.Texture[17-j*2] = texnum + j;
}
rot.Texture[8] = texnum + 4;
rot.Texture[9] = texnum + 4;
rot.Flip = 0x00FC;
tex->Rotations = SpriteFrames.Push (rot);
}
else if (rotType == 2)
{
spriteframe_t rot;
rot.Texture[0] = texnum;
rot.Texture[1] = texnum;
for (int j = 1; j < 8; ++j)
{
rot.Texture[16-j*2] = texnum + j;
rot.Texture[17-j*2] = texnum + j;
}
rot.Flip = 0;
tex->Rotations = SpriteFrames.Push (rot);
}
}
}
//
// R_InitBuildTiles
//
// [RH] Support Build tiles!
//
void R_InitBuildTiles ()
{
int numartfiles = 0;
char artfile[] = "tilesXXX.art";
int lumpnum;
lumpnum = Wads.CheckNumForFullName ("blood.pal");
if (lumpnum >= 0)
{
// Blood's tiles are external resources. (Why did they do it like that?)
FString rffpath = Wads.GetWadFullName (Wads.GetLumpFile (lumpnum));
int slashat = rffpath.LastIndexOf ('/');
if (slashat >= 0)
{
rffpath.Truncate (slashat + 1);
}
else
{
rffpath += '/';
}
for (; numartfiles < 1000; numartfiles++)
{
artfile[5] = numartfiles / 100 + '0';
artfile[6] = numartfiles / 10 % 10 + '0';
artfile[7] = numartfiles % 10 + '0';
FString artpath = rffpath;
artpath += artfile;
FILE *f = fopen (artpath, "rb");
if (f == NULL)
{
break;
}
size_t len = Q_filelength (f);
BYTE *art = new BYTE[len];
if (fread (art, 1, len, f) != len || LittleLong(*(DWORD *)art) != 1)
{
delete[] art;
}
else
{
BuildTileFiles.Push (art);
AddTiles (art);
}
fclose (f);
}
}
for (; numartfiles < 1000; numartfiles++)
{
artfile[5] = numartfiles / 100 + '0';
artfile[6] = numartfiles / 10 % 10 + '0';
artfile[7] = numartfiles % 10 + '0';
lumpnum = Wads.CheckNumForFullName (artfile);
if (lumpnum < 0)
{
break;
}
BYTE *art = new BYTE[Wads.LumpLength (lumpnum)];
Wads.ReadLump (lumpnum, art);
if (LittleLong(*(DWORD *)art) != 1)
{
delete[] art;
}
else
{
BuildTileFiles.Push (art);
AddTiles (art);
}
}
}
void R_DeinitBuildTiles ()
{
for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i)
{
delete[] BuildTileFiles[i];
}
BuildTileFiles.Clear();
}

View file

@ -0,0 +1,167 @@
/*
** canvastexture.cpp
** Texture class for camera textures
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_local.h"
extern float LastFOV;
FCanvasTexture::FCanvasTexture (const char *name, int width, int height)
{
strncpy (Name, name, 8);
Name[8] = 0;
Width = width;
Height = height;
LeftOffset = TopOffset = 0;
CalcBitSize ();
bMasked = false;
DummySpans[0].TopOffset = 0;
DummySpans[0].Length = height;
DummySpans[1].TopOffset = 0;
DummySpans[1].Length = 0;
UseType = TEX_Wall;
Canvas = NULL;
bNeedsUpdate = true;
bDidUpdate = false;
bHasCanvas = true;
bFirstUpdate = true;
}
FCanvasTexture::~FCanvasTexture ()
{
Unload ();
}
const BYTE *FCanvasTexture::GetColumn (unsigned int column, const Span **spans_out)
{
bNeedsUpdate = true;
if (Canvas == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = DummySpans;
}
return Pixels + column*Height;
}
const BYTE *FCanvasTexture::GetPixels ()
{
bNeedsUpdate = true;
if (Canvas == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FCanvasTexture::MakeTexture ()
{
Canvas = new DSimpleCanvas (Width, Height);
Canvas->Lock ();
if (Width != Height || Width != Canvas->GetPitch())
{
Pixels = new BYTE[Width*Height];
}
else
{
Pixels = Canvas->GetBuffer();
}
// Draw a special "unrendered" initial texture into the buffer.
memset (Pixels, 0, Width*Height/2);
memset (Pixels+Width*Height/2, 255, Width*Height/2);
}
void FCanvasTexture::Unload ()
{
if (Canvas != NULL)
{
if (Pixels != NULL && Pixels != Canvas->GetBuffer())
{
delete[] Pixels;
}
Pixels = NULL;
delete Canvas;
Canvas = NULL;
}
}
bool FCanvasTexture::CheckModified ()
{
if (bDidUpdate)
{
bDidUpdate = false;
return true;
}
return false;
}
void FCanvasTexture::RenderView (AActor *viewpoint, int fov)
{
if (Canvas == NULL)
{
MakeTexture ();
}
float savedfov = LastFOV;
R_SetFOV ((float)fov);
R_RenderViewToCanvas (viewpoint, Canvas, 0, 0, Width, Height, bFirstUpdate);
R_SetFOV (savedfov);
if (Pixels == Canvas->GetBuffer())
{
FlipSquareBlock (Pixels, Width, Height);
}
else
{
FlipNonSquareBlock (Pixels, Canvas->GetBuffer(), Width, Height, Canvas->GetPitch());
}
bNeedsUpdate = false;
bDidUpdate = true;
bFirstUpdate = false;
}

View file

@ -0,0 +1,152 @@
/*
** flattexture.cpp
** Texture class for standard Doom flats
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "w_wad.h"
bool FFlatTexture::Check(FileReader & file)
{
return true;
}
FTexture *FFlatTexture::Create(FileReader & file, int lumpnum)
{
return new FFlatTexture(lumpnum);
}
FFlatTexture::FFlatTexture (int lumpnum)
: SourceLump(lumpnum), Pixels(0)
{
int area;
int bits;
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
area = Wads.LumpLength (lumpnum);
switch (area)
{
default:
case 64*64: bits = 6; break;
case 8*8: bits = 3; break;
case 16*16: bits = 4; break;
case 32*32: bits = 5; break;
case 128*128: bits = 7; break;
case 256*256: bits = 8; break;
}
bMasked = false;
WidthBits = HeightBits = bits;
Width = Height = 1 << bits;
WidthMask = (1 << bits) - 1;
DummySpans[0].TopOffset = 0;
DummySpans[0].Length = Height;
DummySpans[1].TopOffset = 0;
DummySpans[1].Length = 0;
/*
if (bits > 6)
{
ScaleX = ScaleY = 8 << (bits - 6);
}
else
{
ScaleX = ScaleY = 8;
}
*/
}
FFlatTexture::~FFlatTexture ()
{
Unload ();
}
void FFlatTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FFlatTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = DummySpans;
}
return Pixels + column*Height;
}
const BYTE *FFlatTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FFlatTexture::MakeTexture ()
{
FWadLump lump = Wads.OpenLumpNum (SourceLump);
Pixels = new BYTE[Width*Height];
long numread = lump.Read (Pixels, Width*Height);
if (numread < Width*Height)
{
memset (Pixels + numread, 0xBB, Width*Height - numread);
}
FlipSquareBlockRemap (Pixels, Width, Height, GPalette.Remap);
}

View file

@ -0,0 +1,224 @@
/*
** imgztexture.cpp
** Texture class for IMGZ style images
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "w_wad.h"
// [RH] Just a format I invented to avoid WinTex's palette remapping
// when I wanted to insert some alpha maps.
struct FIMGZTexture::ImageHeader
{
BYTE Magic[4];
WORD Width;
WORD Height;
SWORD LeftOffset;
SWORD TopOffset;
BYTE Compression;
BYTE Reserved[11];
};
bool FIMGZTexture::Check(FileReader & file)
{
DWORD id;
file.Seek(0, SEEK_SET);
file.Read(&id, 4);
return (id == MAKE_ID('I','M','G','Z'));
}
FTexture *FIMGZTexture::Create(FileReader & file, int lumpnum)
{
DWORD magic;
WORD w, h;
SWORD l, t;
file.Seek(0, SEEK_SET);
file >> magic >> w >> h >> l >> t;
return new FIMGZTexture(lumpnum, w, h, l, t);
}
FIMGZTexture::FIMGZTexture (int lumpnum, WORD w, WORD h, SWORD l, SWORD t)
: SourceLump(lumpnum), Pixels(0), Spans(0)
{
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
Width = w;
Height = h;
LeftOffset = l;
TopOffset = t;
CalcBitSize ();
}
FIMGZTexture::~FIMGZTexture ()
{
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
}
void FIMGZTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FIMGZTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
const BYTE *FIMGZTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FIMGZTexture::MakeTexture ()
{
FMemLump lump = Wads.ReadLump (SourceLump);
const ImageHeader *imgz = (const ImageHeader *)lump.GetMem();
const BYTE *data = (const BYTE *)&imgz[1];
if (Width != 0xFFFF)
{
Width = LittleShort(imgz->Width);
Height = LittleShort(imgz->Height);
LeftOffset = LittleShort(imgz->LeftOffset);
TopOffset = LittleShort(imgz->TopOffset);
}
BYTE *dest_p;
int dest_adv = Height;
int dest_rew = Width * Height - 1;
CalcBitSize ();
Pixels = new BYTE[Width*Height];
dest_p = Pixels;
// Convert the source image from row-major to column-major format
if (!imgz->Compression)
{
for (int y = Height; y != 0; --y)
{
for (int x = Width; x != 0; --x)
{
*dest_p = *data;
dest_p += dest_adv;
data++;
}
dest_p -= dest_rew;
}
}
else
{
// IMGZ compression is the same RLE used by IFF ILBM files
int runlen = 0, setlen = 0;
BYTE setval = 0; // Shut up, GCC
for (int y = Height; y != 0; --y)
{
for (int x = Width; x != 0; )
{
if (runlen != 0)
{
BYTE color = *data;
*dest_p = color;
dest_p += dest_adv;
data++;
x--;
runlen--;
}
else if (setlen != 0)
{
*dest_p = setval;
dest_p += dest_adv;
x--;
setlen--;
}
else
{
SBYTE code = *data++;
if (code >= 0)
{
runlen = code + 1;
}
else if (code != -128)
{
setlen = (-code) + 1;
setval = *data++;
}
}
}
dest_p -= dest_rew;
}
}
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
}

View file

@ -0,0 +1,316 @@
/*
** jpegtexture.cpp
** Texture class for JPEG images
**
**---------------------------------------------------------------------------
** Copyright 2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "r_jpeg.h"
#include "w_wad.h"
#include "v_text.h"
void FLumpSourceMgr::InitSource (j_decompress_ptr cinfo)
{
((FLumpSourceMgr *)(cinfo->src))->StartOfFile = true;
}
boolean FLumpSourceMgr::FillInputBuffer (j_decompress_ptr cinfo)
{
FLumpSourceMgr *me = (FLumpSourceMgr *)(cinfo->src);
long nbytes = me->Lump->Read (me->Buffer, sizeof(me->Buffer));
if (nbytes <= 0)
{
me->Buffer[0] = (JOCTET)0xFF;
me->Buffer[1] = (JOCTET)JPEG_EOI;
nbytes = 2;
}
me->next_input_byte = me->Buffer;
me->bytes_in_buffer = nbytes;
me->StartOfFile = false;
return TRUE;
}
void FLumpSourceMgr::SkipInputData (j_decompress_ptr cinfo, long num_bytes)
{
FLumpSourceMgr *me = (FLumpSourceMgr *)(cinfo->src);
if (num_bytes <= (long)me->bytes_in_buffer)
{
me->bytes_in_buffer -= num_bytes;
me->next_input_byte += num_bytes;
}
else
{
num_bytes -= (long)me->bytes_in_buffer;
me->Lump->Seek (num_bytes, SEEK_CUR);
FillInputBuffer (cinfo);
}
}
void FLumpSourceMgr::TermSource (j_decompress_ptr cinfo)
{
}
void JPEG_ErrorExit (j_common_ptr cinfo)
{
(*cinfo->err->output_message) (cinfo);
throw -1;
}
void JPEG_OutputMessage (j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
(*cinfo->err->format_message) (cinfo, buffer);
Printf (TEXTCOLOR_ORANGE "JPEG failure: %s\n", buffer);
}
bool FJPEGTexture::Check(FileReader & file)
{
BYTE hdr[3];
file.Seek(0, SEEK_SET);
file.Read(hdr, 3);
return (hdr[0] == 0xFF && hdr[1] == 0xD8 && hdr[2] == 0xFF);
}
FTexture *FJPEGTexture::Create(FileReader & data, int lumpnum)
{
union
{
DWORD dw;
WORD w[2];
BYTE b[4];
} first4bytes;
data.Seek(0, SEEK_SET);
data.Read(&first4bytes, 4);
// Find the SOFn marker to extract the image dimensions,
// where n is 0, 1, or 2 (other types are unsupported).
while ((unsigned)first4bytes.b[3] - 0xC0 >= 3)
{
if (data.Read (first4bytes.w, 2) != 2)
{
return NULL;
}
data.Seek (BigShort(first4bytes.w[0]) - 2, SEEK_CUR);
if (data.Read (first4bytes.b + 2, 2) != 2 || first4bytes.b[2] != 0xFF)
{
return NULL;
}
}
if (data.Read (first4bytes.b, 3) != 3)
{
return NULL;
}
if (BigShort (first4bytes.w[0]) <5)
{
return NULL;
}
if (data.Read (first4bytes.b, 4) != 4)
{
return NULL;
}
return new FJPEGTexture (lumpnum, BigShort(first4bytes.w[1]), BigShort(first4bytes.w[0]));
}
FLumpSourceMgr::FLumpSourceMgr (FileReader *lump, j_decompress_ptr cinfo)
: Lump (lump)
{
cinfo->src = this;
init_source = InitSource;
fill_input_buffer = FillInputBuffer;
skip_input_data = SkipInputData;
resync_to_restart = jpeg_resync_to_restart;
term_source = TermSource;
bytes_in_buffer = 0;
next_input_byte = NULL;
}
FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height)
: SourceLump(lumpnum), Pixels(0)
{
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
UseType = TEX_MiscPatch;
LeftOffset = 0;
TopOffset = 0;
bMasked = false;
Width = width;
Height = height;
CalcBitSize ();
DummySpans[0].TopOffset = 0;
DummySpans[0].Length = Height;
DummySpans[1].TopOffset = 0;
DummySpans[1].Length = 0;
}
FJPEGTexture::~FJPEGTexture ()
{
Unload ();
}
void FJPEGTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FJPEGTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = DummySpans;
}
return Pixels + column*Height;
}
const BYTE *FJPEGTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FJPEGTexture::MakeTexture ()
{
FWadLump lump = Wads.OpenLumpNum (SourceLump);
JSAMPLE *buff = NULL;
jpeg_decompress_struct cinfo;
jpeg_error_mgr jerr;
Pixels = new BYTE[Width * Height];
memset (Pixels, 0xBA, Width * Height);
cinfo.err = jpeg_std_error(&jerr);
cinfo.err->output_message = JPEG_OutputMessage;
cinfo.err->error_exit = JPEG_ErrorExit;
jpeg_create_decompress(&cinfo);
try
{
FLumpSourceMgr sourcemgr(&lump, &cinfo);
jpeg_read_header(&cinfo, TRUE);
if (!((cinfo.out_color_space == JCS_RGB && cinfo.num_components == 3) ||
(cinfo.out_color_space == JCS_CMYK && cinfo.num_components == 4) ||
(cinfo.out_color_space == JCS_GRAYSCALE && cinfo.num_components == 1)))
{
Printf (TEXTCOLOR_ORANGE "Unsupported color format\n", Name);
throw -1;
}
jpeg_start_decompress(&cinfo);
int y = 0;
buff = new BYTE[cinfo.output_width * cinfo.output_components];
while (cinfo.output_scanline < cinfo.output_height)
{
int num_scanlines = jpeg_read_scanlines(&cinfo, &buff, 1);
BYTE *in = buff;
BYTE *out = Pixels + y;
switch (cinfo.out_color_space)
{
case JCS_RGB:
for (int x = Width; x > 0; --x)
{
*out = RGB32k[in[0]>>3][in[1]>>3][in[2]>>3];
out += Height;
in += 3;
}
break;
case JCS_GRAYSCALE:
for (int x = Width; x > 0; --x)
{
*out = GrayMap[in[0]];
out += Height;
in += 1;
}
break;
case JCS_CMYK:
// What are you doing using a CMYK image? :)
for (int x = Width; x > 0; --x)
{
// To be precise, these calculations should use 255, but
// 256 is much faster and virtually indistinguishable.
int r = in[3] - (((256-in[0])*in[3]) >> 8);
int g = in[3] - (((256-in[1])*in[3]) >> 8);
int b = in[3] - (((256-in[2])*in[3]) >> 8);
*out = RGB32k[r >> 3][g >> 3][b >> 3];
out += Height;
in += 4;
}
break;
}
y++;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
}
catch (int)
{
Printf (TEXTCOLOR_ORANGE " in texture %s\n", Name);
jpeg_destroy_decompress(&cinfo);
}
if (buff != NULL)
{
delete[] buff;
}
}

View file

@ -0,0 +1,534 @@
/*
** multipatchtexture.cpp
** Texture class for standard Doom multipatch textures
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "w_wad.h"
#include "i_system.h"
#include "gi.h"
// On the Alpha, accessing the shorts directly if they aren't aligned on a
// 4-byte boundary causes unaligned access warnings. Why it does this at
// all and only while initing the textures is beyond me.
#ifdef ALPHA
#define SAFESHORT(s) ((short)(((byte *)&(s))[0] + ((byte *)&(s))[1] * 256))
#else
#define SAFESHORT(s) LittleShort(s)
#endif
FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife)
: Pixels (0), Spans(0), Parts(0), bRedirect(false)
{
union
{
const maptexture_t *d;
const strifemaptexture_t *s;
}
mtexture;
union
{
const mappatch_t *d;
const strifemappatch_t *s;
}
mpatch;
int i;
mtexture.d = (const maptexture_t *)texdef;
if (strife)
{
NumParts = SAFESHORT(mtexture.s->patchcount);
}
else
{
NumParts = SAFESHORT(mtexture.d->patchcount);
}
if (NumParts <= 0)
{
I_FatalError ("Bad texture directory");
}
UseType = FTexture::TEX_Wall;
Parts = new TexPart[NumParts];
Width = SAFESHORT(mtexture.d->width);
Height = SAFESHORT(mtexture.d->height);
strncpy (Name, mtexture.d->name, 8);
Name[8] = 0;
CalcBitSize ();
// [RH] Special for beta 29: Values of 0 will use the tx/ty cvars
// to determine scaling instead of defaulting to 8. I will likely
// remove this once I finish the betas, because by then, users
// should be able to actually create scaled textures.
// 10-June-2003: It's still here long after beta 29. Heh.
ScaleX = mtexture.d->ScaleX ? mtexture.d->ScaleX : 0;
ScaleY = mtexture.d->ScaleY ? mtexture.d->ScaleY : 0;
if (mtexture.d->Flags & MAPTEXF_WORLDPANNING)
{
bWorldPanning = true;
}
if (strife)
{
mpatch.s = &mtexture.s->patches[0];
}
else
{
mpatch.d = &mtexture.d->patches[0];
}
for (i = 0; i < NumParts; ++i)
{
if (unsigned(LittleShort(mpatch.d->patch)) >= unsigned(maxpatchnum))
{
I_FatalError ("Bad PNAMES and/or texture directory:\n\nPNAMES has %d entries, but\n%s wants to use entry %d.",
maxpatchnum, Name, LittleShort(mpatch.d->patch)+1);
}
Parts[i].OriginX = LittleShort(mpatch.d->originx);
Parts[i].OriginY = LittleShort(mpatch.d->originy);
Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture;
if (Parts[i].Texture == NULL)
{
Printf ("Unknown patch %s in texture %s\n", patchlookup[LittleShort(mpatch.d->patch)].Name, Name);
NumParts--;
i--;
}
if (strife)
mpatch.s++;
else
mpatch.d++;
}
if (NumParts == 0)
{
Printf ("Texture %s is left without any patches\n", Name);
}
CheckForHacks ();
// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height)
{
bRedirect = true;
}
}
}
FMultiPatchTexture::~FMultiPatchTexture ()
{
Unload ();
if (Parts != NULL)
{
delete[] Parts;
Parts = NULL;
}
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
}
void FMultiPatchTexture::SetFrontSkyLayer ()
{
for (int i = 0; i < NumParts; ++i)
{
Parts[i].Texture->SetFrontSkyLayer ();
}
bNoRemap0 = true;
}
void FMultiPatchTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FMultiPatchTexture::GetPixels ()
{
if (bRedirect)
{
return Parts->Texture->GetPixels ();
}
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
const BYTE *FMultiPatchTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (bRedirect)
{
return Parts->Texture->GetColumn (column, spans_out);
}
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
void FMultiPatchTexture::MakeTexture ()
{
// Add a little extra space at the end if the texture's height is not
// a power of 2, in case somebody accidentally makes it repeat vertically.
int numpix = Width * Height + (1 << HeightBits) - Height;
Pixels = new BYTE[numpix];
memset (Pixels, 0, numpix);
for (int i = 0; i < NumParts; ++i)
{
Parts[i].Texture->CopyToBlock (Pixels, Width, Height,
Parts[i].OriginX, Parts[i].OriginY);
}
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
}
void FMultiPatchTexture::CheckForHacks ()
{
if (NumParts <= 0)
{
return;
}
// Heretic sky textures are marked as only 128 pixels tall,
// even though they are really 200 pixels tall.
if (gameinfo.gametype == GAME_Heretic &&
Name[0] == 'S' &&
Name[1] == 'K' &&
Name[2] == 'Y' &&
Name[4] == 0 &&
Name[3] >= '1' &&
Name[3] <= '3' &&
Height == 128)
{
Height = 200;
HeightBits = 8;
return;
}
// The Doom E1 sky has its patch's y offset at -8 instead of 0.
if (gameinfo.gametype == GAME_Doom &&
!(gameinfo.flags & GI_MAPxx) &&
NumParts == 1 &&
Height == 128 &&
Parts->OriginY == -8 &&
Name[0] == 'S' &&
Name[1] == 'K' &&
Name[2] == 'Y' &&
Name[3] == '1' &&
Name[4] == 0)
{
Parts->OriginY = 0;
return;
}
// BIGDOOR7 in Doom also has patches at y offset -4 instead of 0.
if (gameinfo.gametype == GAME_Doom &&
!(gameinfo.flags & GI_MAPxx) &&
NumParts == 2 &&
Height == 128 &&
Parts[0].OriginY == -4 &&
Parts[1].OriginY == -4 &&
Name[0] == 'B' &&
Name[1] == 'I' &&
Name[2] == 'G' &&
Name[3] == 'D' &&
Name[4] == 'O' &&
Name[5] == 'O' &&
Name[6] == 'R' &&
Name[7] == '7')
{
Parts[0].OriginY = 0;
Parts[1].OriginY = 0;
return;
}
// [RH] Some wads (I forget which!) have single-patch textures 256
// pixels tall that have patch lengths recorded as 0. I can't think of
// any good reason for them to do this, and since I didn't make note
// of which wad made me hack in support for them, the hack is gone
// because I've added support for DeePsea's true tall patches.
//
// Okay, I found a wad with crap patches: Pleiades.wad's sky patches almost
// fit this description and are a big mess, but they're not single patch!
if (Height == 256)
{
int i;
// All patches must be at the top of the texture for this fix
for (i = 0; i < NumParts; ++i)
{
if (Parts[i].OriginX != 0)
{
break;
}
}
if (i == NumParts)
{
// This really must check whether the texture in question is
// actually an FPatchTexture before casting the pointer.
for (i = 0; i < NumParts; ++i) if (Parts[i].Texture->bIsPatch)
{
FPatchTexture *tex = (FPatchTexture *)Parts[i].Texture;
// Check if this patch is likely to be a problem.
// It must be 256 pixels tall, and all its columns must have exactly
// one post, where each post has a supposed length of 0.
FMemLump lump = Wads.ReadLump (tex->SourceLump);
const patch_t *realpatch = (patch_t *)lump.GetMem();
const DWORD *cofs = realpatch->columnofs;
int x, x2 = LittleShort(realpatch->width);
if (LittleShort(realpatch->height) == 256)
{
for (x = 0; x < x2; ++x)
{
const column_t *col = (column_t*)((byte*)realpatch+LittleLong(cofs[x]));
if (col->topdelta != 0 || col->length != 0)
{
break; // It's not bad!
}
col = (column_t *)((byte *)col + 256 + 4);
if (col->topdelta != 0xFF)
{
break; // More than one post in a column!
}
}
if (x == x2)
{ // If all the columns were checked, it needs fixing.
tex->HackHack (Height);
}
}
}
}
}
}
void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int patcheslump, int firstdup, bool texture1)
{
FPatchLookup *patchlookup;
int i, j;
DWORD numpatches;
if (firstdup == 0)
{
firstdup = (int)Textures.Size();
}
{
FWadLump pnames = Wads.OpenLumpNum (patcheslump);
pnames >> numpatches;
// Check whether the amount of names reported is correct.
if (numpatches < 0)
{
Printf("Corrupt PNAMES lump found (negative amount of entries reported)");
return;
}
// Check whether the amount of names reported is correct.
int lumplength = Wads.LumpLength(patcheslump);
if (numpatches > DWORD((lumplength-4)/8))
{
Printf("PNAMES lump is shorter than required (%ld entries reported but only %d bytes (%d entries) long\n",
numpatches, lumplength, (lumplength-4)/8);
// Truncate but continue reading. Who knows how many such lumps exist?
numpatches = (lumplength-4)/8;
}
// Catalog the patches these textures use so we know which
// textures they represent.
patchlookup = (FPatchLookup *)alloca (numpatches * sizeof(*patchlookup));
for (DWORD i = 0; i < numpatches; ++i)
{
pnames.Read (patchlookup[i].Name, 8);
patchlookup[i].Name[8] = 0;
j = CheckForTexture (patchlookup[i].Name, FTexture::TEX_WallPatch);
if (j >= 0)
{
patchlookup[i].Texture = Textures[j].Texture;
}
else
{
// Shareware Doom has the same PNAMES lump as the registered
// Doom, so printing warnings for patches that don't really
// exist isn't such a good idea.
//Printf ("Patch %s not found.\n", patchlookup[i].Name);
patchlookup[i].Texture = NULL;
}
}
}
bool isStrife = false;
const DWORD *maptex, *directory;
DWORD maxoff;
int numtextures;
DWORD offset = 0; // Shut up, GCC!
maptex = (const DWORD *)lumpdata;
numtextures = LittleLong(*maptex);
maxoff = lumpsize;
if (maxoff < DWORD(numtextures+1)*4)
{
Printf ("Texture directory is too short");
return;
}
// Scan the texture lump to decide if it contains Doom or Strife textures
for (i = 0, directory = maptex+1; i < numtextures; ++i)
{
offset = LittleLong(directory[i]);
if (offset > maxoff)
{
Printf ("Bad texture directory");
return;
}
maptexture_t *tex = (maptexture_t *)((BYTE *)maptex + offset);
// There is bizzarely a Doom editing tool that writes to the
// first two elements of columndirectory, so I can't check those.
if (SAFESHORT(tex->patchcount) <= 0 ||
tex->columndirectory[2] != 0 ||
tex->columndirectory[3] != 0)
{
isStrife = true;
break;
}
}
// Textures defined earlier in the lump take precedence over those defined later,
// but later TEXTUREx lumps take precedence over earlier ones.
for (i = 1, directory = maptex; i <= numtextures; ++i)
{
if (i == 1 && texture1)
{
// The very first texture is just a dummy. Copy its dimensions to texture 0.
// It still needs to be created in case someone uses it by name.
offset = LittleLong(directory[1]);
const maptexture_t *tex = (const maptexture_t *)((const BYTE *)maptex + offset);
FDummyTexture *tex0 = static_cast<FDummyTexture *>(Textures[0].Texture);
tex0->SetSize (SAFESHORT(tex->width), SAFESHORT(tex->height));
}
offset = LittleLong(directory[i]);
if (offset > maxoff)
{
Printf ("Bad texture directory");
return;
}
// If this texture was defined already in this lump, skip it
// This could cause problems with animations that use the same name for intermediate
// textures. Should I be worried?
for (j = (int)Textures.Size() - 1; j >= firstdup; --j)
{
if (strnicmp (Textures[j].Texture->Name, (const char *)maptex + offset, 8) == 0)
break;
}
if (j + 1 == firstdup)
{
FTexture *tex = new FMultiPatchTexture ((const BYTE *)maptex + offset, patchlookup, numpatches, isStrife);
if (i == 1 && texture1)
{
tex->UseType = FTexture::TEX_Null;
}
TexMan.AddTexture (tex);
}
}
}
void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump)
{
int firstdup = (int)Textures.Size();
if (lump1 >= 0)
{
FMemLump texdir = Wads.ReadLump (lump1);
AddTexturesLump (texdir.GetMem(), Wads.LumpLength (lump1), patcheslump, firstdup, true);
}
if (lump2 >= 0)
{
FMemLump texdir = Wads.ReadLump (lump2);
AddTexturesLump (texdir.GetMem(), Wads.LumpLength (lump2), patcheslump, firstdup, false);
}
}

View file

@ -0,0 +1,400 @@
/*
** patchtexture.cpp
** Texture class for single Doom patches
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "w_wad.h"
#include "templates.h"
bool FPatchTexture::Check(FileReader & file)
{
if (file.GetLength() < 13) return false; // minimum length of a valid Doom patch
BYTE *data = new BYTE[file.GetLength()];
file.Seek(0, SEEK_SET);
file.Read(data, file.GetLength());
const patch_t * foo = (const patch_t *)data;
int height = LittleShort(foo->height);
int width = LittleShort(foo->width);
bool gapAtStart=true;
if (height > 0 && height < 2048 && width > 0 && width <= 2048 && width < file.GetLength()/4)
{
// The dimensions seem like they might be valid for a patch, so
// check the column directory for extra security. At least one
// column must begin exactly at the end of the column directory,
// and none of them must point past the end of the patch.
bool gapAtStart = true;
int x;
for (x = 0; x < width; ++x)
{
DWORD ofs = LittleLong(foo->columnofs[x]);
if (ofs == (DWORD)width * 4 + 8)
{
gapAtStart = false;
}
else if (ofs >= (DWORD)(file.GetLength())) // Need one byte for an empty column (but there's patches that don't know that!)
{
delete [] data;
return false;
}
}
delete [] data;
return !gapAtStart;
}
delete [] data;
return false;
}
FTexture *FPatchTexture::Create(FileReader & file, int lumpnum)
{
patch_t header;
file.Seek(0, SEEK_SET);
file >> header.width >> header.height >> header.leftoffset >> header.topoffset;
return new FPatchTexture(lumpnum, &header);
}
FPatchTexture::FPatchTexture (int lumpnum, patch_t * header)
: SourceLump(lumpnum), Pixels(0), Spans(0)
{
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
bIsPatch = true;
Width = header->width;
Height = header->height;
LeftOffset = header->leftoffset;
TopOffset = header->topoffset;
}
FPatchTexture::~FPatchTexture ()
{
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
}
void FPatchTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FPatchTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
const BYTE *FPatchTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
void FPatchTexture::MakeTexture ()
{
BYTE *remap, remaptable[256];
Span *spanstuffer, *spanstarter;
const column_t *maxcol;
bool warned;
int numspans;
int x;
FMemLump lump = Wads.ReadLump (SourceLump);
const patch_t *patch = (const patch_t *)lump.GetMem();
maxcol = (const column_t *)((const BYTE *)patch + Wads.LumpLength (SourceLump) - 3);
// Check for badly-sized patches
if (LittleShort(patch->width) <= 0 || LittleShort(patch->height) <= 0)
{
lump = Wads.ReadLump ("-BADPATC");
patch = (const patch_t *)lump.GetMem();
Printf (PRINT_BOLD, "Patch %s has a non-positive size.\n", Name);
}
else if (LittleShort(patch->width) > 2048 || LittleShort(patch->height) > 2048)
{
lump = Wads.ReadLump ("-BADPATC");
patch = (const patch_t *)lump.GetMem();
Printf (PRINT_BOLD, "Patch %s is too big.\n", Name);
}
if (Width == 0xFFFF)
{
Width = LittleShort(patch->width);
Height = LittleShort(patch->height);
LeftOffset = LittleShort(patch->leftoffset);
TopOffset = LittleShort(patch->topoffset);
}
CalcBitSize ();
// Add a little extra space at the end if the texture's height is not
// a power of 2, in case somebody accidentally makes it repeat vertically.
int numpix = Width * Height + (1 << HeightBits) - Height;
numspans = Width;
Pixels = new BYTE[numpix];
memset (Pixels, 0, numpix);
if (bNoRemap0)
{
memcpy (remaptable, GPalette.Remap, 256);
remaptable[0] = 0;
remap = remaptable;
}
else
{
remap = GPalette.Remap;
}
// Draw the image to the buffer
for (x = 0; x < Width; ++x)
{
BYTE *outtop = Pixels + x*Height;
const column_t *column = (const column_t *)((const BYTE *)patch + LittleLong(patch->columnofs[x]));
int top = -1;
while (column < maxcol && column->topdelta != 0xFF)
{
if (column->topdelta <= top)
{
top += column->topdelta;
}
else
{
top = column->topdelta;
}
int len = column->length;
BYTE *out = outtop + top;
if (len != 0)
{
if (top + len > Height) // Clip posts that extend past the bottom
{
len = Height - top;
}
if (len > 0)
{
numspans++;
const BYTE *in = (const BYTE *)column + 3;
for (int i = 0; i < len; ++i)
{
out[i] = remap[in[i]];
}
}
}
column = (const column_t *)((const BYTE *)column + column->length + 4);
}
}
// Create the spans
if (Spans != NULL)
{
return;
}
Spans = (Span **)M_Malloc (sizeof(Span*)*Width + sizeof(Span)*numspans);
spanstuffer = (Span *)((BYTE *)Spans + sizeof(Span*)*Width);
warned = false;
for (x = 0; x < Width; ++x)
{
const column_t *column = (const column_t *)((const BYTE *)patch + LittleLong(patch->columnofs[x]));
int top = -1;
Spans[x] = spanstuffer;
spanstarter = spanstuffer;
while (column < maxcol && column->topdelta != 0xFF)
{
if (column->topdelta <= top)
{
top += column->topdelta;
}
else
{
top = column->topdelta;
}
int len = column->length;
if (len != 0)
{
if (top + len > Height) // Clip posts that extend past the bottom
{
len = Height - top;
}
if (len > 0)
{
// There is something of this post to draw. If it starts at the same
// place where the previous span ends, add it to that one. If it starts
// before the other one ends, that's bad, but deal with it. If it starts
// after the previous one ends, create another span.
// Assume we need to create another span.
spanstuffer->TopOffset = top;
spanstuffer->Length = len;
// Now check if that's really the case.
if (spanstuffer > spanstarter)
{
if ((spanstuffer - 1)->TopOffset + (spanstuffer - 1)->Length == top)
{
(--spanstuffer)->Length += len;
}
else
{
int prevbot;
while (spanstuffer > spanstarter &&
spanstuffer->TopOffset < (prevbot =
(spanstuffer - 1)->TopOffset + (spanstuffer - 1)->Length))
{
if (spanstuffer->TopOffset < (spanstuffer - 1)->TopOffset)
{
(spanstuffer - 1)->TopOffset = spanstuffer->TopOffset;
}
(spanstuffer - 1)->Length = MAX(prevbot,
spanstuffer->TopOffset + spanstuffer->Length)
- (spanstuffer - 1)->TopOffset;
spanstuffer--;
if (!warned)
{
warned = true;
Printf (PRINT_BOLD, "Patch %s is malformed.\n", Name);
}
}
}
}
spanstuffer++;
}
}
column = (const column_t *)((const BYTE *)column + column->length + 4);
}
spanstuffer->Length = spanstuffer->TopOffset = 0;
spanstuffer++;
}
}
// Fix for certain special patches on single-patch textures.
void FPatchTexture::HackHack (int newheight)
{
BYTE *out;
int x;
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
}
{
FMemLump lump = Wads.ReadLump (SourceLump);
const patch_t *patch = (const patch_t *)lump.GetMem();
Width = LittleShort(patch->width);
Height = newheight;
LeftOffset = 0;
TopOffset = 0;
Pixels = new BYTE[Width * Height];
// Draw the image to the buffer
for (x = 0, out = Pixels; x < Width; ++x)
{
const BYTE *in = (const BYTE *)patch + LittleLong(patch->columnofs[x]) + 3;
for (int y = newheight; y > 0; --y)
{
*out = *in != 255 ? *in : Near255;
out++, in++;
}
out += newheight;
}
}
// Create the spans
Spans = (Span **)M_Malloc (sizeof(Span *)*Width + sizeof(Span)*Width*2);
Span *span = (Span *)&Spans[Width];
for (x = 0; x < Width; ++x)
{
Spans[x] = span;
span[0].Length = newheight;
span[0].TopOffset = 0;
span[1].Length = 0;
span[1].TopOffset = 0;
span += 2;
}
}

419
src/textures/pngtexture.cpp Normal file
View file

@ -0,0 +1,419 @@
/*
** pmgtexture.cpp
** Texture class for PNG images
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_local.h"
#include "w_wad.h"
#include "templates.h"
#include "m_png.h"
bool FPNGTexture::Check(FileReader & file)
{
DWORD id;
file.Seek(0, SEEK_SET);
file.Read(&id, 4);
return (id == MAKE_ID(137,'P','N','G'));
}
FTexture *FPNGTexture::Create(FileReader & data, int lumpnum)
{
union
{
DWORD dw;
WORD w[2];
BYTE b[4];
} first4bytes;
DWORD width, height;
BYTE bitdepth, colortype, compression, filter, interlace;
// This is most likely a PNG, but make sure. (Note that if the
// first 4 bytes match, but later bytes don't, we assume it's
// a corrupt PNG.)
data.Seek(4, SEEK_SET);
data.Read (first4bytes.b, 4);
if (first4bytes.dw != MAKE_ID(13,10,26,10)) return NULL;
data.Read (first4bytes.b, 4);
if (first4bytes.dw != MAKE_ID(0,0,0,13)) return NULL;
data.Read (first4bytes.b, 4);
if (first4bytes.dw != MAKE_ID('I','H','D','R')) return NULL;
// The PNG looks valid so far. Check the IHDR to make sure it's a
// type of PNG we support.
data >> width >> height
>> bitdepth >> colortype >> compression >> filter >> interlace;
if (compression != 0 || filter != 0 || interlace > 1)
{
return NULL;
}
if (!((1 << colortype) & 0x5D))
{
return NULL;
}
if (!((1 << bitdepth) & 0x116))
{
return NULL;
}
// Just for completeness, make sure the PNG has something more than an
// IHDR.
data.Seek (4, SEEK_CUR);
data.Read (first4bytes.b, 4);
if (first4bytes.dw == 0)
{
data.Read (first4bytes.b, 4);
if (first4bytes.dw == MAKE_ID('I','E','N','D'))
{
return NULL;
}
}
return new FPNGTexture (data, lumpnum, BigLong((int)width), BigLong((int)height),
bitdepth, colortype, interlace);
}
FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height,
BYTE depth, BYTE colortype, BYTE interlace)
: SourceLump(lumpnum), Pixels(0), Spans(0),
BitDepth(depth), ColorType(colortype), Interlace(interlace),
PaletteMap(0), PaletteSize(0), StartOfIDAT(0)
{
union
{
DWORD palette[256];
BYTE pngpal[256][3];
};
BYTE trans[256];
bool havetRNS = false;
DWORD len, id;
int i;
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
UseType = TEX_MiscPatch;
LeftOffset = 0;
TopOffset = 0;
bMasked = false;
Width = width;
Height = height;
CalcBitSize ();
memset (trans, 255, 256);
// Parse pre-IDAT chunks. I skip the CRCs. Is that bad?
lump.Seek (33, SEEK_SET);
lump >> len >> id;
while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D'))
{
len = BigLong((unsigned int)len);
switch (id)
{
default:
lump.Seek (len, SEEK_CUR);
break;
case MAKE_ID('g','r','A','b'):
// This is like GRAB found in an ILBM, except coordinates use 4 bytes
{
DWORD hotx, hoty;
lump >> hotx >> hoty;
LeftOffset = BigLong((int)hotx);
TopOffset = BigLong((int)hoty);
}
break;
case MAKE_ID('P','L','T','E'):
PaletteSize = MIN<int> (len / 3, 256);
lump.Read (pngpal, PaletteSize * 3);
if (PaletteSize * 3 != (int)len)
{
lump.Seek (len - PaletteSize * 3, SEEK_CUR);
}
for (i = PaletteSize - 1; i >= 0; --i)
{
palette[i] = MAKERGB(pngpal[i][0], pngpal[i][1], pngpal[i][2]);
}
break;
case MAKE_ID('t','R','N','S'):
lump.Read (trans, len);
havetRNS = true;
break;
case MAKE_ID('a','l','P','h'):
bAlphaTexture = true;
bMasked = true;
break;
}
lump >> len >> len; // Skip CRC
id = MAKE_ID('I','E','N','D');
lump >> id;
}
StartOfIDAT = lump.Tell() - 8;
switch (colortype)
{
case 4: // Grayscale + Alpha
bMasked = true;
// intentional fall-through
case 0: // Grayscale
if (!bAlphaTexture)
{
if (colortype == 0 && havetRNS && trans[0] != 0)
{
bMasked = true;
PaletteSize = 256;
PaletteMap = new BYTE[256];
memcpy (PaletteMap, GrayMap, 256);
PaletteMap[trans[0]] = 0;
}
else
{
PaletteMap = GrayMap;
}
}
break;
case 3: // Paletted
PaletteMap = new BYTE[PaletteSize];
GPalette.MakeRemap (palette, PaletteMap, trans, PaletteSize);
for (i = 0; i < PaletteSize; ++i)
{
if (trans[i] == 0)
{
bMasked = true;
PaletteMap[i] = 0;
}
}
break;
case 6: // RGB + Alpha
bMasked = true;
break;
}
}
FPNGTexture::~FPNGTexture ()
{
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
if (PaletteMap != NULL && PaletteMap != GrayMap)
{
delete[] PaletteMap;
PaletteMap = NULL;
}
}
void FPNGTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FPNGTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
const BYTE *FPNGTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FPNGTexture::MakeTexture ()
{
FWadLump lump = Wads.OpenLumpNum (SourceLump);
Pixels = new BYTE[Width*Height];
if (StartOfIDAT == 0)
{
memset (Pixels, 0x99, Width*Height);
}
else
{
DWORD len, id;
lump.Seek (StartOfIDAT, SEEK_SET);
lump >> len >> id;
if (ColorType == 0 || ColorType == 3) /* Grayscale and paletted */
{
M_ReadIDAT (&lump, Pixels, Width, Height, Width, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
if (Width == Height)
{
if (PaletteMap != NULL)
{
FlipSquareBlockRemap (Pixels, Width, Height, PaletteMap);
}
else
{
FlipSquareBlock (Pixels, Width, Height);
}
}
else
{
BYTE *newpix = new BYTE[Width*Height];
if (PaletteMap != NULL)
{
FlipNonSquareBlockRemap (newpix, Pixels, Width, Height, PaletteMap);
}
else
{
FlipNonSquareBlock (newpix, Pixels, Width, Height, Width);
}
BYTE *oldpix = Pixels;
Pixels = newpix;
delete[] oldpix;
}
}
else /* RGB and/or Alpha present */
{
int bytesPerPixel = ColorType == 2 ? 3 : ColorType == 4 ? 2 : 4;
BYTE *tempix = new BYTE[Width * Height * bytesPerPixel];
BYTE *in, *out;
int x, y, pitch, backstep;
M_ReadIDAT (&lump, tempix, Width, Height, Width*bytesPerPixel, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
in = tempix;
out = Pixels;
// Convert from source format to paletted, column-major.
// Formats with alpha maps are reduced to only 1 bit of alpha.
switch (ColorType)
{
case 2: // RGB
pitch = Width * 3;
backstep = Height * pitch - 3;
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = RGB32k[in[0]>>3][in[1]>>3][in[2]>>3];
in += pitch;
}
in -= backstep;
}
break;
case 4: // Grayscale + Alpha
pitch = Width * 2;
backstep = Height * pitch - 2;
if (PaletteMap != NULL)
{
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = in[1] < 128 ? 0 : PaletteMap[in[0]];
in += pitch;
}
in -= backstep;
}
}
else
{
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = in[1] < 128 ? 0 : in[0];
in += pitch;
}
in -= backstep;
}
}
break;
case 6: // RGB + Alpha
pitch = Width * 4;
backstep = Height * pitch - 4;
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = in[3] < 128 ? 0 : RGB32k[in[0]>>3][in[1]>>3][in[2]>>3];
in += pitch;
}
in -= backstep;
}
break;
}
delete[] tempix;
}
}
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
}

View file

@ -0,0 +1,201 @@
/*
** rawpagetexture.cpp
** Texture class for Raven's raw fullscreen pages
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "w_wad.h"
bool FRawPageTexture::Check(FileReader & data)
{
if (data.GetLength() != 64000) return false;
// This is probably a raw page graphic, but do some checking to be sure
patch_t *foo;
int height;
int width;
foo = (patch_t *)M_Malloc (data.GetLength());
data.Seek (0, SEEK_SET);
data.Read (foo, data.GetLength());
height = LittleShort(foo->height);
width = LittleShort(foo->width);
if (height > 0 && height < 510 && width > 0 && width < 15997)
{
// The dimensions seem like they might be valid for a patch, so
// check the column directory for extra security. At least one
// column must begin exactly at the end of the column directory,
// and none of them must point past the end of the patch.
bool gapAtStart = true;
int x;
for (x = 0; x < width; ++x)
{
DWORD ofs = LittleLong(foo->columnofs[x]);
if (ofs == (DWORD)width * 4 + 8)
{
gapAtStart = false;
}
else if (ofs >= 64000-1) // Need one byte for an empty column
{
free (foo);
return true;
}
else
{
// Ensure this column does not extend beyond the end of the patch
const BYTE *foo2 = (const BYTE *)foo;
while (ofs < 64000)
{
if (foo2[ofs] == 255)
{
free (foo);
return true;
}
ofs += foo2[ofs+1] + 4;
}
if (ofs >= 64000)
{
free (foo);
return true;
}
}
}
if (gapAtStart || (x != width))
{
free (foo);
return true;
}
free(foo);
return false;
}
else
{
free (foo);
return true;
}
}
FTexture *FRawPageTexture::Create(FileReader & file, int lumpnum)
{
return new FRawPageTexture(lumpnum);
}
const FTexture::Span FRawPageTexture::DummySpans[2] =
{
{ 0, 200 }, { 0, 0 }
};
FRawPageTexture::FRawPageTexture (int lumpnum)
: SourceLump(lumpnum), Pixels(0)
{
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
Width = 320;
Height = 200;
WidthBits = 8;
HeightBits = 8;
WidthMask = 255;
}
FRawPageTexture::~FRawPageTexture ()
{
Unload ();
}
void FRawPageTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FRawPageTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
column %= 320;
}
if (spans_out != NULL)
{
*spans_out = DummySpans;
}
return Pixels + column*Height;
}
const BYTE *FRawPageTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FRawPageTexture::MakeTexture ()
{
FMemLump lump = Wads.ReadLump (SourceLump);
const BYTE *source = (const BYTE *)lump.GetMem();
const BYTE *source_p = source;
BYTE *dest_p;
Pixels = new BYTE[Width*Height];
dest_p = Pixels;
// Convert the source image from row-major to column-major format
for (int y = 200; y != 0; --y)
{
for (int x = 320; x != 0; --x)
{
*dest_p = GPalette.Remap[*source_p];
dest_p += 200;
source_p++;
}
dest_p -= 200*320-1;
}
}

423
src/textures/texture.cpp Normal file
View file

@ -0,0 +1,423 @@
/*
** texture.cpp
** The base texture class
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "w_wad.h"
#include "r_data.h"
#include "templates.h"
typedef bool (*CheckFunc)(FileReader & file);
typedef FTexture * (*CreateFunc)(FileReader & file, int lumpnum);
struct TexCreateInfo
{
CheckFunc Check;
CreateFunc Create;
int usetype;
};
BYTE FTexture::GrayMap[256];
void FTexture::InitGrayMap()
{
for (int i = 0; i < 256; ++i)
{
GrayMap[i] = ColorMatcher.Pick (i, i, i);
}
}
// Examines the lump contents to decide what type of texture to create,
// and creates the texture.
FTexture * FTexture::CreateTexture (int lumpnum, int usetype)
{
static TexCreateInfo CreateInfo[]={
{ FIMGZTexture::Check, FIMGZTexture::Create, FTexture::TEX_Any },
{ FPNGTexture::Check, FPNGTexture::Create, FTexture::TEX_Any },
{ FJPEGTexture::Check, FJPEGTexture::Create, FTexture::TEX_Any },
{ FTGATexture::Check, FTGATexture::Create, FTexture::TEX_Any },
{ FRawPageTexture::Check, FRawPageTexture::Create, FTexture::TEX_MiscPatch },
{ FFlatTexture::Check, FFlatTexture::Create, FTexture::TEX_Flat },
{ FPatchTexture::Check, FPatchTexture::Create, FTexture::TEX_Any },
{ FAutomapTexture::Check, FAutomapTexture::Create, FTexture::TEX_Autopage },
};
FWadLump data = Wads.OpenLumpNum (lumpnum);
for(int i = 0; i < countof(CreateInfo); i++)
{
if ((CreateInfo[i].usetype == usetype || CreateInfo[i].usetype == TEX_Any) &&
CreateInfo[i].Check(data))
{
FTexture * tex = CreateInfo[i].Create(data, lumpnum);
if (tex != NULL)
{
tex->UseType = usetype;
if (usetype == FTexture::TEX_Flat)
{
int w = tex->GetWidth();
int h = tex->GetHeight();
// Auto-scale flats with dimensions 128x128 and 256x256
if (w==128 && h==128) tex->ScaleX = tex->ScaleY = 16;
else if (w==256 && h==256) tex->ScaleX = tex->ScaleY = 32;
}
return tex;
}
}
}
return NULL;
}
FTexture::FTexture ()
: LeftOffset(0), TopOffset(0),
WidthBits(0), HeightBits(0), ScaleX(8), ScaleY(8),
UseType(TEX_Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false),
bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bIsPatch(false),
Rotations(0xFFFF), Width(0), Height(0), WidthMask(0)
{
*Name=0;
}
FTexture::~FTexture ()
{
}
bool FTexture::CheckModified ()
{
return false;
}
void FTexture::SetFrontSkyLayer ()
{
bNoRemap0 = true;
}
void FTexture::CalcBitSize ()
{
// WidthBits is rounded down, and HeightBits is rounded up
int i;
for (i = 0; (1 << i) < Width; ++i)
{ }
WidthBits = i;
// Having WidthBits that would allow for columns past the end of the
// texture is not allowed, even if it means the entire texture is
// not drawn.
if (Width < (1 << WidthBits))
{
WidthBits--;
}
WidthMask = (1 << WidthBits) - 1;
// The minimum height is 2, because we cannot shift right 32 bits.
for (i = 1; (1 << i) < Height; ++i)
{ }
HeightBits = i;
}
FTexture::Span **FTexture::CreateSpans (const BYTE *pixels) const
{
Span **spans, *span;
if (!bMasked)
{ // Texture does not have holes, so it can use a simpler span structure
spans = (Span **)M_Malloc (sizeof(Span*)*Width + sizeof(Span)*2);
span = (Span *)&spans[Width];
for (int x = 0; x < Width; ++x)
{
spans[x] = span;
}
span[0].Length = Height;
span[0].TopOffset = 0;
span[1].Length = 0;
span[1].TopOffset = 0;
}
else
{ // Texture might have holes, so build a complete span structure
int numcols = Width;
int numrows = Height;
int numspans = numcols; // One span to terminate each column
const BYTE *data_p;
bool newspan;
int x, y;
data_p = pixels;
// Count the number of spans in this texture
for (x = numcols; x > 0; --x)
{
newspan = true;
for (y = numrows; y > 0; --y)
{
if (*data_p++ == 0)
{
if (!newspan)
{
newspan = true;
}
}
else if (newspan)
{
newspan = false;
numspans++;
}
}
}
// Allocate space for the spans
spans = (Span **)M_Malloc (sizeof(Span*)*numcols + sizeof(Span)*numspans);
// Fill in the spans
for (x = 0, span = (Span *)&spans[numcols], data_p = pixels; x < numcols; ++x)
{
newspan = true;
spans[x] = span;
for (y = 0; y < numrows; ++y)
{
if (*data_p++ == 0)
{
if (!newspan)
{
newspan = true;
span++;
}
}
else
{
if (newspan)
{
newspan = false;
span->TopOffset = y;
span->Length = 1;
}
else
{
span->Length++;
}
}
}
if (!newspan)
{
span++;
}
span->TopOffset = 0;
span->Length = 0;
span++;
}
}
return spans;
}
void FTexture::FreeSpans (Span **spans) const
{
free (spans);
}
void FTexture::CopyToBlock (BYTE *dest, int dwidth, int dheight, int xpos, int ypos, const BYTE *translation)
{
int x1 = xpos, x2 = x1 + GetWidth(), xo = -x1;
if (x1 < 0)
{
x1 = 0;
}
if (x2 > dwidth)
{
x2 = dwidth;
}
for (; x1 < x2; ++x1)
{
const BYTE *data;
const Span *span;
BYTE *outtop = &dest[dheight * x1];
data = GetColumn (x1 + xo, &span);
while (span->Length != 0)
{
int len = span->Length;
int y = ypos + span->TopOffset;
int adv = span->TopOffset;
if (y < 0)
{
adv -= y;
len += y;
y = 0;
}
if (y + len > dheight)
{
len = dheight - y;
}
if (len > 0)
{
if (translation == NULL)
{
memcpy (outtop + y, data + adv, len);
}
else
{
for (int j = 0; j < len; ++j)
{
outtop[y+j] = translation[data[adv+j]];
}
}
}
span++;
}
}
}
// Converts a texture between row-major and column-major format
// by flipping it about the X=Y axis.
void FTexture::FlipSquareBlock (BYTE *block, int x, int y)
{
int i, j;
if (x != y) return;
for (i = 0; i < x; ++i)
{
BYTE *corner = block + x*i + i;
int count = x - i;
if (count & 1)
{
count--;
swap<BYTE> (corner[count], corner[count*x]);
}
for (j = 0; j < count; j += 2)
{
swap<BYTE> (corner[j], corner[j*x]);
swap<BYTE> (corner[j+1], corner[(j+1)*x]);
}
}
}
void FTexture::FlipSquareBlockRemap (BYTE *block, int x, int y, const BYTE *remap)
{
int i, j;
BYTE t;
if (x != y) return;
for (i = 0; i < x; ++i)
{
BYTE *corner = block + x*i + i;
int count = x - i;
if (count & 1)
{
count--;
t = remap[corner[count]];
corner[count] = remap[corner[count*x]];
corner[count*x] = t;
}
for (j = 0; j < count; j += 2)
{
t = remap[corner[j]];
corner[j] = remap[corner[j*x]];
corner[j*x] = t;
t = remap[corner[j+1]];
corner[j+1] = remap[corner[(j+1)*x]];
corner[(j+1)*x] = t;
}
}
}
void FTexture::FlipNonSquareBlock (BYTE *dst, const BYTE *src, int x, int y, int srcpitch)
{
int i, j;
for (i = 0; i < x; ++i)
{
for (j = 0; j < y; ++j)
{
dst[i*y+j] = src[i+j*srcpitch];
}
}
}
void FTexture::FlipNonSquareBlockRemap (BYTE *dst, const BYTE *src, int x, int y, const BYTE *remap)
{
int i, j;
for (i = 0; i < x; ++i)
{
for (j = 0; j < y; ++j)
{
dst[i*y+j] = remap[src[i+j*x]];
}
}
}
FDummyTexture::FDummyTexture ()
{
Width = 64;
Height = 64;
HeightBits = 6;
WidthBits = 6;
WidthMask = 63;
Name[0] = 0;
UseType = TEX_Null;
}
void FDummyTexture::Unload ()
{
}
void FDummyTexture::SetSize (int width, int height)
{
Width = width;
Height = height;
CalcBitSize ();
}
// This must never be called
const BYTE *FDummyTexture::GetColumn (unsigned int column, const Span **spans_out)
{
return NULL;
}
// And this also must never be called
const BYTE *FDummyTexture::GetPixels ()
{
return NULL;
}

398
src/textures/tgatexture.cpp Normal file
View file

@ -0,0 +1,398 @@
/*
** pmgtexture.cpp
** Texture class for TGA images
**
**---------------------------------------------------------------------------
** Copyright 2006 Christoph Oelckers
** 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 "doomtype.h"
#include "files.h"
#include "r_local.h"
#include "w_wad.h"
#include "templates.h"
#pragma pack(1)
struct TGAHeader
{
BYTE id_len;
BYTE has_cm;
BYTE img_type;
SWORD cm_first;
SWORD cm_length;
BYTE cm_size;
SWORD x_origin;
SWORD y_origin;
SWORD width;
SWORD height;
BYTE bpp;
BYTE img_desc;
};
#pragma pack()
bool FTGATexture::Check(FileReader & data)
{
TGAHeader hdr;
if (data.GetLength() < sizeof(hdr)) return false;
data.Seek(0, SEEK_SET);
data.Read(&hdr, sizeof(hdr));
#ifdef WORDS_BIGENDIAN
hdr.width = LittleShort(hdr.width);
hdr.height = LittleShort(hdr.height);
#endif
// Not much that can be done here because TGA does not have a proper
// header to be identified with.
if (hdr.has_cm != 0 && hdr.has_cm != 1) return false;
if (hdr.width <=0 || hdr.height <=0 || hdr.width > 2048 || hdr.height > 2048) return false;
if (hdr.bpp != 8 && hdr.bpp != 15 && hdr.bpp != 16 && hdr.bpp !=24 && hdr.bpp !=32) return false;
if (hdr.img_type <= 0 || hdr.img_type > 11) return false;
if (hdr.img_type >=4 && hdr.img_type <= 8) return false;
if ((hdr.img_desc & 16) != 0) return false;
return true;
}
FTexture *FTGATexture::Create(FileReader & file, int lumpnum)
{
TGAHeader hdr;
file.Seek(0, SEEK_SET);
file.Read(&hdr, sizeof(hdr));
return new FTGATexture(lumpnum, LittleShort(hdr.width), LittleShort(hdr.height));
}
FTGATexture::FTGATexture (int lumpnum, int w, int h)
: SourceLump(lumpnum), Pixels(0), Spans(0)
{
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
Width = w;
Height = h;
CalcBitSize();
}
FTGATexture::~FTGATexture ()
{
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
}
void FTGATexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FTGATexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
const BYTE *FTGATexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FTGATexture::ReadCompressed(FileReader &lump, BYTE * buffer, int bytesperpixel)
{
BYTE b;
BYTE data[4];
int Size = Width * Height;
while (Size > 0)
{
lump >> b;
if (b & 128)
{
b&=~128;
lump.Read(data, bytesperpixel);
for (int i=MIN<int>(Size, (b+1)); i>0; i--)
{
buffer[0] = data[0];
if (bytesperpixel>=2) buffer[1] = data[1];
if (bytesperpixel>=3) buffer[2] = data[2];
if (bytesperpixel==4) buffer[3] = data[3];
buffer+=bytesperpixel;
}
}
else
{
lump.Read(buffer, MIN<int>(Size, (b+1))*bytesperpixel);
buffer += (b+1)*bytesperpixel;
}
Size -= b+1;
}
}
void FTGATexture::MakeTexture ()
{
BYTE PaletteMap[256];
FWadLump lump = Wads.OpenLumpNum (SourceLump);
TGAHeader hdr;
WORD w;
BYTE r,g,b,a;
BYTE * buffer;
Pixels = new BYTE[Width*Height];
lump.Read(&hdr, sizeof(hdr));
lump.Seek(hdr.id_len, SEEK_CUR);
#ifdef WORDS_BIGENDIAN
hdr.width = LittleShort(hdr.width);
hdr.height = LittleShort(hdr.height);
hdr.cm_first = LittleShort(hdr.cm_first);
hdr.cm_length = LittleShort(hdr.cm_length);
#endif
bMasked = false;
if (hdr.has_cm)
{
memset(PaletteMap, 0, 256);
for (int i = hdr.cm_first; i < hdr.cm_first + hdr.cm_length && i < 256; i++)
{
switch (hdr.cm_size)
{
case 15:
case 16:
lump >> w;
r = (w & 0x001F) << 3;
g = (w & 0x03E0) >> 2;
b = (w & 0x7C00) >> 7;
a = 255;
break;
case 24:
lump >> b >> g >> r;
a=255;
break;
case 32:
lump >> b >> g >> r >> a;
if ((hdr.img_desc&15)!=8) a=255;
else if (a<128) bMasked=true;
break;
default: // should never happen
r=g=b=a=0;
break;
}
PaletteMap[i] = a>=128? ColorMatcher.Pick(r, g, b) : 0;
}
}
int Size = Width * Height * (hdr.bpp>>3);
buffer = new BYTE[Size];
if (hdr.img_type < 4) // uncompressed
{
lump.Read(buffer, Size);
}
else // compressed
{
ReadCompressed(lump, buffer, hdr.bpp>>3);
}
BYTE * ptr = buffer;
int step_x = (hdr.bpp>>3);
int Pitch = Width * step_x;
if (hdr.img_desc&32)
{
ptr += (Width-1) * step_x;
step_x =- step_x;
}
if (!(hdr.img_desc&64))
{
ptr += (Height-1) * Pitch;
Pitch = -Pitch;
}
switch (hdr.img_type & 7)
{
case 1: // paletted
for(int y=0;y<Height;y++)
{
BYTE * p = ptr + y * Pitch;
for(int x=0;x<Width;x++)
{
Pixels[x*Height+y] = PaletteMap[*p];
p+=step_x;
}
}
break;
case 2: // RGB
switch (hdr.bpp)
{
case 15:
case 16:
step_x>>=1;
for(int y=0;y<Height;y++)
{
WORD * p = (WORD*)(ptr + y * Pitch);
for(int x=0;x<Width;x++)
{
int v = LittleLong(*p);
Pixels[x*Height+y] = RGB32k[(v>>10) & 0x1f][(v>>5) & 0x1f][v & 0x1f];
p+=step_x;
}
}
break;
case 24:
for(int y=0;y<Height;y++)
{
BYTE * p = ptr + y * Pitch;
for(int x=0;x<Width;x++)
{
Pixels[x*Height+y] = RGB32k[p[2]>>3][p[1]>>3][p[0]>>3];
p+=step_x;
}
}
break;
case 32:
if ((hdr.img_desc&15)!=8) // 32 bits without a valid alpha channel
{
for(int y=0;y<Height;y++)
{
BYTE * p = ptr + y * Pitch;
for(int x=0;x<Width;x++)
{
Pixels[x*Height+y] = RGB32k[p[2]>>3][p[1]>>3][p[0]>>3];
p+=step_x;
}
}
}
else
{
bMasked=true;
for(int y=0;y<Height;y++)
{
BYTE * p = ptr + y * Pitch;
for(int x=0;x<Width;x++)
{
Pixels[x*Height+y] = p[3] >= 128? RGB32k[p[2]>>3][p[1]>>3][p[0]>>3] : 0;
p+=step_x;
}
}
}
break;
default:
break;
}
break;
case 3: // Grayscale
switch (hdr.bpp)
{
case 8:
for(int y=0;y<Height;y++)
{
BYTE * p = ptr + y * Pitch;
for(int x=0;x<Width;x++)
{
Pixels[x*Height+y] = GrayMap[*p];
p+=step_x;
}
}
break;
case 16:
for(int y=0;y<Height;y++)
{
BYTE * p = ptr + y * Pitch;
for(int x=0;x<Width;x++)
{
Pixels[x*Height+y] = GrayMap[p[1]]; // only use the high byte
p+=step_x;
}
}
break;
default:
break;
}
break;
default:
break;
}
delete [] buffer;
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
}

View file

@ -0,0 +1,233 @@
/*
** warptexture.cpp
** Texture class for warped textures
**
**---------------------------------------------------------------------------
** Copyright 2004-2006 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 "doomtype.h"
#include "files.h"
#include "r_data.h"
#include "templates.h"
FWarpTexture::FWarpTexture (FTexture *source)
: SourcePic (source), Pixels (0), Spans (0), GenTime (0)
{
Width = source->GetWidth ();
Height = source->GetHeight ();
LeftOffset = source->LeftOffset;
TopOffset = source->TopOffset;
WidthBits = source->WidthBits;
HeightBits = source->HeightBits;
WidthMask = (1 << WidthBits) - 1;
ScaleX = source->ScaleX;
ScaleY = source->ScaleY;
bNoDecals = source->bNoDecals;
Rotations = source->Rotations;
bWarped = 1;
}
FWarpTexture::~FWarpTexture ()
{
Unload ();
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
delete SourcePic;
}
void FWarpTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
SourcePic->Unload ();
}
bool FWarpTexture::CheckModified ()
{
return r_FrameTime != GenTime;
}
const BYTE *FWarpTexture::GetPixels ()
{
DWORD time = r_FrameTime;
if (Pixels == NULL || time != GenTime)
{
MakeTexture (time);
}
return Pixels;
}
const BYTE *FWarpTexture::GetColumn (unsigned int column, const Span **spans_out)
{
DWORD time = r_FrameTime;
if (Pixels == NULL || time != GenTime)
{
MakeTexture (time);
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
if (Spans == NULL)
{
Spans = CreateSpans (Pixels);
}
*spans_out = Spans[column];
}
return Pixels + column*Height;
}
void FWarpTexture::MakeTexture (DWORD time)
{
const BYTE *otherpix = SourcePic->GetPixels ();
if (Pixels == NULL)
{
Pixels = new BYTE[Width * Height];
}
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
GenTime = time;
byte *buffer = (byte *)alloca (MAX (Width, Height));
int xsize = Width;
int ysize = Height;
int xmask = WidthMask;
int ymask = Height - 1;
int ybits = HeightBits;
int x, y;
if ((1 << ybits) > Height)
{
ybits--;
}
DWORD timebase = time * 32 / 28;
for (y = ysize-1; y >= 0; y--)
{
int xt, xf = (finesine[(timebase+y*128)&FINEMASK]>>13) & xmask;
const BYTE *source = otherpix + y;
BYTE *dest = Pixels + y;
for (xt = xsize; xt; xt--, xf = (xf+1)&xmask, dest += ysize)
*dest = source[xf << ybits];
}
timebase = time * 23 / 28;
for (x = xsize-1; x >= 0; x--)
{
int yt, yf = (finesine[(time+(x+17)*128)&FINEMASK]>>13) & ymask;
const BYTE *source = Pixels + (x << ybits);
BYTE *dest = buffer;
for (yt = ysize; yt; yt--, yf = (yf+1)&ymask)
*dest++ = source[yf];
memcpy (Pixels+(x<<ybits), buffer, ysize);
}
}
// [GRB] Eternity-like warping
FWarp2Texture::FWarp2Texture (FTexture *source)
: FWarpTexture (source)
{
bWarped = 2;
}
void FWarp2Texture::MakeTexture (DWORD time)
{
const BYTE *otherpix = SourcePic->GetPixels ();
if (Pixels == NULL)
{
Pixels = new BYTE[Width * Height];
}
if (Spans != NULL)
{
FreeSpans (Spans);
Spans = NULL;
}
GenTime = time;
int xsize = Width;
int ysize = Height;
int xmask = WidthMask;
int ymask = Height - 1;
int ybits = HeightBits;
int x, y;
if ((1 << ybits) > Height)
{
ybits--;
}
DWORD timebase = time * 40 / 28;
for (x = xsize-1; x >= 0; x--)
{
for (y = ysize-1; y >= 0; y--)
{
int xt = (x + 128
+ ((finesine[(y*128 + timebase*5 + 900) & FINEMASK]*2)>>FRACBITS)
+ ((finesine[(x*256 + timebase*4 + 300) & FINEMASK]*2)>>FRACBITS)) & xmask;
int yt = (y + 128
+ ((finesine[(y*128 + timebase*3 + 700) & FINEMASK]*2)>>FRACBITS)
+ ((finesine[(x*256 + timebase*4 + 1200) & FINEMASK]*2)>>FRACBITS)) & ymask;
const BYTE *source = otherpix + (xt << ybits) + yt;
BYTE *dest = Pixels + (x << ybits) + y;
*dest = *source;
}
}
}

View file

@ -77,7 +77,7 @@ teleport,70,1
teleport_nofog,71,1,2
teleport_newmap,74,2
teleport_endgame,75,0
thrustthing,72,2,3
thrustthing,72,2,4
damagething,73,1
thing_activate,130,1
thing_deactivate,131,1
@ -168,4 +168,13 @@ floorandceiling_lowerraise,251,3
ceiling_raisetonearest,252,2
ceiling_lowertolowest,253,2
ceiling_lowertofloor,254,2
ceiling_crushraiseandstaysila,255,4
ceiling_crushraiseandstaysila,255,4
door_animated,14,3
clearforcefield,34,1
teleport_zombiechanger,39,2
acs_executewithresult,84,1,4
plat_upnearestwaitdownstay,172,3
noisealert,173,2
thing_raise,17,1
startconversation,18,1,2
acs_lockedexecutedoor,85,5

View file

@ -4334,6 +4334,62 @@
>
</File>
</Filter>
<Filter
Name="Textures"
>
<File
RelativePath=".\src\textures\automaptexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\buildtexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\canvastexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\flattexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\imgztexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\jpegtexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\multipatchtexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\patchtexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\pngtexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\rawpagetexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\texture.cpp"
>
</File>
<File
RelativePath=".\src\textures\tgatexture.cpp"
>
</File>
<File
RelativePath=".\src\textures\warptexture.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="A Header Files"