Added loader for Full Tilt .dat files, v1.

Works with some data hacks in lowest resolution.
Seems to work ok, even though BL is still 3DPB.
pull/5/head
Muzychenko Andrey 2 years ago
parent 6ff457eb68
commit 49f6132d23

@ -39,21 +39,21 @@ Type Meaning/comments
9 String (content)
10 Array of 16bits integer values
11 Array of 32bits floating point values (collision box, ...)
12 16 bpp bitmap (Heightmap?)
12 16 bpp bitmap (zMap)
//-- 8bpp bitmap data header --//
+0: Unknown (0) BYTE
+0: Resolution BYTE 0=640x480, 1=800x600, 2=1024x768, -1=Load in all resolutions
+1: Width WORD
+3: Height WORD
+5: X position WORD
+7 Y position WORD
+9: Size of bitmap DWORD
+13: Unknown (1) BYTE
+13: Flags BYTE bit0=Raw bmp align; bit1=DibBitmap, raw when 0; bit2=Spliced bitmap (aka skipline), combines bmp and zMap in RLE-like way
+14: Bitmap data BYTE*(DWORD@+9)
//-- 16bpp bitmap data header --//
//-- 16bpp zMap data header --//
+0: Width WORD
+2: Height WORD
+4: Pitch/2 WORD
@ -62,6 +62,16 @@ Type Meaning/comments
+12: Unknown (80) WORD
+14: Bitmap data BYTE*(DWORD@+9)
//-- 16bpp zMap data header full tilt --//
+0: Resolution BYTE 0=640x480, 1=800x600, 2=1024x768, -1=Load in all resolutions
+1: Width WORD
+3: Height WORD
+5: Pitch/2 WORD
+7: Unknown (0) DWORD
+11: Unknown (0) WORD
+13: Unknown (80) WORD
+15: Bitmap data BYTE*(DWORD@+9)
//-- Pinball 3D remarkable groups --//

@ -31,6 +31,10 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
ListBitmap = new objlist_class<gdrv_bitmap8>(0, 4);
auto groupIndex = loader::query_handle("ball");
/*Full tilt hack - ball is ball0*/
if (groupIndex < 0)
groupIndex = loader::query_handle("ball0");
Offset = *loader::query_float_attribute(groupIndex, 0, 500);
auto visualCount = loader::query_visual_states(groupIndex);
auto index = 0;

@ -27,6 +27,12 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
auto collMult = *floatArr;
auto bmpCoef2 = *floatArr2;
auto bmpCoef1 = *floatArr3;
/*Full tilt hack: different flipper speed*/
if (bmpCoef2 > 1)
bmpCoef2 = 0.08f;
if (bmpCoef1 > 1)
bmpCoef1 = 0.04f;
auto vecT2 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 802));
auto vecT1 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 801));
auto origin = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 800));

