- added a map preview to the user map browser.

This commit is contained in:
Christoph Oelckers 2021-12-26 19:58:52 +01:00
parent 6dfd975f88
commit 00a7be545d
7 changed files with 293 additions and 62 deletions

View file

@ -510,6 +510,170 @@ void loadMap(const char* filename, int flags, vec3_t* pos, int16_t* ang, int* cu
}
//==========================================================================
//
// 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;
}
}
//==========================================================================
//
// P_LoadBloodMap
//
// This was adapted from ZDoom's old Build map loader.
//
//==========================================================================
static void P_LoadBloodMapWalls(uint8_t* data, size_t len, TArray<walltype>& lwalls)
{
uint8_t infoBlock[37];
int mapver = data[5];
uint32_t matt;
int i;
int k;
if (mapver != 6 && mapver != 7)
{
return;
}
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);
}
int numRevisions = *(uint32_t*)(infoBlock + 27);
int numSectors = *(uint16_t*)(infoBlock + 31);
int numWalls = *(uint16_t*)(infoBlock + 33);
int numSprites = *(uint16_t*)(infoBlock + 35);
int skyLen = 2 << *(uint16_t*)(infoBlock + 16);
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;
lwalls.Reserve(numWalls);
// Read sectors
k = numRevisions * sizeof(sectortypedisk);
for (i = 0; i < numSectors; ++i)
{
sectortypedisk bsec;
if (mapver == 7)
{
Decrypt(&bsec, data, sizeof(sectortypedisk), k);
}
else
{
memcpy(&bsec, data, sizeof(sectortypedisk));
}
data += sizeof(sectortypedisk);
if (bsec.extra > 0) // skip Xsector
{
data += 60;
}
}
// Read walls
k |= 0x7474614d;
for (i = 0; i < numWalls; ++i)
{
walltypedisk load;
if (mapver == 7)
{
Decrypt(&load, data, sizeof(walltypedisk), k);
}
else
{
memcpy(&load, data, sizeof(walltypedisk));
}
// only copy what we need to draw the map preview.
auto pWall = &lwalls[i];
pWall->pos.X = LittleLong(load.x);
pWall->pos.Y = LittleLong(load.y);
pWall->point2 = LittleShort(load.point2);
pWall->nextwall = LittleShort(load.nextwall);
pWall->nextsector = LittleShort(load.nextsector);
data += sizeof(walltypedisk);
if (load.extra > 0) // skip Xwall
{
data += 24;
}
}
}
TArray<walltype> loadMapWalls(const char* filename)
{
TArray<walltype> lwalls;
FileReader fr = fileSystem.OpenFileReader(filename);
if (!fr.isOpen()) return lwalls;
if (isBlood())
{
auto data = fr.Read();
P_LoadBloodMapWalls(data.Data(), data.Size(), lwalls);
return lwalls;
}
int mapversion = fr.ReadInt32();
if (mapversion < 5 || mapversion > 9) return lwalls;
fr.Seek(16, FileReader::SeekCur);
// Get the basics out before loading the data so that we can set up the global storage.
unsigned numsectors = fr.ReadUInt16();
fr.Seek((mapversion == 5 ? sectorsize5 : mapversion == 6 ? sectorsize6 : sectorsize7) * numsectors, FileReader::SeekCur);
unsigned numwalls = fr.ReadUInt16();
lwalls.Resize(numwalls);
for (unsigned i = 0; i < lwalls.Size(); i++)
{
switch (mapversion)
{
case 5: ReadWallV5(fr, lwalls[i]); break;
case 6: ReadWallV6(fr, lwalls[i]); break;
default: ReadWallV7(fr, lwalls[i]); break;
}
}
return lwalls;
}
void qloadboard(const char* filename, char flags, vec3_t* dapos, int16_t* daang);

View file

@ -30,6 +30,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
#include "ns.h"
#include "tarray.h"
#include "tflags.h"
#include "intvec.h"
//=============================================================================
//
@ -700,5 +701,6 @@ void allocateMapArrays(int numwall, int numsector, int numsprites);
void validateSprite(spritetype& spr, int secno, int index);
void fixSectors();
void loadMap(const char *filename, int flags, vec3_t *pos, int16_t *ang, int *cursectnum, SpawnSpriteDef& sprites);
TArray<walltype> loadMapWalls(const char* filename);
void loadMapBackup(const char* filename);
void loadMapHack(const char* filename, const unsigned char*, SpawnSpriteDef& sprites);

