SBSPSS/Utils/Libs/GinLib/mapread.cpp
2000-12-02 18:55:49 +00:00

534 lines
11 KiB
C++

/*=========================================================================
EXPORT.CPP
Author:
Created:
Project:
Purpose:
Copyright (c) 1998 Climax Development Ltd
===========================================================================*/
/*----------------------------------------------------------------------
Includes
-------- */
/* Std Lib
------- */
#include "mapread.h"
/* Glib
---- */
#include <tquant.h>
/* Local
----- */
/* Graphics
-------- */
/*----------------------------------------------------------------------
Tyepdefs && Defines
------------------- */
#define TILE_SHIFT 8
/*----------------------------------------------------------------------
Structure defintions
-------------------- */
/*----------------------------------------------------------------------
Positional Vars
--------------- */
/*----------------------------------------------------------------------
Function Prototypes
------------------- */
/*----------------------------------------------------------------------
Vars
---- */
/*----------------------------------------------------------------------
Data
---- */
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
int CMapFile::GetVersion( char * version )
{
int ret = 0;
int len;
char whole[8];
char frac[8];
len = strlen(version);
if (len)
{
int pos = 0;
int opos = 0;
while (version[pos] != '.')
{
whole[pos] = version[pos];
pos++;
if (pos > len)
GObject::Error(ERR_FATAL,"Corrupt Version - %s\n", version);
}
pos++;
while (version[pos])
{
frac[opos] = version[pos];
pos++;
opos++;
if (pos > len)
GObject::Error(ERR_FATAL,"Corrupt Version - %s\n", version);
}
}
ret = atoi( whole );
ret *= 100;
ret += atoi( frac );
GObject::Error(ERR_WARNING, "Map Version %d\n", ret );
return ret;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
int CMapFile::FindFrame( const char * frame )
{
char InFile[_MAX_FNAME];
char CompFile[_MAX_FNAME];
_splitpath( frame, NULL, NULL, InFile, NULL );
for (int f=0;f<RepItems.size();f++)
{
_splitpath( RepItems[f].m_texName, NULL, NULL, CompFile, NULL );
if (!strcmp( InFile, CompFile )) return f;
}
if (m_errorOnMissingFile)
GObject::Error(ERR_FATAL,"Missing bmp - %s\n", frame);
return -1;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CMapFile::Parse()
{
int i;
int version;
int x, y;
float lowestY;
TILE_PACKET * t;
MapFile.Seek( 0 );
MapFile.Read( VersionText, 4 );
version = GetVersion( (char *)VersionText );
// READ GLOBAL TILE NAMES
MapFile.Read( &nbTiles );
TileNames = (CFileName *)malloc( nbTiles * sizeof(CFileName) );
for (i=0;i<nbTiles;i++)
{
MapFile.Read( &TileNames[i], sizeof(CFileName) );
}
// READ GLOBAL OBJECT INFO
MapFile.Read( &nbObjects );
Objects = (CObject *)malloc( nbObjects * sizeof(CObject) );
for (i=0;i<nbObjects;i++)
{
MapFile.Read( &Objects[i].Name, sizeof(CFileName) );
if (version < 104)
{
MapFile.Read( &Objects[i].Width );
MapFile.Read( &Objects[i].Height );
MapFile.Read( &Objects[i].Depth );
MapFile.Read( &Objects[i].Mask, (sizeof(bool) * MAX_MASKX * MAX_MASKY) );
}
}
// READ TILE MAP
MapFile.Read( &MapWidth );
MapFile.Read( &MapHeight );
MapFile.Read( &TileSize );
if (TileSize > sizeof(MapCTile)) GObject::Error(ERR_FATAL, "MapCTile STRUCT MISMATCH" );
Tiles = (TILE_PACKET *)malloc( (MapWidth * MapHeight * sizeof( TILE_PACKET )) );
if (!Tiles)
GObject::Error(ERR_FATAL, "can't allocate tiles" );
t = Tiles;
nbSpawnPoints=0;
lowestY = 65536;
for (y=0;y<MapHeight;y++)
{
for (x=0;x<MapWidth;x++)
{
MapCTile tile;
int frame = 0;
int angle = 0;
MapFile.Read( &tile, TileSize );
strlwr( tile.FrameName );
for (int l=0;l<strlen(tile.FrameName);l++)
{
if (tile.FrameName[l] == '\\') tile.FrameName[l] = '/';
}
if (tile.frame) frame = FindFrame( tile.FrameName );
else frame = 0;
angle = (int)tile.angle;
angle++;
angle &= 0x3;
if (angle == 2) angle = 0;
else if (angle == 0) angle = 2;
t->frame = tile.frame;
t->r = (u8)(tile.r * 255.f);
t->g = (u8)(tile.g * 255.f);
t->b = (u8)(tile.b * 255.f);
t->pad = 0;
if (tile.flag&TF_SPAWN)
{
if (nbSpawnPoints>=MAX_SPAWNING_TILES)
{
GObject::Error(ERR_FATAL, "Max Spawning Positions exceeded for level" );
}
Spawn[nbSpawnPoints].x = x;
Spawn[nbSpawnPoints].y = y;
nbSpawnPoints++;
}
t->angle = angle;
t->flags = (int)(tile.flag&(~TF_SPAWN));
t->height = (int)tile.py;
t->frame = frame;
t->xflip = tile.xflip;
t->yflip = tile.yflip;
t->type = tile.type;
// if (t->flags & TF_NO_BUILD)
// GObject::Error(ERR_WARNING, "No build flag found\n" );
if (frame < 0) t->flags |= TF_HIDDEN;
if (!(tile.flag & TF_HIDDEN) && (x < MapWidth-1) && (y < MapHeight-1))
{
if (lowestY > tile.py) lowestY = tile.py;
}
t++;
}
}
GObject::Error( ERR_WARNING, "Lowest land height = %f\n", lowestY );
t = Tiles;
for (y=0;y<MapHeight;y++)
{
for (x=0;x<MapWidth;x++)
{
t->height -= (int)lowestY;
if (t->height < 0) t->height = 0;
// if (t->height > sizeof(u16))
// {
// GObject::Error( ERR_FATAL, "Land height overflow - %d\n", t->height );
// }
t++;
}
}
// READ OBJECT LIST
MapFile.Read( &nbModels );
MapFile.Read( &ModelSize );
if (ModelSize > sizeof(CModel)) GObject::Error(ERR_FATAL, "Struct mismatch in CModel" );
Models = (MODEL_PACKET *)malloc( nbModels * sizeof(MODEL_PACKET) );
if (!Models)
GObject::Error(ERR_FATAL, "Can't allocate models\n" );
MODEL_PACKET * m = Models;
for (i=0;i<nbModels;i++)
{
u32 animflag;
u16 angle;
CModel model;
char MyDir[_MAX_DIR];
char MyFile[_MAX_FNAME];
MapFile.Read( &model, ModelSize );
_splitpath( model.MeshName, NULL, MyDir, MyFile, NULL );
angle = (u16)model.AngY;
if (angle == 1) angle = 3;
else if (angle == 3) angle = 1;
animflag = FindFileEquate( MyFile );
animflag &= ~MODEL_FLAGS_MASK;
if (model.m_Animates) animflag |= MODEL_ANIMATE_FLAG;
if (model.m_Busstop) animflag |= MODEL_BUSSTOP_FLAG;
if (model.m_Booth) animflag |= MODEL_BOOTH_FLAG;
if (model.m_OtherAnim) animflag |= MODEL_OTHERANIM_FLAG;
if (model.m_Entrance) animflag |= MODEL_ENTRANCE_FLAG;
m->AnimAndFlags = animflag;
m->xp = (u16)(model.PosX / (1 << TILE_SHIFT));
m->yp = (u16)(model.PosY - lowestY);
m->zp = (u16)(model.PosZ / (1 << TILE_SHIFT));
m->ya = (u16)angle;
// if (m->yp > sizeof(u16))
// {
// GObject::Error( ERR_FATAL, "Object Y position overflow - %d\n", m->yp );
// }
m++;
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
int CMapFile::FindFileEquate( char * name )
{
strupr( name );
for (int i=0;i<AnimItems.size();i++)
{
if (!strcmp( AnimItems[i].m_AnimName, name )) return( AnimItems[i].m_Frame );
}
if (AnimHeaderFile)
{
GObject::Error( ERR_WARNING, "Could not find anim %s in anim header %s\n", name, AnimHeaderFile );
}
else
{
GObject::Error( ERR_WARNING, "Could not find anim %s - anim header not loaded\n", name );
}
return (-1);
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CMapFile::MakeMapPalette(void)
{
using namespace std;
vector<u8> SourcePal;
vector<u8> DestPal;
SourcePal.resize(MapWidth*MapHeight*3);
TileToPalNum.resize(MapWidth*MapHeight);
DestPal.resize(NUM_OF_PAL_ENTRIES*3);
MapPal.resize(NUM_OF_PAL_ENTRIES);
for (int f=0;f<MapWidth*MapHeight;f++)
{
SourcePal[f*3+0]=Tiles[f].r;
SourcePal[f*3+1]=Tiles[f].g;
SourcePal[f*3+2]=Tiles[f].b;
}
tquant(&SourcePal[0],&TileToPalNum[0],&DestPal[0],NUM_OF_PAL_ENTRIES,MapWidth*MapHeight);
for (int c=0;c<NUM_OF_PAL_ENTRIES;c++)
{
MapPal[c].r=DestPal[c*3+0];
MapPal[c].g=DestPal[c*3+1];
MapPal[c].b=DestPal[c*3+2];
}
}
void CMapFile::WriteMapPalette(FILE * F)
{
int count = NUM_OF_PAL_ENTRIES;
fwrite( &count, sizeof(u32), 1,F);
for (int f=0;f<count;f++)
{
u8 Dummy = 0;
fwrite( &MapPal[f].r, sizeof(u8), 1,F);
fwrite( &MapPal[f].g, sizeof(u8), 1,F);
fwrite( &MapPal[f].b, sizeof(u8), 1,F);
fwrite( &Dummy,sizeof(u8),1,F);
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CMapFile::SetInfoOut( int x, int y, TILE_PACKET * T, OUT_TILE_PACKET * O )
{
O->mType = 0;
if (T->height<0)
{
O->ypos = 0;
// printf("low height %d\n", T->height);
} else
if (T->height>255*4.f)
{
O->ypos = 255;
// printf("hi height %d\n", T->height);
} else
{
O->ypos = (T->height/4.f);
}
O->mNeighbours = 0;
O->mDirection = 0;
if (T->frame > 4095) GObject::Error(ERR_FATAL, "Tile index overflow" );
O->mTileIndex = T->frame;
O->mTileIndex |= (T->angle << 12); // STUFF ANGLE IN TOP BITS OF TILE INDEX
O->ColIdx = GetPalNum( x, y );
O->mFlags = T->flags;
if (T->xflip) O->mTileIndex |= (1 << 15); // SET X/Y FLIP IN TOP BITS OF TILE INDEX
if (T->yflip) O->mTileIndex |= (1 << 14);
switch(T->type)
{
case TT_VOID:
O->mType = (u8)CELL_Void;
break;
case TT_PATH:
O->mType = (u8)CELL_Path;
break;
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CMapFile::Export( const char * file )
{
FILE * level;
MakeMapPalette();
level = fopen( file, "wb" );
if (level)
{
WriteMapPalette( level );
fwrite( &MapWidth, sizeof( int ), 1, level );
fwrite( &MapHeight, sizeof( int ), 1, level );
for (int y=0;y<MapHeight;y++)
{
for (int x=0;x<MapWidth;x++)
{
TILE_PACKET * tile;
OUT_TILE_PACKET out;
tile = &Tiles[x + (y * MapWidth)];
SetInfoOut( x, y, tile, &out );
fwrite( &out, sizeof(OUT_TILE_PACKET), 1, level );
}
}
fwrite( &nbModels, sizeof( int ), 1, level );
for (int i=0;i<nbModels;i++)
{
fwrite( &Models[i], sizeof(MODEL_PACKET), 1, level );
}
fwrite( &nbSpawnPoints, sizeof(int), 1, level );
for (i=0; i<nbSpawnPoints; i++)
{
fwrite( &Spawn[i], sizeof(SPAWNPOS), 1, level);
}
// printf( "WRITTEN %s\n", file );
}
else
{
GObject::Error(ERR_FATAL, "Could not save lvl file - %s", file );
}
}
/*===========================================================================
end */