mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-27 14:22:13 +00:00
921bc763fb
- moved testcolor and test fades into SWRenderer files. These CCMDs work by hacking the default colormap and were never implemented for hardware rendering because they require many checks throughout the code.
855 lines
24 KiB
C++
855 lines
24 KiB
C++
|
|
//**************************************************************************
|
|
//**
|
|
//** TEMPLATE.C
|
|
//**
|
|
//**************************************************************************
|
|
|
|
// HEADER FILES ------------------------------------------------------------
|
|
|
|
#include "p_local.h"
|
|
#include "m_swap.h"
|
|
#include "w_wad.h"
|
|
#include "templates.h"
|
|
#include "r_sky.h"
|
|
#include "r_defs.h"
|
|
#include "p_setup.h"
|
|
#include "g_level.h"
|
|
#include "r_data/colormaps.h"
|
|
#include "gi.h"
|
|
#include "p_spec.h"
|
|
|
|
#if 0
|
|
// MACROS ------------------------------------------------------------------
|
|
|
|
//#define SHADE2LIGHT(s) (160-2*(s))
|
|
#define SHADE2LIGHT(s) (255-2*s)
|
|
|
|
// TYPES -------------------------------------------------------------------
|
|
|
|
//ceilingstat/floorstat:
|
|
// bit 0: 1 = parallaxing, 0 = not "P"
|
|
// bit 1: 1 = groudraw, 0 = not
|
|
// bit 2: 1 = swap x&y, 0 = not "F"
|
|
// bit 3: 1 = double smooshiness "E"
|
|
// bit 4: 1 = x-flip "F"
|
|
// bit 5: 1 = y-flip "F"
|
|
// bit 6: 1 = Align texture to first wall of sector "R"
|
|
// bits 7-8: "T"
|
|
// 00 = normal floors
|
|
// 01 = masked floors
|
|
// 10 = transluscent masked floors
|
|
// 11 = reverse transluscent masked floors
|
|
// bits 9-15: reserved
|
|
|
|
//40 bytes
|
|
struct sectortype
|
|
{
|
|
int16_t wallptr, wallnum;
|
|
int32_t ceilingZ, floorZ;
|
|
int16_t ceilingstat, floorstat;
|
|
int16_t ceilingpicnum, ceilingheinum;
|
|
int8_t ceilingshade;
|
|
uint8_t ceilingpal, ceilingxpanning, ceilingypanning;
|
|
int16_t floorpicnum, floorheinum;
|
|
int8_t floorshade;
|
|
uint8_t floorpal, floorxpanning, floorypanning;
|
|
uint8_t visibility, filler;
|
|
int16_t lotag, hitag, extra;
|
|
};
|
|
|
|
//cstat:
|
|
// bit 0: 1 = Blocking wall (use with clipmove, getzrange) "B"
|
|
// bit 1: 1 = bottoms of invisible walls swapped, 0 = not "2"
|
|
// bit 2: 1 = align picture on bottom (for doors), 0 = top "O"
|
|
// bit 3: 1 = x-flipped, 0 = normal "F"
|
|
// bit 4: 1 = masking wall, 0 = not "M"
|
|
// bit 5: 1 = 1-way wall, 0 = not "1"
|
|
// bit 6: 1 = Blocking wall (use with hitscan / cliptype 1) "H"
|
|
// bit 7: 1 = Transluscence, 0 = not "T"
|
|
// bit 8: 1 = y-flipped, 0 = normal "F"
|
|
// bit 9: 1 = Transluscence reversing, 0 = normal "T"
|
|
// bits 10-15: reserved
|
|
|
|
//32 bytes
|
|
struct walltype
|
|
{
|
|
int32_t x, y;
|
|
int16_t point2, nextwall, nextsector, cstat;
|
|
int16_t picnum, overpicnum;
|
|
int8_t shade;
|
|
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
|
|
int16_t lotag, hitag, extra;
|
|
};
|
|
|
|
//cstat:
|
|
// bit 0: 1 = Blocking sprite (use with clipmove, getzrange) "B"
|
|
// bit 1: 1 = transluscence, 0 = normal "T"
|
|
// bit 2: 1 = x-flipped, 0 = normal "F"
|
|
// bit 3: 1 = y-flipped, 0 = normal "F"
|
|
// bits 5-4: 00 = FACE sprite (default) "R"
|
|
// 01 = WALL sprite (like masked walls)
|
|
// 10 = FLOOR sprite (parallel to ceilings&floors)
|
|
// bit 6: 1 = 1-sided sprite, 0 = normal "1"
|
|
// bit 7: 1 = Real centered centering, 0 = foot center "C"
|
|
// bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1) "H"
|
|
// bit 9: 1 = Transluscence reversing, 0 = normal "T"
|
|
// bits 10-14: reserved
|
|
// bit 15: 1 = Invisible sprite, 0 = not invisible
|
|
|
|
//44 bytes
|
|
struct spritetype
|
|
{
|
|
int32_t x, y, z;
|
|
int16_t cstat, picnum;
|
|
int8_t shade;
|
|
uint8_t pal, clipdist, filler;
|
|
uint8_t xrepeat, yrepeat;
|
|
int8_t xoffset, yoffset;
|
|
int16_t sectnum, statnum;
|
|
int16_t ang, owner, xvel, yvel, zvel;
|
|
int16_t lotag, hitag, extra;
|
|
};
|
|
|
|
// I used to have all the Xobjects mapped out. Not anymore.
|
|
// (Thanks for the great firmware, Seagate!)
|
|
struct Xsprite
|
|
{
|
|
uint8_t NotReallyPadding[16];
|
|
uint16_t Data1;
|
|
uint16_t Data2;
|
|
uint16_t Data3;
|
|
uint16_t ThisIsntPaddingEither;
|
|
uint32_t NorThis:2;
|
|
uint32_t Data4:16;
|
|
uint32_t WhatIsThisIDontEven:14;
|
|
uint8_t ThisNeedsToBe56Bytes[28];
|
|
};
|
|
|
|
struct SlopeWork
|
|
{
|
|
walltype *wal;
|
|
walltype *wal2;
|
|
long dx, dy, i, x[3], y[3], z[3];
|
|
long heinum;
|
|
};
|
|
|
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
|
|
|
void P_AdjustLine (line_t *line);
|
|
|
|
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
|
|
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
|
|
|
static bool P_LoadBloodMap (uint8_t *data, size_t len, FMapThing **sprites, int *numsprites);
|
|
static void LoadSectors (sectortype *bsectors, int count);
|
|
static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors);
|
|
static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, sectortype *bsectors, FMapThing *mapthings);
|
|
static vertex_t *FindVertex (int32_t x, int32_t y);
|
|
static void CreateStartSpot (int32_t *pos, FMapThing *start);
|
|
static void CalcPlane (SlopeWork &slope, secplane_t &plane);
|
|
static void Decrypt (void *to, const void *from, int len, int key);
|
|
|
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
|
|
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
|
|
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
|
|
|
// CODE --------------------------------------------------------------------
|
|
|
|
bool P_IsBuildMap(MapData *map)
|
|
{
|
|
uint32_t len = map->Size(ML_LABEL);
|
|
if (len < 4)
|
|
{
|
|
return false;
|
|
}
|
|
uint8_t *data = new uint8_t[len];
|
|
|
|
map->Seek(ML_LABEL);
|
|
map->Read(ML_LABEL, data);
|
|
|
|
// Check for a Blood map.
|
|
if (*(uint32_t *)data == MAKE_ID('B','L','M','\x1a'))
|
|
{
|
|
delete[] data;
|
|
return true;
|
|
}
|
|
|
|
const int numsec = LittleShort(*(uint16_t *)(data + 20));
|
|
int numwalls;
|
|
|
|
if (len < 26 + numsec*sizeof(sectortype) ||
|
|
(numwalls = LittleShort(*(uint16_t *)(data + 22 + numsec*sizeof(sectortype))),
|
|
len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) ||
|
|
LittleLong(*(uint32_t *)data) != 7 ||
|
|
LittleShort(*(uint16_t *)(data + 16)) >= 2048)
|
|
{ // Can't possibly be a version 7 BUILD map
|
|
delete[] data;
|
|
return false;
|
|
}
|
|
delete[] data;
|
|
return true;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_LoadBuildMap
|
|
//
|
|
//==========================================================================
|
|
|
|
bool P_LoadBuildMap (uint8_t *data, size_t len, FMapThing **sprites, int *numspr)
|
|
{
|
|
if (len < 26)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check for a Blood map.
|
|
if (*(uint32_t *)data == MAKE_ID('B','L','M','\x1a'))
|
|
{
|
|
return P_LoadBloodMap (data, len, sprites, numspr);
|
|
}
|
|
|
|
const int numsec = LittleShort(*(uint16_t *)(data + 20));
|
|
int numwalls;
|
|
int numsprites;
|
|
|
|
if (len < 26 + numsec*sizeof(sectortype) ||
|
|
(numwalls = LittleShort(*(uint16_t *)(data + 22 + numsec*sizeof(sectortype))),
|
|
len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) ||
|
|
LittleLong(*(uint32_t *)data) != 7 ||
|
|
LittleShort(*(uint16_t *)(data + 16)) >= 2048)
|
|
{ // Can't possibly be a version 7 BUILD map
|
|
return false;
|
|
}
|
|
|
|
LoadSectors ((sectortype *)(data + 22), numsec);
|
|
LoadWalls ((walltype *)(data + 24 + numsec*sizeof(sectortype)), numwalls,
|
|
(sectortype *)(data + 22));
|
|
|
|
numsprites = *(uint16_t *)(data + 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype));
|
|
*sprites = new FMapThing[numsprites + 1];
|
|
CreateStartSpot ((int32_t *)(data + 4), *sprites);
|
|
*numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)),
|
|
NULL, numsprites, (sectortype *)(data + 22), *sprites + 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_LoadBloodMap
|
|
//
|
|
//==========================================================================
|
|
|
|
static bool P_LoadBloodMap (uint8_t *data, size_t len, FMapThing **mapthings, int *numspr)
|
|
{
|
|
uint8_t infoBlock[37];
|
|
int mapver = data[5];
|
|
uint32_t matt;
|
|
int numRevisions, numWalls, numsprites, skyLen, visibility, parallaxType;
|
|
int i;
|
|
int k;
|
|
|
|
if (mapver != 6 && mapver != 7)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
matt = *(uint32_t *)(data + 28);
|
|
if (matt != 0 &&
|
|
matt != MAKE_ID('M','a','t','t') &&
|
|
matt != MAKE_ID('t','t','a','M'))
|
|
{
|
|
Decrypt (infoBlock, data + 6, 37, 0x7474614d);
|
|
}
|
|
else
|
|
{
|
|
memcpy (infoBlock, data + 6, 37);
|
|
}
|
|
skyLen = 2 << LittleShort(*(uint16_t *)(infoBlock + 16));
|
|
visibility = LittleLong(*(uint32_t *)(infoBlock + 18));
|
|
parallaxType = infoBlock[26];
|
|
numRevisions = LittleLong(*(uint32_t *)(infoBlock + 27));
|
|
int numsectors = LittleShort(*(uint16_t *)(infoBlock + 31));
|
|
numWalls = LittleShort(*(uint16_t *)(infoBlock + 33));
|
|
numsprites = LittleShort(*(uint16_t *)(infoBlock + 35));
|
|
Printf("Visibility: %d\n", visibility);
|
|
|
|
if (mapver == 7)
|
|
{
|
|
// Version 7 has some extra stuff after the info block. This
|
|
// includes a copyright, and I have no idea what the rest of
|
|
// it is.
|
|
data += 171;
|
|
}
|
|
else
|
|
{
|
|
data += 43;
|
|
}
|
|
|
|
// Skip the sky info.
|
|
data += skyLen;
|
|
|
|
sectortype *bsec = new sectortype[numsectors];
|
|
walltype *bwal = new walltype[numWalls];
|
|
spritetype *bspr = new spritetype[numsprites];
|
|
Xsprite *xspr = new Xsprite[numsprites];
|
|
|
|
// Read sectors
|
|
k = numRevisions * sizeof(sectortype);
|
|
for (i = 0; i < numsectors; ++i)
|
|
{
|
|
if (mapver == 7)
|
|
{
|
|
Decrypt (&bsec[i], data, sizeof(sectortype), k);
|
|
}
|
|
else
|
|
{
|
|
memcpy (&bsec[i], data, sizeof(sectortype));
|
|
}
|
|
data += sizeof(sectortype);
|
|
if (bsec[i].extra > 0) // skip Xsector
|
|
{
|
|
data += 60;
|
|
}
|
|
}
|
|
|
|
// Read walls
|
|
k |= 0x7474614d;
|
|
for (i = 0; i < numWalls; ++i)
|
|
{
|
|
if (mapver == 7)
|
|
{
|
|
Decrypt (&bwal[i], data, sizeof(walltype), k);
|
|
}
|
|
else
|
|
{
|
|
memcpy (&bwal[i], data, sizeof(walltype));
|
|
}
|
|
data += sizeof(walltype);
|
|
if (bwal[i].extra > 0) // skip Xwall
|
|
{
|
|
data += 24;
|
|
}
|
|
}
|
|
|
|
// Read sprites
|
|
k = (numRevisions * sizeof(spritetype)) | 0x7474614d;
|
|
for (i = 0; i < numsprites; ++i)
|
|
{
|
|
if (mapver == 7)
|
|
{
|
|
Decrypt (&bspr[i], data, sizeof(spritetype), k);
|
|
}
|
|
else
|
|
{
|
|
memcpy (&bspr[i], data, sizeof(spritetype));
|
|
}
|
|
data += sizeof(spritetype);
|
|
if (bspr[i].extra > 0) // copy Xsprite
|
|
{
|
|
assert(sizeof(Xsprite) == 56);
|
|
memcpy(&xspr[i], data, sizeof(Xsprite));
|
|
data += sizeof(Xsprite);
|
|
}
|
|
else
|
|
{
|
|
memset(&xspr[i], 0, sizeof(Xsprite));
|
|
}
|
|
}
|
|
|
|
// Now convert to Doom format, since we've extracted all the standard
|
|
// BUILD info from the map we need. (Sprites are ignored.)
|
|
LoadSectors (bsec, numsectors);
|
|
LoadWalls (bwal, numWalls, bsec);
|
|
*mapthings = new FMapThing[numsprites];
|
|
*numspr = LoadSprites (bspr, xspr, numsprites, bsec, *mapthings);
|
|
|
|
delete[] bsec;
|
|
delete[] bwal;
|
|
delete[] bspr;
|
|
delete[] xspr;
|
|
|
|
return true;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// LoadSectors
|
|
//
|
|
//==========================================================================
|
|
|
|
static void LoadSectors (sectortype *bsec, int count)
|
|
{
|
|
sector_t *sec;
|
|
char tnam[9];
|
|
|
|
level.sectors.Alloc(count);
|
|
sec = &level.sectors[0];
|
|
memset (sec, 0, sizeof(sector_t)*count);
|
|
|
|
sec->e = new extsector_t[count];
|
|
|
|
for (int i = 0; i < count; ++i, ++bsec, ++sec)
|
|
{
|
|
bsec->wallptr = uint16_t(bsec->wallptr);
|
|
bsec->wallnum = uint16_t(bsec->wallnum);
|
|
bsec->ceilingstat = uint16_t(bsec->ceilingstat);
|
|
bsec->floorstat = uint16_t(bsec->floorstat);
|
|
|
|
sec->e = &sec->e[i];
|
|
double floorheight = -LittleLong(bsec->floorZ) / 256.;
|
|
sec->SetPlaneTexZ(sector_t::floor, floorheight);
|
|
sec->floorplane.SetAtHeight(floorheight, sector_t::floor);
|
|
mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(bsec->floorpicnum));
|
|
sec->SetTexture(sector_t::floor, TexMan.GetTexture (tnam, FTexture::TEX_Build));
|
|
sec->SetXScale(sector_t::floor, (bsec->floorstat & 8) ? 2. : 1.);
|
|
sec->SetYScale(sector_t::floor, (bsec->floorstat & 8) ? 2. : 1.);
|
|
sec->SetXOffset(sector_t::floor, bsec->floorxpanning + 32.);
|
|
sec->SetYOffset(sector_t::floor, bsec->floorypanning + 0.);
|
|
sec->SetPlaneLight(sector_t::floor, SHADE2LIGHT (bsec->floorshade));
|
|
sec->ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
|
|
|
|
double ceilingheight = -LittleLong(bsec->ceilingZ) / 256.;
|
|
sec->SetPlaneTexZ(sector_t::ceiling, ceilingheight);
|
|
sec->ceilingplane.SetAtHeight(ceilingheight, sector_t::ceiling);
|
|
mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(bsec->ceilingpicnum));
|
|
sec->SetTexture(sector_t::ceiling, TexMan.GetTexture (tnam, FTexture::TEX_Build));
|
|
if (bsec->ceilingstat & 1)
|
|
{
|
|
sky1texture = sky2texture = sec->GetTexture(sector_t::ceiling);
|
|
sec->SetTexture(sector_t::ceiling, skyflatnum);
|
|
}
|
|
sec->SetXScale(sector_t::ceiling, (bsec->ceilingstat & 8) ? 2. : 1.);
|
|
sec->SetYScale(sector_t::ceiling, (bsec->ceilingstat & 8) ? 2. : 1.);
|
|
sec->SetXOffset(sector_t::ceiling, bsec->ceilingxpanning + 32.);
|
|
sec->SetYOffset(sector_t::ceiling, bsec->ceilingypanning + 0.);
|
|
sec->SetPlaneLight(sector_t::ceiling, SHADE2LIGHT (bsec->ceilingshade));
|
|
sec->ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
|
|
|
|
sec->lightlevel = (sec->GetPlaneLight(sector_t::floor) + sec->GetPlaneLight(sector_t::ceiling)) / 2;
|
|
|
|
sec->seqType = -1;
|
|
sec->SeqName = NAME_None;
|
|
sec->nextsec = -1;
|
|
sec->prevsec = -1;
|
|
sec->gravity = 1.f;
|
|
sec->friction = ORIG_FRICTION;
|
|
sec->movefactor = ORIG_FRICTION_FACTOR;
|
|
sec->ColorMap = map;
|
|
sec->ZoneNumber = 0xFFFF;
|
|
sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1;
|
|
|
|
if (bsec->floorstat & 4)
|
|
{
|
|
sec->SetAngle(sector_t::floor, DAngle(90.));
|
|
sec->SetXScale(sector_t::floor, -sec->GetXScale(sector_t::floor));
|
|
}
|
|
if (bsec->floorstat & 16)
|
|
{
|
|
sec->SetXScale(sector_t::floor, -sec->GetXScale(sector_t::floor));
|
|
}
|
|
if (bsec->floorstat & 32)
|
|
{
|
|
sec->SetYScale(sector_t::floor, -sec->GetYScale(sector_t::floor));
|
|
}
|
|
|
|
if (bsec->ceilingstat & 4)
|
|
{
|
|
sec->SetAngle(sector_t::ceiling, DAngle(90.));
|
|
sec->SetYScale(sector_t::ceiling, -sec->GetYScale(sector_t::ceiling));
|
|
}
|
|
if (bsec->ceilingstat & 16)
|
|
{
|
|
sec->SetXScale(sector_t::ceiling, -sec->GetXScale(sector_t::ceiling));
|
|
}
|
|
if (bsec->ceilingstat & 32)
|
|
{
|
|
sec->SetYScale(sector_t::ceiling, -sec->GetYScale(sector_t::ceiling));
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// LoadWalls
|
|
//
|
|
//==========================================================================
|
|
|
|
static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec)
|
|
{
|
|
int i, j;
|
|
|
|
// Setting numvertexes to the same as numwalls is overly conservative,
|
|
// but the extra vertices will be removed during the BSP building pass.
|
|
numsides = numvertexes = numwalls;
|
|
int numlines = 0;
|
|
|
|
sides = new side_t[numsides];
|
|
memset (sides, 0, numsides*sizeof(side_t));
|
|
|
|
vertexes = new vertex_t[numvertexes];
|
|
numvertexes = 0;
|
|
|
|
// First mark each sidedef with the sector it belongs to
|
|
for (unsigned i = 0; i < level.sectors.Size(); i++)
|
|
{
|
|
if (bsec[i].wallptr >= 0)
|
|
{
|
|
for (j = 0; j < bsec[i].wallnum; ++j)
|
|
{
|
|
sides[j + bsec[i].wallptr].sector = &level.sectors[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now copy wall properties to their matching sidedefs
|
|
for (i = 0; i < numwalls; ++i)
|
|
{
|
|
char tnam[9];
|
|
FTextureID overpic, pic;
|
|
|
|
mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(walls[i].picnum));
|
|
pic = TexMan.GetTexture (tnam, FTexture::TEX_Build);
|
|
mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(walls[i].overpicnum));
|
|
overpic = TexMan.GetTexture (tnam, FTexture::TEX_Build);
|
|
|
|
walls[i].x = LittleLong(walls[i].x);
|
|
walls[i].y = LittleLong(walls[i].y);
|
|
walls[i].point2 = LittleShort(walls[i].point2);
|
|
walls[i].cstat = LittleShort(walls[i].cstat);
|
|
walls[i].nextwall = LittleShort(walls[i].nextwall);
|
|
walls[i].nextsector = LittleShort(walls[i].nextsector);
|
|
|
|
sides[i].SetTextureXOffset((double)walls[i].xpanning);
|
|
sides[i].SetTextureYOffset((double)walls[i].ypanning);
|
|
|
|
sides[i].SetTexture(side_t::top, pic);
|
|
sides[i].SetTexture(side_t::bottom, pic);
|
|
if (walls[i].nextsector < 0 || (walls[i].cstat & 32))
|
|
{
|
|
sides[i].SetTexture(side_t::mid, pic);
|
|
}
|
|
else if (walls[i].cstat & 16)
|
|
{
|
|
sides[i].SetTexture(side_t::mid, overpic);
|
|
}
|
|
else
|
|
{
|
|
sides[i].SetTexture(side_t::mid, FNullTextureID());
|
|
}
|
|
|
|
sides[i].TexelLength = walls[i].xrepeat * 8;
|
|
sides[i].SetTextureYScale(walls[i].yrepeat / 8.);
|
|
sides[i].SetTextureXScale(1.);
|
|
sides[i].SetLight(SHADE2LIGHT(walls[i].shade));
|
|
sides[i].Flags = WALLF_ABSLIGHTING;
|
|
sides[i].RightSide = walls[i].point2;
|
|
sides[walls[i].point2].LeftSide = i;
|
|
|
|
if (walls[i].nextwall >= 0 && walls[i].nextwall <= i)
|
|
{
|
|
sides[i].linedef = sides[walls[i].nextwall].linedef;
|
|
}
|
|
else
|
|
{
|
|
sides[i].linedef = (line_t*)(intptr_t)(numlines++);
|
|
}
|
|
}
|
|
|
|
// Set line properties that Doom doesn't store per-sidedef
|
|
level.lines.Alloc(numlines);
|
|
memset (&level.lines[0], 0, numlines*sizeof(line_t));
|
|
|
|
for (i = 0, j = -1; i < numwalls; ++i)
|
|
{
|
|
if (walls[i].nextwall >= 0 && walls[i].nextwall <= i)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
j = int(intptr_t(sides[i].linedef));
|
|
auto &lines = level.lines;
|
|
lines[j].sidedef[0] = (side_t*)(intptr_t)i;
|
|
lines[j].sidedef[1] = (side_t*)(intptr_t)walls[i].nextwall;
|
|
lines[j].v1 = FindVertex (walls[i].x, walls[i].y);
|
|
lines[j].v2 = FindVertex (walls[walls[i].point2].x, walls[walls[i].point2].y);
|
|
lines[j].frontsector = sides[i].sector;
|
|
lines[j].flags |= ML_WRAP_MIDTEX;
|
|
if (walls[i].nextsector >= 0)
|
|
{
|
|
lines[j].backsector = &level.sectors[walls[i].nextsector];
|
|
lines[j].flags |= ML_TWOSIDED;
|
|
}
|
|
else
|
|
{
|
|
lines[j].backsector = NULL;
|
|
}
|
|
P_AdjustLine (&lines[j]);
|
|
if (walls[i].cstat & 128)
|
|
{
|
|
if (walls[i].cstat & 512)
|
|
{
|
|
lines[j].alpha = 1/3.;
|
|
}
|
|
else
|
|
{
|
|
lines[j].alpha = 2/3.;
|
|
}
|
|
}
|
|
if (walls[i].cstat & 1)
|
|
{
|
|
lines[j].flags |= ML_BLOCKING;
|
|
}
|
|
if (walls[i].nextwall < 0)
|
|
{
|
|
if (walls[i].cstat & 4)
|
|
{
|
|
lines[j].flags |= ML_DONTPEGBOTTOM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (walls[i].cstat & 4)
|
|
{
|
|
lines[j].flags |= ML_DONTPEGTOP;
|
|
}
|
|
else
|
|
{
|
|
lines[j].flags |= ML_DONTPEGBOTTOM;
|
|
}
|
|
}
|
|
if (walls[i].cstat & 64)
|
|
{
|
|
lines[j].flags |= ML_BLOCKEVERYTHING;
|
|
}
|
|
}
|
|
|
|
// Finish setting sector properties that depend on walls
|
|
for (auto &sec : level.sectors)
|
|
{
|
|
SlopeWork slope;
|
|
|
|
slope.wal = &walls[bsec->wallptr];
|
|
slope.wal2 = &walls[slope.wal->point2];
|
|
slope.dx = slope.wal2->x - slope.wal->x;
|
|
slope.dy = slope.wal2->y - slope.wal->y;
|
|
slope.i = long (g_sqrt ((double)(slope.dx*slope.dx+slope.dy*slope.dy))) << 5;
|
|
if (slope.i == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((bsec->floorstat & 2) && (bsec->floorheinum != 0))
|
|
{ // floor is sloped
|
|
slope.heinum = -LittleShort(bsec->floorheinum);
|
|
slope.z[0] = slope.z[1] = slope.z[2] = -bsec->floorZ;
|
|
CalcPlane (slope, sec.floorplane);
|
|
}
|
|
if ((bsec->ceilingstat & 2) && (bsec->ceilingheinum != 0))
|
|
{ // ceiling is sloped
|
|
slope.heinum = -LittleShort(bsec->ceilingheinum);
|
|
slope.z[0] = slope.z[1] = slope.z[2] = -bsec->ceilingZ;
|
|
CalcPlane (slope, sec.ceilingplane);
|
|
}
|
|
int linenum = sides[bsec->wallptr].linedef->Index();
|
|
int sidenum = int(intptr_t(level.lines[linenum].sidedef[1] - sides));
|
|
if (bsec->floorstat & 64)
|
|
{ // floor is aligned to first wall
|
|
P_AlignFlat (linenum, sidenum == bsec->wallptr, 0);
|
|
}
|
|
if (bsec->ceilingstat & 64)
|
|
{ // ceiling is aligned to first wall
|
|
P_AlignFlat (linenum, sidenum == bsec->wallptr, 0);
|
|
}
|
|
}
|
|
for (i = 0; i < numlines; i++)
|
|
{
|
|
intptr_t front = intptr_t(level.lines[i].sidedef[0]-sides);
|
|
intptr_t back = intptr_t(level.lines[i].sidedef[1]-sides);
|
|
lines[i].sidedef[0] = front >= 0 ? &sides[front] : NULL;
|
|
lines[i].sidedef[1] = back >= 0 ? &sides[back] : NULL;
|
|
}
|
|
for (i = 0; i < numsides; i++)
|
|
{
|
|
assert(sides[i].sector != NULL);
|
|
sides[i].linedef = &lines[intptr_t(sides[i].linedef)];
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// LoadSprites
|
|
//
|
|
//==========================================================================
|
|
|
|
static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites,
|
|
sectortype *bsectors, FMapThing *mapthings)
|
|
{
|
|
int count = 0;
|
|
|
|
memset(mapthings, 0, sizeof(*mapthings)*numsprites);
|
|
|
|
for (int i = 0; i < numsprites; ++i)
|
|
{
|
|
mapthings[count].thingid = 0;
|
|
mapthings[count].pos.X = sprites[i].x / 16.;
|
|
mapthings[count].pos.Y = -sprites[i].y / 16.;
|
|
mapthings[count].pos.Z = (bsectors[sprites[i].sectnum].floorZ - sprites[i].z) / 256.;
|
|
mapthings[count].angle = (((2048-sprites[i].ang) & 2047) * 360) >> 11;
|
|
mapthings[count].ClassFilter = 0xffff;
|
|
mapthings[count].SkillFilter = 0xffff;
|
|
mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH;
|
|
mapthings[count].special = 0;
|
|
mapthings[count].Gravity = 1.;
|
|
mapthings[count].RenderStyle = STYLE_Count;
|
|
mapthings[count].Alpha = -1;
|
|
mapthings[count].health = -1;
|
|
mapthings[count].FloatbobPhase = -1;
|
|
|
|
if (xsprites != NULL && sprites[i].lotag == 710)
|
|
{ // Blood ambient sound
|
|
mapthings[count].args[0] = xsprites[i].Data3;
|
|
// I am totally guessing about the volume level. 50 seems to be a pretty
|
|
// typical value for Blood's standard maps, so I assume it's 100-based.
|
|
mapthings[count].args[1] = xsprites[i].Data4;
|
|
mapthings[count].args[2] = xsprites[i].Data1;
|
|
mapthings[count].args[3] = xsprites[i].Data2;
|
|
mapthings[count].EdNum = 14065;
|
|
}
|
|
else if (xsprites != NULL && sprites[i].lotag == 1)
|
|
{ // Blood player start
|
|
if (xsprites[i].Data1 < 4)
|
|
mapthings[count].EdNum= 1 + xsprites[i].Data1;
|
|
else
|
|
mapthings[count].EdNum = 4001 + xsprites[i].Data1 - 4;
|
|
}
|
|
else if (xsprites != NULL && sprites[i].lotag == 2)
|
|
{ // Bloodbath start
|
|
mapthings[count].EdNum = 11;
|
|
}
|
|
else
|
|
{
|
|
if (sprites[i].cstat & 32768) continue;
|
|
if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue;
|
|
|
|
mapthings[count].EdNum = 9988;
|
|
mapthings[count].args[0] = sprites[i].picnum;
|
|
mapthings[count].args[2] = sprites[i].xrepeat;
|
|
mapthings[count].args[3] = sprites[i].yrepeat;
|
|
mapthings[count].args[4] = sprites[i].cstat;
|
|
}
|
|
mapthings[count].info = DoomEdMap.CheckKey(mapthings[count].EdNum);
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// FindVertex
|
|
//
|
|
//==========================================================================
|
|
|
|
vertex_t *FindVertex (int32_t xx, int32_t yy)
|
|
{
|
|
int i;
|
|
|
|
double x = xx / 64.;
|
|
double y = -yy / 64.;
|
|
|
|
for (i = 0; i < numvertexes; ++i)
|
|
{
|
|
if (vertexes[i].fX() == x && vertexes[i].fY() == y)
|
|
{
|
|
return &vertexes[i];
|
|
}
|
|
}
|
|
vertexes[i].set(x, y);
|
|
numvertexes++;
|
|
return &vertexes[i];
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// CreateStartSpot
|
|
//
|
|
//==========================================================================
|
|
|
|
static void CreateStartSpot (int32_t *pos, FMapThing *start)
|
|
{
|
|
short angle = LittleShort(*(uint16_t *)(&pos[3]));
|
|
FMapThing mt = { 0, };
|
|
|
|
mt.pos.X = LittleLong(pos[0]) / 16.;
|
|
mt.pos.Y = -LittleLong(pos[1]) / 16.;
|
|
mt.angle = short(Scale((2048-angle)&2047, 360, 2048));
|
|
mt.info = DoomEdMap.CheckKey(1);
|
|
mt.EdNum = 1;
|
|
mt.flags = 7|MTF_SINGLE|224;
|
|
|
|
*start = mt;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// CalcPlane
|
|
//
|
|
//==========================================================================
|
|
|
|
static void CalcPlane (SlopeWork &slope, secplane_t &plane)
|
|
{
|
|
DVector3 pt[3];
|
|
long j;
|
|
|
|
slope.x[0] = slope.wal->x; slope.y[0] = slope.wal->y;
|
|
slope.x[1] = slope.wal2->x; slope.y[1] = slope.wal2->y;
|
|
if (slope.dx == 0)
|
|
{
|
|
slope.x[2] = slope.x[0] + 64;
|
|
slope.y[2] = slope.y[0];
|
|
}
|
|
else
|
|
{
|
|
slope.x[2] = slope.x[0];
|
|
slope.y[2] = slope.y[0] + 64;
|
|
}
|
|
j = DMulScale3 (slope.dx, slope.y[2]-slope.wal->y, -slope.dy, slope.x[2]-slope.wal->x);
|
|
slope.z[2] += Scale (slope.heinum, j, slope.i);
|
|
|
|
pt[0] = DVector3(slope.dx, -slope.dy, 0);
|
|
pt[1] = DVector3(slope.x[2] - slope.x[0], slope.y[0] - slope.y[2], (slope.z[2] - slope.z[0]) / 16);
|
|
pt[2] = (pt[0] ^ pt[1]).Unit();
|
|
|
|
if ((pt[2][2] < 0 && plane.fC() > 0) || (pt[2][2] > 0 && plane.fC() < 0))
|
|
{
|
|
pt[2] = -pt[2];
|
|
}
|
|
|
|
double dist = -pt[2][0] * slope.x[0] * 16 + pt[2][1] * slope.y[0] * 16 - pt[2][2] * slope.z[0];
|
|
plane.set(pt[2][0], pt[2][1], pt[2][2], dist);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// Decrypt
|
|
//
|
|
// Note that this is different from the general RFF encryption.
|
|
//
|
|
//==========================================================================
|
|
|
|
static void Decrypt (void *to_, const void *from_, int len, int key)
|
|
{
|
|
uint8_t *to = (uint8_t *)to_;
|
|
const uint8_t *from = (const uint8_t *)from_;
|
|
|
|
for (int i = 0; i < len; ++i, ++key)
|
|
{
|
|
to[i] = from[i] ^ key;
|
|
}
|
|
}
|
|
|
|
#endif
|