View file

@ -47,6 +47,7 @@
#include "usermap.h"
#include "gamecontrol.h"
#include "mapinfo.h"
#include "v_draw.h"
static FUsermapDirectory root;
@ -139,6 +140,25 @@ void ReadUserMaps()
SortEntries(root);
}
void LoadMapPreview(FUsermapEntry* entry)
{
if (entry->wallsread) return;
entry->walls = loadMapWalls(entry->filename);
}
void UnloadMapPreviews(FUsermapDirectory* dir)
{
for (auto& entry : dir->entries)
{
if (entry.walls.Size() > 0) entry.wallsread = false;
entry.walls.Reset();
}
for (auto& sub : dir->subdirectories)
{
UnloadMapPreviews(&sub);
}
}
DEFINE_FIELD(FUsermapEntry, filename);
DEFINE_FIELD(FUsermapEntry, container);
DEFINE_FIELD(FUsermapEntry, displayname);
@ -185,17 +205,51 @@ DEFINE_ACTION_FUNCTION(FUsermapDirectory, GetDirectory)
ACTION_RETURN_POINTER(&self->subdirectories[num]);
}
DEFINE_ACTION_FUNCTION(FUsermapDirectory, DrawPreview)
DEFINE_ACTION_FUNCTION(_UserMapMenu, DrawPreview)
{
PARAM_SELF_STRUCT_PROLOGUE(FUsermapDirectory);
PARAM_UINT(num);
PARAM_PROLOGUE;
PARAM_POINTER(entry, FUsermapEntry);
PARAM_INT(left);
PARAM_INT(top);
PARAM_INT(width);
PARAM_INT(height);
if (num >= self->entries.Size()) return 0;
// todo
if (!entry) return 0;
LoadMapPreview(entry);
if (entry->walls.Size() == 0) return 0;
int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN;
for (auto& wal : entry->walls)
{
if (wal.pos.X < minx) minx = wal.pos.X;
if (wal.pos.X > maxx) maxx = wal.pos.X;
if (wal.pos.Y < miny) miny = wal.pos.Y;
if (wal.pos.Y > maxy) maxy = wal.pos.Y;
}
float scalex = float(width) / (maxx - minx);
float scaley = float(height) / (maxy - miny);
int centerx = (minx + maxx) >> 1;
int centery = (miny + maxy) >> 1;
int dcenterx = left + (width >> 1);
int dcentery = top + (height >> 1);
float scale = min(scalex, scaley);
float drawleft = dcenterx - (centerx - minx) * scale;
float drawtop = dcentery - (centery - miny) * scale;
for (auto& wal : entry->walls)
{
if (wal.nextwall < 0) continue;
auto point2 = &entry->walls[wal.point2];
twod->AddLine(dcenterx + (wal.pos.X - centerx) * scale, dcentery + (wal.pos.Y - centery) * scale,
dcenterx + (point2->pos.X - centerx) * scale, dcentery + (point2->pos.Y - centery) * scale,
-1, -1, INT_MAX, INT_MAX, 0xff808080);
}
for (auto& wal : entry->walls)
{
if (wal.nextwall >= 0) continue;
auto point2 = &entry->walls[wal.point2];
twod->AddLine(dcenterx + (wal.pos.X - centerx) * scale, dcentery + (wal.pos.Y - centery) * scale,
dcenterx + (point2->pos.X - centerx) * scale, dcentery + (point2->pos.Y - centery) * scale,
-1, -1, INT_MAX, INT_MAX, 0xffffffff);
}
return 0;
}
@ -213,5 +267,6 @@ DEFINE_ACTION_FUNCTION(_UsermapMenu, StartMap)
DoStartMap(entry->filename);
M_ClearMenus();
UnloadMapPreviews(&root);
return 0;
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "maptypes.h"
struct FUsermapEntry
{
@ -7,7 +8,9 @@ struct FUsermapEntry
FString container;
FString filename;
FString info;
int size;
int size = 0;
bool wallsread = false;
TArray<walltype> walls; // for rendering a preview of the map
};
struct FUsermapDirectory