@ -19,16 +19,8 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
MessageField = 0;
Timer = 0;
BallCapturedFlag = 0;
auto floatArr1 = loader::query_float_attribute(groupIndex, 0, 407);
if (floatArr1)
Unknown3 = *floatArr1;
else
Unknown3 = 0.25;
auto floatArr2 = loader::query_float_attribute(groupIndex, 0, 701);
if (floatArr2)
GravityMult = *floatArr2;
else
GravityMult = 0.5;
Unknown3 = loader::query_float_attribute(groupIndex, 0, 407, 0.25f);
GravityMult = loader::query_float_attribute(groupIndex, 0, 701, 0.2f);
GravityPull = *loader::query_float_attribute(groupIndex, 0, 305);
loader::query_visual(groupIndex, 0, &visual);
@ -38,7 +30,8 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
if (Circle.RadiusSq == 0.0)
Circle.RadiusSq = 0.001f;
auto tCircle = new TCircle(this, &ActiveFlag, visual.CollisionGroup, reinterpret_cast<vector_type*>(visual.FloatArr),
auto tCircle = new TCircle(this, &ActiveFlag, visual.CollisionGroup,
reinterpret_cast<vector_type*>(visual.FloatArr),
Circle.RadiusSq);
if (tCircle)
{
@ -49,6 +42,10 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
ZSetValue = loader::query_float_attribute(groupIndex, 0, 408)[2];
FieldFlag = static_cast<int>(floor(*loader::query_float_attribute(groupIndex, 0, 1304)));
/*Full tilt hack - FieldFlag should be on*/
if (!FieldFlag)
FieldFlag = 1;
Circle.RadiusSq = visual.FloatArr[2] * visual.FloatArr[2];
circle.RadiusSq = Circle.RadiusSq;
circle.Center.X = Circle.Center.X;

@ -48,6 +48,19 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool
zMap = ListZMap->Get(0);
if (ListBitmap)
{
/* Full tilt hack - spliced bitmap includes zMap
* Users access bitmap-zMap in pairs, pad zMap list with 0 for such users
* zdrv does not access zMap when drawing spliced bitmap*/
if (!ListZMap)
{
ListZMap = new objlist_class<zmap_header_type>(0, 4);
for (int index = 0; index < ListBitmap->GetCount(); index++)
{
assertm(ListBitmap->Get(index)->BitmapType == BitmapType::Spliced, "Wrong zMap padding");
ListZMap->Add(visual.ZMap);
}
}
rectangle_type bmp1Rect{}, tmpRect{};
auto rootBmp = ListBitmap->Get(0);
bmp1Rect.XPosition = rootBmp->XPosition - table->XOffset;

@ -22,16 +22,8 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
loader::query_visual(groupIndex, 0, &visual);
CollisionGroup = visual.CollisionGroup;
auto floatArr1 = loader::query_float_attribute(groupIndex, 0, 701);
if (floatArr1)
BallFieldMult = *floatArr1;
else
BallFieldMult = 0.2f;
auto floatArr2 = loader::query_float_attribute(groupIndex, 0, 1305);
if (floatArr2)
RampFlag1 = static_cast<int>(floor(*floatArr2));
else
RampFlag1 = 0;
BallFieldMult = loader::query_float_attribute(groupIndex, 0, 701, 0.2f);
RampFlag1 = static_cast<int>(loader::query_float_attribute(groupIndex, 0, 1305, 0));
auto floatArr3Plane = loader::query_float_attribute(groupIndex, 0, 1300);
RampPlaneCount = static_cast<int>(floor(*floatArr3Plane));

@ -49,11 +49,12 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
PinballTable->GravityAnglY = 1.570796f;
}
auto table3 = PinballTable;
GraityDirX = cos(table3->GravityAnglY) * sin(table3->GravityAngleX) * table3->GravityDirVectMult;
GraityDiY = sin(table3->GravityAnglY) * sin(table3->GravityAngleX) * table3->GravityDirVectMult;
GraityDirX = cos(PinballTable->GravityAnglY) * sin(PinballTable->GravityAngleX) * PinballTable->GravityDirVectMult;
GraityDirY = sin(PinballTable->GravityAnglY) * sin(PinballTable->GravityAngleX) * PinballTable->GravityDirVectMult;
auto angleMultArr = loader::query_float_attribute(groupIndex, 0, 701);
if (angleMultArr)
/*Full tilt hack - GraityMult should be 0.2*/
if (angleMultArr && *angleMultArr < 1)
GraityMult = *angleMultArr;
else
GraityMult = 0.2f;
@ -109,7 +110,7 @@ int TTableLayer::FieldEffect(TBall* ball, vector_type* vecDst)
{
vecDst->X = GraityDirX - (0.5f - static_cast<float>(rand()) * 0.00003051850947599719f + ball->Acceleration.X) *
ball->Speed * GraityMult;
vecDst->Y = GraityDiY - ball->Acceleration.Y * ball->Speed * GraityMult;
vecDst->Y = GraityDirY - ball->Acceleration.Y * ball->Speed * GraityMult;
return 1;
}
@ -254,7 +255,7 @@ void TTableLayer::edges_insert_circle(circle_type* circle, TEdgeSegment* edge, f
ray.Origin.Y = ray.Origin.Y - edge_manager->AdvanceY;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0)
break;
collision = false;
}
while (false);

@ -26,7 +26,7 @@ public:
float Unknown3F;
float Unknown4F;
float GraityDirX;
float GraityDiY;
float GraityDirY;
int Unknown7;
float GraityMult;
field_effect_type Field;

@ -185,6 +185,21 @@ int gdrv::create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag)
return 0;
}
int gdrv::create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size)
{
bmp->Dib = nullptr;
bmp->Width = width;
bmp->Stride = width;
bmp->BitmapType = BitmapType::Spliced;
bmp->Height = height;
char* buf = memory::allocate(size);
bmp->BmpBufPtr1 = buf;
if (!buf)
return -1;
bmp->BmpBufPtr2 = bmp->BmpBufPtr1;
return 0;
}
int gdrv::display_palette(PALETTEENTRY* plt)
{

@ -5,6 +5,7 @@ enum class BitmapType : char
None = 0,
RawBitmap = 1,
DibBitmap = 2,
Spliced = 4,
};
struct gdrv_bitmap8
@ -50,6 +51,7 @@ public:
static int create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height);
static int create_bitmap(gdrv_bitmap8* bmp, int width, int height);
static int create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag);
static int create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size);
static int destroy_bitmap(gdrv_bitmap8* bmp);
static int display_palette(PALETTEENTRY* plt);
static UINT start_blit_sequence();

