/* ** 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" #include "st_start.h" static TArray BuildTileFiles; //========================================================================== // // A texture defined in a Build TILESxxx.ART file // //========================================================================== class FBuildTexture : public FTexture { public: FBuildTexture (int tilenum, const BYTE *pixels, int width, int height, int left, int top); ~FBuildTexture (); const BYTE *GetColumn (unsigned int column, const Span **spans_out); const BYTE *GetPixels (); void Unload (); protected: const BYTE *Pixels; Span **Spans; }; //========================================================================== // // // //========================================================================== 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 (); mysnprintf (Name, countof(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; } //=========================================================================== // // AddTiles // // Adds all the tiles in an artfile to the texture manager. // //=========================================================================== 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; FTextureID 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--; } StartScreen->Progress(); 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); } } } //=========================================================================== // // CountTiles // // Returns the number of tiles provided by an artfile // //=========================================================================== static int CountTiles (void *tiles) { int version = LittleLong(*(DWORD *)tiles); if (version != 1) { return 0; } int tilestart = LittleLong(((DWORD *)tiles)[2]); int tileend = LittleLong(((DWORD *)tiles)[3]); return tileend >= tilestart ? tileend - tilestart + 1 : 0; } //=========================================================================== // // R_CountBuildTiles // // Returns the number of tiles found. Also loads all the data for // R_InitBuildTiles() to process later. // //=========================================================================== int R_CountBuildTiles () { int numartfiles = 0; char artfile[] = "tilesXXX.art"; int lumpnum; int numtiles; int totaltiles = 0; 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 || (numtiles = CountTiles(art)) == 0) { delete[] art; } else { BuildTileFiles.Push (art); totaltiles += numtiles; } 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 ((numtiles = CountTiles(art)) == 0) { delete[] art; } else { BuildTileFiles.Push (art); totaltiles += numtiles; } } return totaltiles; } //=========================================================================== // // R_InitBuildTiles // // [RH] Support Build tiles! // //=========================================================================== void R_InitBuildTiles () { for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i) { AddTiles (BuildTileFiles[i]); } } //=========================================================================== // // R_DeinitBuildTiles // //=========================================================================== void R_DeinitBuildTiles () { for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i) { delete[] BuildTileFiles[i]; } BuildTileFiles.Clear(); }