View file

@ -119,58 +119,6 @@ const int nXSpriteSize = 56;
const int nXWallSize = 24;
#pragma pack(push, 1)
// This is the on-disk format. Only Blood still needs this for its retarded encryption that has to read this in as a block so that it can be decoded.
// Keep it local so that the engine's sprite type is no longer limited by file format restrictions.
struct spritetypedisk
{
int32_t x, y, z;
uint16_t cstat;
int16_t picnum;
int8_t shade;
uint8_t pal, clipdist, detail;
uint8_t xrepeat, yrepeat;
int8_t xoffset, yoffset;
int16_t sectnum, statnum;
int16_t ang, owner;
int16_t index, yvel, inittype;
int16_t type;
int16_t hitag;
int16_t extra;
};
struct sectortypedisk
{
int16_t wallptr, wallnum;
int32_t ceilingz, floorz;
uint16_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, fogpal;
int16_t type;
int16_t hitag;
int16_t extra;
};
struct walltypedisk
{
int32_t x, y;
int16_t point2, nextwall, nextsector;
uint16_t cstat;
int16_t picnum, overpicnum;
int8_t shade;
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
int16_t type;
int16_t hitag;
int16_t extra;
};
#pragma pack(pop)
void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, sectortype** ppSector, unsigned int* pCRC, BloodSpawnSpriteDef& sprites)
{
int16_t tpskyoff[256];

View file

@ -2,8 +2,62 @@
#pragma once
#include "ns.h"
#pragma pack(push, 1)
// This is the on-disk format. Only Blood still needs this for its retarded encryption that has to read this in as a block so that it can be decoded.
// Keep it local so that the engine's sprite type is no longer limited by file format restrictions.
struct spritetypedisk
{
int32_t x, y, z;
uint16_t cstat;
int16_t picnum;
int8_t shade;
uint8_t pal, clipdist, detail;
uint8_t xrepeat, yrepeat;
int8_t xoffset, yoffset;
int16_t sectnum, statnum;
int16_t ang, owner;
int16_t index, yvel, inittype;
int16_t type;
int16_t hitag;
int16_t extra;
};
struct sectortypedisk
{
int16_t wallptr, wallnum;
int32_t ceilingz, floorz;
uint16_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, fogpal;
int16_t type;
int16_t hitag;
int16_t extra;
};
struct walltypedisk
{
int32_t x, y;
int16_t point2, nextwall, nextsector;
uint16_t cstat;
int16_t picnum, overpicnum;
int8_t shade;
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
int16_t type;
int16_t hitag;
int16_t extra;
};
#pragma pack(pop)
BEGIN_BLD_NS
TArray<walltype> dbLoadMapWalls(const char* pPath);
class DBloodActor;
struct AISTATE;

View file

@ -53,7 +53,6 @@ struct UsermapDirectory native
native int GetNumDirectories();
native UsermapEntry GetEntry(int num);
native UsermapDirectory GetDirectory(int num);
native void DrawPreview(int num, int left, int top, int width, int height);
String GetInfo(int Selected)
{
if (parent) Selected--;
@ -105,7 +104,7 @@ class UsermapMenu : ListMenu
// private to this menu to prevent exploits.
private native static void StartMap(UsermapEntry entry);
private native static void DrawPreview(UsermapEntry entry, int left, int top, int width, int height);
//=============================================================================
//
@ -183,7 +182,13 @@ class UsermapMenu : ListMenu
SetWindows();
DrawFrame(previewLeft, previewTop, previewWidth, previewHeight);
screen.Dim(0, 0.6, previewLeft, previewTop, previewWidth, previewHeight);
currentDir.DrawPreview(Selected, previewLeft, previewTop, previewWidth, previewHeight);
if (Selected >= numparent + numdirs)
{
let entry = currentDir.GetEntry(Selected - numparent - numdirs);
DrawPreview(entry, previewLeft, previewTop, previewWidth, previewHeight);
}
// Draw comment area
DrawFrame (commentLeft, commentTop, commentWidth, commentHeight);