@ -242,6 +242,37 @@ float* loader::query_float_attribute(int groupIndex, int groupIndexOffset, int f
return nullptr;
}
float loader::query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal)
{
if (groupIndex < 0)
{
error(0, 22);
return NAN;
}
int stateId = state_id(groupIndex, groupIndexOffset);
if (stateId < 0)
{
error(16, 22);
return NAN;
}
for (auto skipIndex = 0;; ++skipIndex)
{
auto floatArr = reinterpret_cast<float*>(partman::field_nth(loader_table, stateId,
datFieldTypes::FloatArray,skipIndex));
if (!floatArr)
break;
if (static_cast<__int16>(floor(*floatArr)) == firstValue)
return floatArr[1];
}
if (!isnan(defVal))
return defVal;
error(13, 22);
return NAN;
}
int loader::material(int groupIndex, visualStruct* visual)
{
if (groupIndex < 0)

@ -65,6 +65,7 @@ public:
static int query_visual(int groupIndex, int groupIndexOffset, visualStruct* visual);
static char* query_name(int groupIndex);
static float* query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue);
static float query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal);
static __int16* query_iattribute(int groupIndex, int firstValue, int* arraySize);
static float play_sound(int soundIndex);
static datFileStruct* loader_table;

@ -9,8 +9,7 @@ short partman::_field_size[] =
2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0
};
datFileStruct* partman::load_records(LPCSTR lpFileName)
datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool fullTiltMode)
{
_OFSTRUCT ReOpenBuff{};
datFileHeader header{};
@ -86,10 +85,10 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
if (!groupData)
break;
groupData->EntryCount = entryCount;
datEntryData* entryData = groupData->Entries;
groupData->EntryCount = 0;
for (auto entryIndex = 0; entryIndex < entryCount; ++entryIndex)
{
auto entryData = &groupData->Entries[groupData->EntryCount];
auto entryType = static_cast<datFieldTypes>(_lread_char(fileHandle));
entryData->EntryType = entryType;
@ -100,6 +99,12 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
if (entryType == datFieldTypes::Bitmap8bit)
{
_hread(fileHandle, &bmpHeader, sizeof(dat8BitBmpHeader));
if (bmpHeader.Resolution != resolution && bmpHeader.Resolution != -1)
{
_llseek(fileHandle, bmpHeader.Size, 1);
continue;
}
auto bmp = reinterpret_cast<gdrv_bitmap8*>(memory::allocate(sizeof(gdrv_bitmap8)));
entryData->Buffer = reinterpret_cast<char*>(bmp);
if (!bmp)
@ -107,10 +112,15 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
abort = true;
break;
}
if (bmpHeader.IsFlagSet(bmp8Flags::DibBitmap)
? gdrv::create_bitmap(bmp, bmpHeader.Width, bmpHeader.Height)
: gdrv::create_raw_bitmap(bmp, bmpHeader.Width, bmpHeader.Height,
bmpHeader.IsFlagSet(bmp8Flags::RawBmpUnaligned)))
int bmpRez;
if (bmpHeader.IsFlagSet(bmp8Flags::Spliced))
bmpRez = gdrv::create_spliced_bitmap(bmp, bmpHeader.Width, bmpHeader.Height, bmpHeader.Size);
else if (bmpHeader.IsFlagSet(bmp8Flags::DibBitmap))
bmpRez = gdrv::create_bitmap(bmp, bmpHeader.Width, bmpHeader.Height);
else
bmpRez = gdrv::create_raw_bitmap(bmp, bmpHeader.Width, bmpHeader.Height,
bmpHeader.IsFlagSet(bmp8Flags::RawBmpUnaligned));
if (bmpRez)
{
abort = true;
break;
@ -121,9 +131,21 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
}
else if (entryType == datFieldTypes::Bitmap16bit)
{
/*Full tilt has extra byte(@0:resolution) in zMap*/
if (fullTiltMode)
{
char zMapResolution = _lread_char(fileHandle);
fieldSize--;
if (zMapResolution != resolution && zMapResolution != -1)
{
_llseek(fileHandle, fieldSize, 1);
continue;
}
}
_hread(fileHandle, &zMapHeader, sizeof(dat16BitBmpHeader));
int length = fieldSize - sizeof(dat16BitBmpHeader);
auto zmap = reinterpret_cast<zmap_header_type*>(memory::allocate(sizeof(zmap_header_type) + length));
zmap->Width = zMapHeader.Width;
zmap->Height = zMapHeader.Height;
@ -144,9 +166,9 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
}
entryData->FieldSize = fieldSize;
datFile->NumberOfGroups = groupIndex + 1;
++entryData;
groupData->EntryCount++;
}
datFile->NumberOfGroups = groupIndex + 1;
}
_lclose(fileHandle);

@ -28,7 +28,8 @@ enum class datFieldTypes : __int16
enum class bmp8Flags : unsigned char
{
RawBmpUnaligned = 1 << 0,
DibBitmap = 1 << 1,
DibBitmap = 1 << 1,
Spliced = 1 << 2,
};
@ -71,7 +72,7 @@ struct datFileStruct
#pragma pack(1)
struct dat8BitBmpHeader
{
char Unknown1;
char Resolution;
__int16 Width;
__int16 Height;
__int16 XPosition;
@ -108,7 +109,7 @@ static_assert(sizeof(dat16BitBmpHeader) == 14, "Wrong size of zmap_header_type")
class partman
{
public:
static datFileStruct* load_records(LPCSTR lpFileName);
static datFileStruct* load_records(LPCSTR lpFileName, int resolution, bool fullTiltMode);
static void unload_records(datFileStruct* datFile);
static char* field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN);
static char* field(datFileStruct* datFile, int groupIndex, datFieldTypes entryType);

@ -37,8 +37,9 @@ int pb::init()
++memory::critical_allocation;
lstrcpyA(datFileName, winmain::DatFileName);
//lstrcpyA(datFileName, "cadet.dat");
pinball::make_path_name(dataFilePath, datFileName, 300);
record_table = partman::load_records(dataFilePath);
record_table = partman::load_records(dataFilePath, 0, strstr(datFileName, "cadet"));
auto useBmpFont = 0;
pinball::get_rc_int(158, &useBmpFont);
@ -55,6 +56,10 @@ int pb::init()
auto backgroundBmp = (gdrv_bitmap8*)partman::field_labeled(record_table, "background", datFieldTypes::Bitmap8bit);
auto cameraInfo = (float*)partman::field_labeled(record_table, "camera_info", datFieldTypes::FloatArray);
/*Full tilt hack - table size is hardcoded*/
if (!tableSize)
tableSize = new short[2]{600, 800};
if (cameraInfo)
{
memcpy(&projMat, cameraInfo, sizeof(float) * 4 * 3);
@ -545,7 +550,7 @@ void pb::end_game()
scores[j] = scores[i];
scores[i] = score;
int index = scoreIndex[j];
int index = scoreIndex[j];
scoreIndex[j] = scoreIndex[i];
scoreIndex[i] = index;
}

@ -25,4 +25,13 @@
/*Sound uses PlaySound*/
#undef PlaySound
inline size_t pgm_save(int width, int height, char* data, FILE* outfile)
{
size_t n = 0;
n += fprintf(outfile, "P5\n%d %d\n%d\n", width, height, 0xFF);
n += fwrite(data, 1, width * height, outfile);
return n;
}
#endif //PCH_H

@ -1,6 +1,7 @@
#include "pch.h"
#include "zdrv.h"
#include "memory.h"
#include "pb.h"
int zdrv::create_zmap(zmap_header_type* zmap, int width, int height)
@ -59,6 +60,13 @@ void zdrv::paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, in
int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, int srcBmpYOff,
zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff)
{
if (srcBmp->BitmapType == BitmapType::Spliced)
{
/*Spliced bitmap is also a zMap, how convenient*/
paint_spliced_bmp(srcBmp->XPosition, srcBmp->YPosition, dstBmp, dstZMap, srcBmp);
return;
}
int dstHeightAbs = abs(dstBmp->Height);
int srcHeightAbs = abs(srcBmp->Height);
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff];
@ -116,3 +124,41 @@ void zdrv::paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOf
zPtr += zMap->Stride - width;
}
}
void zdrv::paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap, gdrv_bitmap8* srcBmp)
{
assertm(srcBmp->BitmapType == BitmapType::Spliced, "Wrong bmp type");
int xOffset = xPos - pb::MainTable->XOffset;
int yOffset = dstBmp->Height - srcBmp->Height - (yPos - pb::MainTable->YOffset);
if (yOffset < 0)
return;
auto bmpDstPtr = &dstBmp->BmpBufPtr2[xOffset + yOffset * dstBmp->Stride];
auto zMapDstPtr = &dstZmap->ZPtr2[xOffset + yOffset * dstZmap->Stride];
auto bmpSrcPtr = reinterpret_cast<unsigned short*>(srcBmp->BmpBufPtr2);
while (true)
{
auto stride = static_cast<short>(*bmpSrcPtr++);
if (stride < 0)
break;
/*Stride is in terms of dst stride, hardcoded to match vScreen width in current resolution*/
zMapDstPtr += stride;
bmpDstPtr += stride;
for (auto count = *bmpSrcPtr++; count; count--)
{
auto depth = *bmpSrcPtr++;
auto charPtr = reinterpret_cast<char**>(&bmpSrcPtr);
if (*zMapDstPtr >= depth)
{
*bmpDstPtr = **charPtr;
*zMapDstPtr = depth;
}
(*charPtr)++;
++zMapDstPtr;
++bmpDstPtr;
}
}
}

@ -24,4 +24,6 @@ public:
static void paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff,
zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp,
int srcBmpXOff, int srcBmpYOff, unsigned __int16 depth);
static void paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap,
gdrv_bitmap8* srcBmp);
};

Loading…
Cancel
Save