gdrv: RGBA buffers, pre-applied palettes, SDL bitmap origin.

Refactored partman.
Added sprite viewer.
This commit is contained in:
Muzychenko Andrey 2021-09-21 13:14:39 +03:00
parent 8bae7a5b05
commit c63c6701ac
28 changed files with 901 additions and 564 deletions

View File

@ -32,6 +32,8 @@ set(SOURCE_FILES
SpaceCadetPinball/fullscrn.h SpaceCadetPinball/fullscrn.h
SpaceCadetPinball/gdrv.cpp SpaceCadetPinball/gdrv.cpp
SpaceCadetPinball/gdrv.h SpaceCadetPinball/gdrv.h
SpaceCadetPinball/GroupData.cpp
SpaceCadetPinball/GroupData.h
SpaceCadetPinball/high_score.cpp SpaceCadetPinball/high_score.cpp
SpaceCadetPinball/high_score.h SpaceCadetPinball/high_score.h
SpaceCadetPinball/loader.cpp SpaceCadetPinball/loader.cpp

View File

@ -0,0 +1,268 @@
#include "pch.h"
#include "GroupData.h"
#include "fullscrn.h"
#include "gdrv.h"
#include "memory.h"
#include "zdrv.h"
EntryData::~EntryData()
{
if (Buffer)
{
if (EntryType == FieldTypes::Bitmap8bit)
gdrv::destroy_bitmap(reinterpret_cast<gdrv_bitmap8*>(Buffer));
else if (EntryType == FieldTypes::Bitmap16bit)
zdrv::destroy_zmap(reinterpret_cast<zmap_header_type*>(Buffer));
memory::free(Buffer);
}
if (DerivedBmp)
{
gdrv::destroy_bitmap(DerivedBmp);
memory::free(DerivedBmp);
}
if (DerivedZMap)
{
zdrv::destroy_zmap(DerivedZMap);
memory::free(DerivedZMap);
}
}
GroupData::GroupData(int groupId)
{
GroupId = groupId;
}
void GroupData::AddEntry(EntryData* entry)
{
Entries.push_back(entry);
switch (entry->EntryType)
{
case FieldTypes::GroupName:
GroupName = entry->Buffer;
break;
case FieldTypes::Bitmap8bit:
{
auto bmp = reinterpret_cast<gdrv_bitmap8*>(entry->Buffer);
if (bmp->BitmapType == BitmapTypes::Spliced)
{
// Get rid of spliced bitmap early on, to simplify render pipeline
auto splitBmp = memory::allocate<gdrv_bitmap8>();
auto splitZMap = memory::allocate<zmap_header_type>();
SplitSplicedBitmap(*bmp, *splitBmp, *splitZMap);
entry->DerivedBmp = splitBmp;
entry->DerivedZMap = splitZMap;
SetBitmap(splitBmp);
SetZMap(splitZMap);
}
else
{
SetBitmap(bmp);
}
break;
}
case FieldTypes::Bitmap16bit:
{
SetZMap(reinterpret_cast<zmap_header_type*>(entry->Buffer));
break;
}
default: break;
}
}
gdrv_bitmap8* GroupData::GetBitmap(int resolution) const
{
return Bitmaps[resolution];
}
zmap_header_type* GroupData::GetZMap(int resolution) const
{
return ZMaps[resolution];
}
void GroupData::SplitSplicedBitmap(const gdrv_bitmap8& srcBmp, gdrv_bitmap8& bmp, zmap_header_type& zMap)
{
assertm(srcBmp.BitmapType == BitmapTypes::Spliced, "GroupData: wrong bitmap type");
gdrv::create_bitmap(&bmp, srcBmp.Width, srcBmp.Height, srcBmp.Width);
std::memset(bmp.IndexedBmpPtr, 0xff, bmp.Stride * bmp.Height);
bmp.XPosition = srcBmp.XPosition;
bmp.YPosition = srcBmp.YPosition;
bmp.Resolution = srcBmp.Resolution;
zdrv::create_zmap(&zMap, srcBmp.Width, srcBmp.Height, srcBmp.Width);
zdrv::fill(&zMap, zMap.Width, zMap.Height, 0, 0, 0xFFFF);
zMap.Resolution = srcBmp.Resolution;
auto tableWidth = fullscrn::resolution_array[srcBmp.Resolution].TableWidth;
auto src = reinterpret_cast<uint16_t*>(srcBmp.IndexedBmpPtr);
auto srcChar = reinterpret_cast<char**>(&src);
for (int dstInd = 0;;)
{
auto stride = static_cast<int16_t>(*src++);
if (stride < 0)
break;
// Stride is in terms of dst stride, hardcoded to match vScreen width in current resolution
if (stride > bmp.Width)
{
stride += bmp.Width - tableWidth;
assertm(stride >= 0, "Spliced bitmap: negative computed stride");
}
dstInd += stride;
for (auto count = *src++; count; count--)
{
auto depth = *src++;
bmp.IndexedBmpPtr[dstInd] = **srcChar;
zMap.ZPtr1[dstInd] = depth;
(*srcChar)++;
dstInd++;
}
}
}
void GroupData::SetBitmap(gdrv_bitmap8* bmp)
{
assertm(Bitmaps[bmp->Resolution] == nullptr, "GroupData: bitmap override");
Bitmaps[bmp->Resolution] = bmp;
auto zMap = ZMaps[bmp->Resolution];
if (zMap)
{
assertm(bmp->Width == zMap->Width && bmp->Height == zMap->Height,
"GroupData: mismatched bitmap/zMap dimensions");
}
}
void GroupData::SetZMap(zmap_header_type* zMap)
{
// Flip zMap to match with flipped non-indexed bitmaps
zdrv::FlipZMapHorizontally(*zMap);
assertm(ZMaps[zMap->Resolution] == nullptr, "GroupData: zMap override");
ZMaps[zMap->Resolution] = zMap;
auto bmp = Bitmaps[zMap->Resolution];
if (bmp)
{
assertm(bmp->Width == zMap->Width && bmp->Height == zMap->Height,
"GroupData: mismatched bitmap/zMap dimensions");
}
}
DatFile::~DatFile()
{
for (auto group : Groups)
{
if (!group)
continue;
for (const auto entry : group->GetEntries())
{
delete entry;
}
delete group;
}
}
char* DatFile::field(int groupIndex, FieldTypes targetEntryType)
{
assertm(targetEntryType != FieldTypes::Bitmap8bit && targetEntryType != FieldTypes::Bitmap16bit,
"partman: Use specific get for bitmaps");
auto group = Groups[groupIndex];
for (const auto entry : group->GetEntries())
{
if (entry->EntryType == targetEntryType)
{
return entry->Buffer;
}
if (entry->EntryType > targetEntryType)
break;
}
return nullptr;
}
char* DatFile::field_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN)
{
assertm(targetEntryType != FieldTypes::Bitmap8bit && targetEntryType != FieldTypes::Bitmap16bit,
"partman: Use specific get for bitmaps");
auto group = Groups[groupIndex];
auto skipCount = 0;
for (const auto entry : group->GetEntries())
{
if (entry->EntryType > targetEntryType)
break;
if (entry->EntryType == targetEntryType)
if (skipCount++ == skipFirstN)
return entry->Buffer;
}
return nullptr;
}
int DatFile::field_size_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN)
{
auto group = Groups[groupIndex];
auto skipCount = 0;
for (const auto entry : group->GetEntries())
{
if (entry->EntryType > targetEntryType)
return 0;
if (entry->EntryType == targetEntryType)
if (skipCount++ == skipFirstN)
return entry->FieldSize;
}
return 0;
}
int DatFile::field_size(int groupIndex, FieldTypes targetEntryType)
{
return field_size_nth(groupIndex, targetEntryType, 0);
}
int DatFile::record_labeled(LPCSTR targetGroupName)
{
auto targetLength = strlen(targetGroupName);
for (int groupIndex = Groups.size() - 1; groupIndex >= 0; --groupIndex)
{
auto groupName = field(groupIndex, FieldTypes::GroupName);
if (!groupName)
continue;
int index;
for (index = 0; index < targetLength; index++)
if (targetGroupName[index] != groupName[index])
break;
if (index == targetLength && !targetGroupName[index] && !groupName[index])
return groupIndex;
}
return -1;
}
char* DatFile::field_labeled(LPCSTR lpString, FieldTypes fieldType)
{
auto groupIndex = record_labeled(lpString);
return groupIndex < 0 ? nullptr : field(groupIndex, fieldType);
}
gdrv_bitmap8* DatFile::GetBitmap(int groupIndex)
{
auto group = Groups[groupIndex];
return group->GetBitmap(fullscrn::GetResolution());
}
zmap_header_type* DatFile::GetZMap(int groupIndex)
{
auto group = Groups[groupIndex];
return group->GetZMap(fullscrn::GetResolution());
}

View File

@ -0,0 +1,97 @@
#pragma once
struct zmap_header_type;
struct gdrv_bitmap8;
enum class FieldTypes : int16_t
{
// One 16 bit signed integer
ShortValue = 0,
// Sprite bitmap, 8bpp, indexed color
Bitmap8bit = 1,
Unknown2 = 2,
// Group name, char[]. Not all groups have names.
GroupName = 3,
Unknown4 = 4,
// Palette, contains 256 RBGA 4-byte colors.
Palette = 5,
Unknown6 = 6,
Unknown7 = 7,
Unknown8 = 8,
// String, char[]
String = 9,
// Array of 16 bit signed integers
ShortArray = 10,
// Array of 32 bit floats
FloatArray = 11,
// Sprite depth map, 16bpp, unsigned
Bitmap16bit = 12,
};
struct EntryData
{
~EntryData();
FieldTypes EntryType{};
int FieldSize{};
char* Buffer{};
gdrv_bitmap8* DerivedBmp{};
zmap_header_type* DerivedZMap{};
};
class GroupData
{
public:
int GroupId;
std::string GroupName;
GroupData(int groupId);
void AddEntry(EntryData* entry);
const std::vector<EntryData*>& GetEntries() const { return Entries; }
const EntryData* GetEntry(size_t index) const { return Entries[index]; }
size_t EntryCount() const { return Entries.size(); }
void ReserveEntries(size_t count) { Entries.reserve(count); }
gdrv_bitmap8* GetBitmap(int resolution) const;
zmap_header_type* GetZMap(int resolution) const;
private:
std::vector<EntryData*> Entries;
gdrv_bitmap8* Bitmaps[3]{};
zmap_header_type* ZMaps[3]{};
static void SplitSplicedBitmap(const gdrv_bitmap8& srcBmp, gdrv_bitmap8& bmp, zmap_header_type& zMap);
void SetBitmap(gdrv_bitmap8* bmp);
void SetZMap(zmap_header_type* zMap);
};
class DatFile
{
public:
std::string AppName;
std::string Description;
std::vector<GroupData*> Groups;
~DatFile();
char* field_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN);
char* field(int groupIndex, FieldTypes entryType);
int field_size_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN);
int field_size(int groupIndex, FieldTypes targetEntryType);
int record_labeled(LPCSTR targetGroupName);
char* field_labeled(LPCSTR lpString, FieldTypes fieldType);
gdrv_bitmap8* GetBitmap(int groupIndex);
zmap_header_type* GetZMap(int groupIndex);
};

View File

@ -3,15 +3,6 @@
#include "pch.h" #include "pch.h"
#include "objlist_class.h"
#include "partman.h"
#include "gdrv.h"
#include "loader.h"
#include "pb.h"
#include "pinball.h"
#include "score.h"
#include "TPinballTable.h"
#include "TTextBox.h"
#include "winmain.h" #include "winmain.h"
int main(int argc, char* argv[]) int main(int argc, char* argv[])
@ -24,57 +15,6 @@ int main(int argc, char* argv[])
winmain::WinMain(cmdLine.c_str()); winmain::WinMain(cmdLine.c_str());
return 0; return 0;
} }
std::cout << "Hello World!\n";
gdrv::init(0,0);
auto d = objlist_class<void>(2, 4);
for (size_t i = 0; i < 100; i++)
{
d.Add((void*)i);
}
d.Delete((void*)3);
auto xx = sizeof(datFileHeader);
winmain::DatFileName = "PINBALL.DAT";
pb::init();
auto datFile = pb::record_table;
assert(partman::field_size_nth(datFile, 0, datFieldTypes::String, 0) == 43);
assert(partman::field_size_nth(datFile, 2, datFieldTypes::Palette, 0) == 1024);
assert(partman::field_size_nth(datFile, 101, datFieldTypes::FloatArray, 4) == 32);
assert(strcmp(partman::field(datFile, 0, datFieldTypes::String), "3D-Pinball: Copyright 1994, Cinematronics") == 0);
assert(strcmp(partman::field(datFile, 540, datFieldTypes::GroupName), "table_objects") == 0);
assert(partman::record_labeled(datFile, "background") == 2);
assert(partman::record_labeled(datFile, "a_bump1") == 372);
assert(memcmp(partman::field_labeled(datFile, "table_size", datFieldTypes::ShortArray), new short[2]{ 600, 416 }, 2 * 2) == 0);
//loader::error(25, 26);
loader::get_sound_id(18);
visualStruct visual1{};
loader::material(96, &visual1);
loader::query_visual(283, 0, &visual1);
visualKickerStruct kicker1{};
loader::kicker(509, &kicker1);
auto score1 = score::create("score1", nullptr);
auto pinballTable = pb::MainTable;
//pinballTable->find_component(1);
for (int i = 0; i < 190; i++)
{
auto rsc = pinball::get_rc_string(i, 0);
if (rsc)
printf("%d:\t%s\n", i, rsc);
}
//DatParser::Parse(dataFileName);
std::cout << "Goodby World!\n";
} }
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu // Run program: Ctrl + F5 or Debug > Start Without Debugging menu

View File

@ -9,6 +9,7 @@
#include "render.h" #include "render.h"
#include "TFlipperEdge.h" #include "TFlipperEdge.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h"
TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false) TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false)
{ {

View File

@ -3,6 +3,7 @@
#include "objlist_class.h" #include "objlist_class.h"
#include "pb.h" #include "pb.h"
#include "pinball.h"
#include "TBlocker.h" #include "TBlocker.h"
#include "TBumper.h" #include "TBumper.h"
#include "TComponentGroup.h" #include "TComponentGroup.h"
@ -27,6 +28,7 @@
#include "TRamp.h" #include "TRamp.h"
#include "TPlunger.h" #include "TPlunger.h"
#include "TWall.h" #include "TWall.h"
#include "TTextBox.h"
int control::pbctrl_state; int control::pbctrl_state;

View File

@ -1,11 +1,15 @@
#include "pch.h" #include "pch.h"
#include "gdrv.h" #include "gdrv.h"
#include "GroupData.h"
#include "memory.h" #include "memory.h"
#include "partman.h"
#include "pb.h"
#include "score.h"
#include "winmain.h" #include "winmain.h"
SDL_Texture* gdrv::vScreenTex = nullptr; SDL_Texture* gdrv::vScreenTex = nullptr;
char* gdrv::vScreenPixels = nullptr; ColorRgba* gdrv::vScreenPixels = nullptr;
int gdrv::vScreenWidth, gdrv::vScreenHeight; int gdrv::vScreenWidth, gdrv::vScreenHeight;
ColorRgba gdrv::current_palette[256]{}; ColorRgba gdrv::current_palette[256]{};
SDL_Rect gdrv::DestinationRect{}; SDL_Rect gdrv::DestinationRect{};
@ -20,7 +24,7 @@ int gdrv::init(int width, int height)
SDL_TEXTUREACCESS_STREAMING, SDL_TEXTUREACCESS_STREAMING,
width, height width, height
); );
vScreenPixels = memory::allocate(width * height * 4); vScreenPixels = memory::allocate<ColorRgba>(width * height);
vScreenWidth = width; vScreenWidth = width;
vScreenHeight = height; vScreenHeight = height;
@ -38,53 +42,84 @@ void gdrv::get_focus()
{ {
} }
int gdrv::create_bitmap(gdrv_bitmap8* bmp, int width, int height) int gdrv::create_bitmap(gdrv_bitmap8* bmp, int width, int height, int stride, bool indexed)
{ {
bmp->Width = width; assertm(width >= 0 && height >= 0, "Negative bitmap8 dimensions");
bmp->Stride = width;
if (width % 4)
bmp->Stride = 4 - width % 4 + width;
bmp->Width = width;
bmp->Height = height; bmp->Height = height;
bmp->Stride = width;
bmp->BitmapType = BitmapTypes::DibBitmap; bmp->BitmapType = BitmapTypes::DibBitmap;
bmp->BmpBufPtr1 = memory::allocate(bmp->Height * bmp->Stride); bmp->Texture = nullptr;
return 0;
if (stride >= 0)
bmp->IndexedStride = stride;
else
{
bmp->IndexedStride = width;
if (width % 4)
bmp->IndexedStride = width - width % 4 + 4;
}
if (indexed)
bmp->IndexedBmpPtr = memory::allocate(bmp->Height * bmp->IndexedStride);
bmp->BmpBufPtr1 = memory::allocate<ColorRgba>(bmp->Height * bmp->Stride);
if (bmp->BmpBufPtr1)
{
return 0;
}
return -1;
} }
int gdrv::create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag) int gdrv::create_bitmap(gdrv_bitmap8& bmp, const dat8BitBmpHeader& header)
{ {
bmp->Width = width; assertm(header.Width >= 0 && header.Height >= 0, "Negative bitmap8 dimensions");
bmp->Stride = width;
if (flag && width % 4)
bmp->Stride = width - width % 4 + 4;
unsigned int sizeInBytes = height * bmp->Stride;
bmp->Height = height;
bmp->BitmapType = BitmapTypes::RawBitmap;
char* buf = memory::allocate(sizeInBytes);
bmp->BmpBufPtr1 = buf;
if (!buf)
return -1;
return 0;
}
int gdrv::create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size) if (header.IsFlagSet(bmp8Flags::Spliced))
{ bmp.BitmapType = BitmapTypes::Spliced;
bmp->Width = width; else if (header.IsFlagSet(bmp8Flags::DibBitmap))
bmp->Stride = width; bmp.BitmapType = BitmapTypes::DibBitmap;
bmp->BitmapType = BitmapTypes::Spliced; else
bmp->Height = height; bmp.BitmapType = BitmapTypes::RawBitmap;
char* buf = memory::allocate(size);
bmp->BmpBufPtr1 = buf; bmp.Width = header.Width;
if (!buf) bmp.Stride = header.Width;
return -1; bmp.IndexedStride = header.Width;
return 0; bmp.Height = header.Height;
bmp.XPosition = header.XPosition;
bmp.YPosition = header.YPosition;
bmp.Resolution = header.Resolution;
bmp.Texture = nullptr;
int sizeInBytes;
if (bmp.BitmapType == BitmapTypes::Spliced)
{
sizeInBytes = header.Size;
}
else
{
if (bmp.BitmapType == BitmapTypes::RawBitmap)
assertm(bmp.Width % 4 == 0 || header.IsFlagSet(bmp8Flags::RawBmpUnaligned), "Wrong raw bitmap align flag");
if (bmp.Width % 4)
bmp.IndexedStride = bmp.Width - bmp.Width % 4 + 4;
sizeInBytes = bmp.Height * bmp.IndexedStride;
assertm(sizeInBytes == header.Size, "Wrong bitmap8 size");
}
bmp.IndexedBmpPtr = memory::allocate(sizeInBytes);
bmp.BmpBufPtr1 = memory::allocate<ColorRgba>(bmp.Stride * bmp.Height);
if (bmp.BmpBufPtr1)
{
return 0;
}
return -1;
} }
int gdrv::display_palette(ColorRgba* plt) int gdrv::display_palette(ColorRgba* plt)
{ {
const uint32_t sysPaletteColors[] const uint32_t sysPaletteColors[]
{ {
0x00000000, 0x00000000, // Color 0: transparent
0x00000080, 0x00000080,
0x00008000, 0x00008000,
0x00008080, 0x00008080,
@ -122,6 +157,19 @@ int gdrv::display_palette(ColorRgba* plt)
current_palette[255].rgba.peGreen = -1; current_palette[255].rgba.peGreen = -1;
current_palette[255].rgba.peRed = -1; current_palette[255].rgba.peRed = -1;
score::ApplyPalette();
for (const auto group : pb::record_table->Groups)
{
for (int i = 0; i <= 2; i++)
{
auto bmp = group->GetBitmap(i);
if (bmp)
{
ApplyPalette(*bmp);
}
}
}
return 0; return 0;
} }
@ -134,6 +182,10 @@ int gdrv::destroy_bitmap(gdrv_bitmap8* bmp)
if (bmp->BitmapType != BitmapTypes::None) if (bmp->BitmapType != BitmapTypes::None)
{ {
memory::free(bmp->BmpBufPtr1); memory::free(bmp->BmpBufPtr1);
if (bmp->IndexedBmpPtr)
memory::free(bmp->IndexedBmpPtr);
if (bmp->Texture)
SDL_DestroyTexture(bmp->Texture);
} }
memset(bmp, 0, sizeof(gdrv_bitmap8)); memset(bmp, 0, sizeof(gdrv_bitmap8));
return 0; return 0;
@ -151,7 +203,7 @@ void gdrv::blit(gdrv_bitmap8* bmp, int xSrc, int ySrc, int xDest, int yDest, int
{ {
StretchDIBitsScaled( StretchDIBitsScaled(
xSrc, xSrc,
ySrc , ySrc,
xDest, xDest,
yDest, yDest,
width, width,
@ -173,51 +225,43 @@ void gdrv::blat(gdrv_bitmap8* bmp, int xDest, int yDest)
); );
} }
void gdrv::fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, char fillChar) void gdrv::fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, uint8_t fillChar)
{ {
int bmpHeight = bmp->Height; auto color = current_palette[fillChar];
if (bmpHeight < 0) auto bmpPtr = &bmp->BmpBufPtr1[bmp->Width * yOff + xOff];
bmpHeight = -bmpHeight;
char* bmpPtr = &bmp->BmpBufPtr1[bmp->Width * (bmpHeight - height - yOff) + xOff];
for (; height > 0; --height) for (; height > 0; --height)
{ {
if (width > 0) for (int x = width; x > 0; --x)
memset(bmpPtr, fillChar, width); *bmpPtr++ = color;
bmpPtr += bmp->Stride; bmpPtr += bmp->Stride - width;
} }
} }
void gdrv::copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp, void gdrv::copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp,
int srcXOff, int srcYOff) int srcXOff, int srcYOff)
{ {
int dstHeight = abs(dstBmp->Height); auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcYOff + srcXOff];
int srcHeight = abs(srcBmp->Height); auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * yOff + xOff];
char* srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeight - height - srcYOff) + srcXOff];
char* dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeight - height - yOff) + xOff];
for (int y = height; y > 0; --y) for (int y = height; y > 0; --y)
{ {
for (int x = width; x > 0; --x) std::memcpy(dstPtr, srcPtr, width * sizeof(ColorRgba));
*dstPtr++ = *srcPtr++; srcPtr += srcBmp->Stride;
dstPtr += dstBmp->Stride;
srcPtr += srcBmp->Stride - width;
dstPtr += dstBmp->Stride - width;
} }
} }
void gdrv::copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, void gdrv::copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff,
gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff) gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff)
{ {
int dstHeight = abs(dstBmp->Height); auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcYOff + srcXOff];
int srcHeight = abs(srcBmp->Height); auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * yOff + xOff];
char* srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeight - height - srcYOff) + srcXOff];
char* dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeight - height - yOff) + xOff];
for (int y = height; y > 0; --y) for (int y = height; y > 0; --y)
{ {
for (int x = width; x > 0; --x) for (int x = width; x > 0; --x)
{ {
if (*srcPtr) if ((*srcPtr).Color)
*dstPtr = *srcPtr; *dstPtr = *srcPtr;
++srcPtr; ++srcPtr;
++dstPtr; ++dstPtr;
@ -230,19 +274,15 @@ void gdrv::copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int heigh
void gdrv::grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6) void gdrv::grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6)
{ {
} }
int gdrv::StretchDIBitsScaled(int xSrc, int ySrc, int xDst, int yDst, int gdrv::StretchDIBitsScaled(int xSrc, int ySrc, int xDst, int yDst,
int width, int height, gdrv_bitmap8* bmp) int width, int height, gdrv_bitmap8* bmp)
{ {
// Y is inverted, X normal left to right
ySrc = std::max(0, std::min(bmp->Height - height, bmp->Height)) - ySrc;
yDst = std::max(0, std::min(vScreenHeight - height, vScreenHeight)) - yDst;
// Negative dst == positive src offset // Negative dst == positive src offset
if (xDst < 0) if (xDst < 0)
{ {
xSrc -= xDst; xSrc -= xDst;
xDst = 0; xDst = 0;
} }
@ -258,27 +298,22 @@ int gdrv::StretchDIBitsScaled(int xSrc, int ySrc, int xDst, int yDst,
if (xSrc + width > bmp->Width) if (xSrc + width > bmp->Width)
width = bmp->Width - xSrc; width = bmp->Width - xSrc;
if (ySrc + height > bmp->Height) if (ySrc + height > bmp->Height)
height = bmp->Height - ySrc; height = bmp->Height - ySrc;
xDst = std::max(0, std::min(xDst, vScreenWidth)); xDst = std::max(0, std::min(xDst, vScreenWidth));
yDst = std::max(0, std::min(yDst, vScreenHeight)); yDst = std::max(0, std::min(yDst, vScreenHeight));
if (xDst + width > vScreenWidth) if (xDst + width > vScreenWidth)
width = vScreenWidth - xDst; width = vScreenWidth - xDst;
if (yDst + height > vScreenHeight) if (yDst + height > vScreenHeight)
height = vScreenHeight - yDst; height = vScreenHeight - yDst;
auto srcPtr = reinterpret_cast<uint8_t*>(&bmp->BmpBufPtr1[bmp->Stride * ySrc + xSrc]); auto srcPtr = &bmp->BmpBufPtr1[bmp->Stride * ySrc + xSrc];
auto dstPtr = &reinterpret_cast<uint32_t*>(vScreenPixels)[vScreenWidth * yDst + xDst]; auto dstPtr = &vScreenPixels[vScreenWidth * yDst + xDst];
for (int y = height; y > 0; --y) for (int y = height; y > 0; --y)
{ {
for (int x = width; x > 0; --x) std::memcpy(dstPtr, srcPtr, width * sizeof(ColorRgba));
{ srcPtr += bmp->Stride;
dstPtr += vScreenWidth;
*dstPtr++ = current_palette[*srcPtr++].Color;
}
srcPtr += bmp->Stride - width;
dstPtr += vScreenWidth - width;
} }
return 0; return 0;
@ -297,5 +332,41 @@ void gdrv::BlitScreen()
); );
std::memcpy(lockedPixels, vScreenPixels, vScreenWidth * vScreenHeight * 4); std::memcpy(lockedPixels, vScreenPixels, vScreenWidth * vScreenHeight * 4);
SDL_UnlockTexture(vScreenTex); SDL_UnlockTexture(vScreenTex);
SDL_RenderCopyEx(winmain::Renderer, vScreenTex, nullptr, &DestinationRect, 0, nullptr, SDL_FLIP_VERTICAL); SDL_RenderCopyEx(winmain::Renderer, vScreenTex, nullptr, &DestinationRect, 0, nullptr, SDL_FLIP_NONE);
}
void gdrv::ApplyPalette(gdrv_bitmap8& bmp)
{
if (bmp.BitmapType == BitmapTypes::None)
return;
assertm(bmp.BitmapType != BitmapTypes::Spliced, "gdrv: wrong bitmap type");
assertm(bmp.IndexedBmpPtr != nullptr, "gdrv: non-indexed bitmap");
// Apply palette, flip horizontally
auto dst = bmp.BmpBufPtr1;
for (auto y = bmp.Height - 1; y >= 0; y--)
{
auto src = reinterpret_cast<uint8_t*>(bmp.IndexedBmpPtr) + bmp.IndexedStride * y;
for (auto x = 0; x < bmp.Width; x++)
{
*dst++ = current_palette[*src++];
}
}
}
void gdrv::CreatePreview(gdrv_bitmap8& bmp)
{
if (bmp.Texture)
return;
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
auto texture = SDL_CreateTexture
(
winmain::Renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
bmp.Width, bmp.Height
);
SDL_UpdateTexture(texture, nullptr, bmp.BmpBufPtr1, bmp.Width * 4);
bmp.Texture = texture;
} }

View File

@ -1,23 +1,13 @@
#pragma once #pragma once
enum class BitmapTypes : char enum class BitmapTypes : uint8_t
{ {
None = 0, None = 0,
RawBitmap = 1, RawBitmap = 1,
DibBitmap = 2, DibBitmap = 2,
Spliced = 4, Spliced = 3,
}; };
struct gdrv_bitmap8
{
char* BmpBufPtr1;
int Width;
int Height;
int Stride;
BitmapTypes BitmapType;
int XPosition;
int YPosition;
};
struct Rgba struct Rgba
{ {
@ -26,13 +16,43 @@ struct Rgba
uint8_t peBlue; uint8_t peBlue;
uint8_t peFlags; uint8_t peFlags;
}; };
union ColorRgba union ColorRgba
{ {
ColorRgba() = default;
explicit ColorRgba(uint32_t color)
: Color(color)
{
}
explicit ColorRgba(Rgba rgba)
: rgba(rgba)
{
}
uint32_t Color; uint32_t Color;
Rgba rgba; Rgba rgba;
}; };
static_assert(sizeof(ColorRgba) == 4, "Wrong size of RGBA color"); static_assert(sizeof(ColorRgba) == 4, "Wrong size of RGBA color");
struct gdrv_bitmap8
{
ColorRgba* BmpBufPtr1;
char* IndexedBmpPtr;
int Width;
int Height;
int Stride;
int IndexedStride;
BitmapTypes BitmapType;
int XPosition;
int YPosition;
unsigned Resolution;
//ColorRgba* RgbaBuffer;
SDL_Texture* Texture;
};
class gdrv class gdrv
{ {
@ -42,25 +62,26 @@ public:
static int init(int width, int height); static int init(int width, int height);
static int uninit(); static int uninit();
static void get_focus(); static void get_focus();
static int create_bitmap(gdrv_bitmap8* bmp, int width, int height); static int create_bitmap(gdrv_bitmap8* bmp, int width, int height, int stride = -1, bool indexed = true);
static int create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag); static int create_bitmap(gdrv_bitmap8& bmp, const struct dat8BitBmpHeader& header);
static int create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size);
static int destroy_bitmap(gdrv_bitmap8* bmp); static int destroy_bitmap(gdrv_bitmap8* bmp);
static int display_palette(ColorRgba* plt); static int display_palette(ColorRgba* plt);
static void start_blit_sequence(); static void start_blit_sequence();
static void end_blit_sequence(); static void end_blit_sequence();
static void blit(gdrv_bitmap8* bmp, int xSrc, int ySrc, int xDest, int yDest, int width, int height); static void blit(gdrv_bitmap8* bmp, int xSrc, int ySrc, int xDest, int yDest, int width, int height);
static void blat(gdrv_bitmap8* bmp, int xDest, int yDest); static void blat(gdrv_bitmap8* bmp, int xDest, int yDest);
static void fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, char fillChar); static void fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, uint8_t fillChar);
static void copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp, static void copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp,
int srcXOff, int srcYOff); int srcXOff, int srcYOff);
static void copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, static void copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff,
gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff); gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff);
static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6); static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6);
static void BlitScreen(); static void BlitScreen();
static void ApplyPalette(gdrv_bitmap8& bmp);
static void CreatePreview(gdrv_bitmap8& bmp);
private: private:
static SDL_Texture* vScreenTex; static SDL_Texture* vScreenTex;
static char* vScreenPixels; static ColorRgba* vScreenPixels;
static int vScreenWidth, vScreenHeight; static int vScreenWidth, vScreenHeight;
static ColorRgba current_palette[256]; static ColorRgba current_palette[256];

View File

@ -3,6 +3,8 @@
#include "memory.h" #include "memory.h"
#include "options.h" #include "options.h"
#include "pinball.h"
#include "score.h"
int high_score::dlg_enter_name; int high_score::dlg_enter_name;
int high_score::dlg_score; int high_score::dlg_score;

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "pinball.h"
struct high_score_struct struct high_score_struct
{ {

View File

@ -1,7 +1,7 @@
#include "pch.h" #include "pch.h"
#include "loader.h" #include "loader.h"
#include "memory.h" #include "memory.h"
#include "partman.h" #include "GroupData.h"
#include "pb.h" #include "pb.h"
#include "pinball.h" #include "pinball.h"
#include "Sound.h" #include "Sound.h"
@ -12,7 +12,7 @@ errorMsg loader::loader_errors[] =
{ {
errorMsg{0, "Bad Handle"}, errorMsg{0, "Bad Handle"},
errorMsg{1, "No Type Field"}, errorMsg{1, "No Type Field"},
errorMsg{2, "No Attributes Field"}, errorMsg{2, "No Attributes Field"},
errorMsg{3, "Wrong Type: MATERIAL Expected"}, errorMsg{3, "Wrong Type: MATERIAL Expected"},
errorMsg{4, "Wrong Type: KICKER Expected"}, errorMsg{4, "Wrong Type: KICKER Expected"},
errorMsg{5, "Wrong Type: AN_OBJECT Expected"}, errorMsg{5, "Wrong Type: AN_OBJECT Expected"},
@ -42,8 +42,8 @@ errorMsg loader::loader_errors[] =
int loader::sound_count = 1; int loader::sound_count = 1;
int loader::loader_sound_count; int loader::loader_sound_count;
datFileStruct* loader::loader_table; DatFile* loader::loader_table;
datFileStruct* loader::sound_record_table; DatFile* loader::sound_record_table;
soundListStruct loader::sound_list[65]; soundListStruct loader::sound_list[65];
int loader::error(int errorCode, int captionCode) int loader::error(int errorCode, int captionCode)
@ -82,14 +82,14 @@ void loader::default_vsi(visualStruct* visual)
visual->SoundIndex4 = 0; visual->SoundIndex4 = 0;
} }
void loader::loadfrom(datFileStruct* datFile) void loader::loadfrom(DatFile* datFile)
{ {
loader_table = datFile; loader_table = datFile;
sound_record_table = loader_table; sound_record_table = loader_table;
for (auto groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex) for (auto groupIndex = 0; groupIndex < datFile->Groups.size(); ++groupIndex)
{ {
auto value = reinterpret_cast<int16_t*>(partman::field(datFile, groupIndex, datFieldTypes::ShortValue)); auto value = reinterpret_cast<int16_t*>(datFile->field(groupIndex, FieldTypes::ShortValue));
if (value && *value == 202) if (value && *value == 202)
{ {
if (sound_count < 65) if (sound_count < 65)
@ -136,26 +136,27 @@ int loader::get_sound_id(int groupIndex)
if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr) if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr)
{ {
WaveHeader wavHeader{}; WaveHeader wavHeader{};
int soundGroupId = sound_list[soundIndex].GroupIndex; int soundGroupId = sound_list[soundIndex].GroupIndex;
sound_list[soundIndex].Duration = 0.0; sound_list[soundIndex].Duration = 0.0;
if (soundGroupId > 0 && !pinball::quickFlag) if (soundGroupId > 0 && !pinball::quickFlag)
{ {
auto value = reinterpret_cast<int16_t*>(partman::field(loader_table, soundGroupId, auto value = reinterpret_cast<int16_t*>(loader_table->field(soundGroupId,
datFieldTypes::ShortValue)); FieldTypes::ShortValue));
if (value && *value == 202) if (value && *value == 202)
{ {
std::string fileName = partman::field(loader_table, soundGroupId, datFieldTypes::String); std::string fileName = loader_table->field(soundGroupId, FieldTypes::String);
// File name is in lower case, while game data is in upper case. // File name is in lower case, while game data is in upper case.
std::transform(fileName.begin(), fileName.end(), fileName.begin(), [](unsigned char c) { return std::toupper(c); }); std::transform(fileName.begin(), fileName.end(), fileName.begin(),
[](unsigned char c) { return std::toupper(c); });
if (pb::FullTiltMode) if (pb::FullTiltMode)
{ {
// FT sounds are in SOUND subfolder // FT sounds are in SOUND subfolder
fileName.insert(0, 1, PathSeparator); fileName.insert(0, 1, PathSeparator);
fileName.insert(0, "SOUND"); fileName.insert(0, "SOUND");
} }
auto filePath = pinball::make_path_name(fileName); auto filePath = pinball::make_path_name(fileName);
auto file = fopen(filePath.c_str(), "rb"); auto file = fopen(filePath.c_str(), "rb");
if (file) if (file)
@ -163,7 +164,7 @@ int loader::get_sound_id(int groupIndex)
fread(&wavHeader, 1, sizeof wavHeader, file); fread(&wavHeader, 1, sizeof wavHeader, file);
fclose(file); fclose(file);
} }
auto sampleCount = wavHeader.data_size / (wavHeader.channels * (wavHeader.bits_per_sample / 8.0)); auto sampleCount = wavHeader.data_size / (wavHeader.channels * (wavHeader.bits_per_sample / 8.0));
sound_list[soundIndex].Duration = static_cast<float>(sampleCount / wavHeader.sample_rate); sound_list[soundIndex].Duration = static_cast<float>(sampleCount / wavHeader.sample_rate);
sound_list[soundIndex].WavePtr = Sound::LoadWaveFile(filePath); sound_list[soundIndex].WavePtr = Sound::LoadWaveFile(filePath);
@ -178,7 +179,7 @@ int loader::get_sound_id(int groupIndex)
int loader::query_handle(LPCSTR lpString) int loader::query_handle(LPCSTR lpString)
{ {
return partman::record_labeled(loader_table, lpString); return loader_table->record_labeled(lpString);
} }
short loader::query_visual_states(int groupIndex) short loader::query_visual_states(int groupIndex)
@ -186,7 +187,7 @@ short loader::query_visual_states(int groupIndex)
short result; short result;
if (groupIndex < 0) if (groupIndex < 0)
return error(0, 17); return error(0, 17);
auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortArray)); auto shortArr = reinterpret_cast<int16_t*>(loader_table->field(groupIndex, FieldTypes::ShortArray));
if (shortArr && *shortArr == 100) if (shortArr && *shortArr == 100)
result = shortArr[1]; result = shortArr[1];
else else
@ -202,7 +203,7 @@ char* loader::query_name(int groupIndex)
return nullptr; return nullptr;
} }
return partman::field(loader_table, groupIndex, datFieldTypes::GroupName); return loader_table->field(groupIndex, FieldTypes::GroupName);
} }
int16_t* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize) int16_t* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize)
@ -215,13 +216,13 @@ int16_t* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize
for (auto skipIndex = 0;; ++skipIndex) for (auto skipIndex = 0;; ++skipIndex)
{ {
auto shortArr = reinterpret_cast<int16_t*>(partman::field_nth(loader_table, groupIndex, auto shortArr = reinterpret_cast<int16_t*>(loader_table->field_nth(groupIndex,
datFieldTypes::ShortArray, skipIndex)); FieldTypes::ShortArray, skipIndex));
if (!shortArr) if (!shortArr)
break; break;
if (*shortArr == firstValue) if (*shortArr == firstValue)
{ {
*arraySize = partman::field_size(loader_table, groupIndex, datFieldTypes::ShortArray) / 2 - 1; *arraySize = loader_table->field_size(groupIndex, FieldTypes::ShortArray) / 2 - 1;
return shortArr + 1; return shortArr + 1;
} }
} }
@ -248,8 +249,8 @@ float* loader::query_float_attribute(int groupIndex, int groupIndexOffset, int f
for (auto skipIndex = 0;; ++skipIndex) for (auto skipIndex = 0;; ++skipIndex)
{ {
auto floatArr = reinterpret_cast<float*>(partman::field_nth(loader_table, stateId, datFieldTypes::FloatArray, auto floatArr = reinterpret_cast<float*>(loader_table->field_nth(stateId, FieldTypes::FloatArray,
skipIndex)); skipIndex));
if (!floatArr) if (!floatArr)
break; break;
if (static_cast<int16_t>(floor(*floatArr)) == firstValue) if (static_cast<int16_t>(floor(*floatArr)) == firstValue)
@ -277,8 +278,8 @@ float loader::query_float_attribute(int groupIndex, int groupIndexOffset, int fi
for (auto skipIndex = 0;; ++skipIndex) for (auto skipIndex = 0;; ++skipIndex)
{ {
auto floatArr = reinterpret_cast<float*>(partman::field_nth(loader_table, stateId, auto floatArr = reinterpret_cast<float*>(loader_table->field_nth(stateId,
datFieldTypes::FloatArray, skipIndex)); FieldTypes::FloatArray, skipIndex));
if (!floatArr) if (!floatArr)
break; break;
if (static_cast<int16_t>(floor(*floatArr)) == firstValue) if (static_cast<int16_t>(floor(*floatArr)) == firstValue)
@ -295,16 +296,16 @@ int loader::material(int groupIndex, visualStruct* visual)
{ {
if (groupIndex < 0) if (groupIndex < 0)
return error(0, 21); return error(0, 21);
auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); auto shortArr = reinterpret_cast<int16_t*>(loader_table->field(groupIndex, FieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 21); return error(1, 21);
if (*shortArr != 300) if (*shortArr != 300)
return error(3, 21); return error(3, 21);
auto floatArr = reinterpret_cast<float*>(partman::field(loader_table, groupIndex, datFieldTypes::FloatArray)); auto floatArr = reinterpret_cast<float*>(loader_table->field(groupIndex, FieldTypes::FloatArray));
if (!floatArr) if (!floatArr)
return error(11, 21); return error(11, 21);
int floatArrLength = partman::field_size(loader_table, groupIndex, datFieldTypes::FloatArray) / 4; int floatArrLength = loader_table->field_size(groupIndex, FieldTypes::FloatArray) / 4;
for (auto index = 0; index < floatArrLength; index += 2) for (auto index = 0; index < floatArrLength; index += 2)
{ {
switch (static_cast<int>(floor(floatArr[index]))) switch (static_cast<int>(floor(floatArr[index])))
@ -339,7 +340,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset)
auto visualState = query_visual_states(groupIndex); auto visualState = query_visual_states(groupIndex);
if (visualState <= 0) if (visualState <= 0)
return error(12, 24); return error(12, 24);
auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); auto shortArr = reinterpret_cast<int16_t*>(loader_table->field(groupIndex, FieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 24); return error(1, 24);
if (*shortArr != 200) if (*shortArr != 200)
@ -350,7 +351,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset)
return groupIndex; return groupIndex;
groupIndex += groupIndexOffset; groupIndex += groupIndexOffset;
shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); shortArr = reinterpret_cast<int16_t*>(loader_table->field(groupIndex, FieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 24); return error(1, 24);
if (*shortArr != 201) if (*shortArr != 201)
@ -362,15 +363,15 @@ int loader::kicker(int groupIndex, visualKickerStruct* kicker)
{ {
if (groupIndex < 0) if (groupIndex < 0)
return error(0, 20); return error(0, 20);
auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); auto shortArr = reinterpret_cast<int16_t*>(loader_table->field(groupIndex, FieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 20); return error(1, 20);
if (*shortArr != 400) if (*shortArr != 400)
return error(4, 20); return error(4, 20);
auto floatArr = reinterpret_cast<float*>(partman::field(loader_table, groupIndex, datFieldTypes::FloatArray)); auto floatArr = reinterpret_cast<float*>(loader_table->field(groupIndex, FieldTypes::FloatArray));
if (!floatArr) if (!floatArr)
return error(11, 20); return error(11, 20);
int floatArrLength = partman::field_size(loader_table, groupIndex, datFieldTypes::FloatArray) / 4; int floatArrLength = loader_table->field_size(groupIndex, FieldTypes::FloatArray) / 4;
if (floatArrLength <= 0) if (floatArrLength <= 0)
return 0; return 0;
@ -421,19 +422,13 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vis
if (stateId < 0) if (stateId < 0)
return error(16, 18); return error(16, 18);
visual->Bitmap = reinterpret_cast<gdrv_bitmap8*>(partman::field(loader_table, stateId, datFieldTypes::Bitmap8bit)); visual->Bitmap = loader_table->GetBitmap(stateId);
visual->ZMap = reinterpret_cast<zmap_header_type*>(partman::field(loader_table, stateId, datFieldTypes::Bitmap16bit) visual->ZMap = loader_table->GetZMap(stateId);
);
if (visual->ZMap)
{
visual->ZMap->ZPtr1 = visual->ZMap->ZBuffer;
visual->ZMap->ZPtr2 = visual->ZMap->ZPtr1;
}
auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, stateId, datFieldTypes::ShortArray)); auto shortArr = reinterpret_cast<int16_t*>(loader_table->field(stateId, FieldTypes::ShortArray));
if (shortArr) if (shortArr)
{ {
unsigned int shortArrSize = partman::field_size(loader_table, stateId, datFieldTypes::ShortArray); unsigned int shortArrSize = loader_table->field_size(stateId, FieldTypes::ShortArray);
for (auto index = 0u; index < shortArrSize / 2;) for (auto index = 0u; index < shortArrSize / 2;)
{ {
switch (shortArr[0]) switch (shortArr[0])
@ -479,13 +474,13 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vis
if (!visual->CollisionGroup) if (!visual->CollisionGroup)
visual->CollisionGroup = 1; visual->CollisionGroup = 1;
auto floatArr = reinterpret_cast<float*>(partman::field(loader_table, stateId, datFieldTypes::FloatArray)); auto floatArr = reinterpret_cast<float*>(loader_table->field(stateId, FieldTypes::FloatArray));
if (!floatArr) if (!floatArr)
return 0; return 0;
if (*floatArr != 600.0f) if (*floatArr != 600.0f)
return 0; return 0;
visual->FloatArrCount = partman::field_size(loader_table, stateId, datFieldTypes::FloatArray) / 4 / 2 - 2; visual->FloatArrCount = loader_table->field_size(stateId, FieldTypes::FloatArray) / 4 / 2 - 2;
auto floatVal = static_cast<int>(floor(floatArr[1]) - 1.0f); auto floatVal = static_cast<int>(floor(floatArr[1]) - 1.0f);
switch (floatVal) switch (floatVal)
{ {

View File

@ -4,7 +4,7 @@
#include "zdrv.h" #include "zdrv.h"
struct datFileStruct; struct DatFile;
struct errorMsg struct errorMsg
{ {
@ -89,7 +89,7 @@ public:
static void default_vsi(visualStruct* visual); static void default_vsi(visualStruct* visual);
static int get_sound_id(int groupIndex); static int get_sound_id(int groupIndex);
static void unload(); static void unload();
static void loadfrom(datFileStruct* datFile); static void loadfrom(DatFile* datFile);
static int query_handle(LPCSTR lpString); static int query_handle(LPCSTR lpString);
static short query_visual_states(int groupIndex); static short query_visual_states(int groupIndex);
static int material(int groupIndex, visualStruct* visual); static int material(int groupIndex, visualStruct* visual);
@ -101,10 +101,10 @@ public:
static float query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal); static float query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal);
static int16_t* query_iattribute(int groupIndex, int firstValue, int* arraySize); static int16_t* query_iattribute(int groupIndex, int firstValue, int* arraySize);
static float play_sound(int soundIndex); static float play_sound(int soundIndex);
static datFileStruct* loader_table; static DatFile* loader_table;
private: private:
static errorMsg loader_errors[]; static errorMsg loader_errors[];
static datFileStruct* sound_record_table; static DatFile* sound_record_table;
static int sound_count; static int sound_count;
static int loader_sound_count; static int loader_sound_count;
static soundListStruct sound_list[65]; static soundListStruct sound_list[65];

View File

@ -7,6 +7,7 @@
#include "render.h" #include "render.h"
#include "TBall.h" #include "TBall.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h"
int nudge::nudged_left; int nudge::nudged_left;
int nudge::nudged_right; int nudge::nudged_right;

View File

@ -5,6 +5,7 @@
#include "memory.h" #include "memory.h"
#include "midi.h" #include "midi.h"
#include "pb.h" #include "pb.h"
#include "pinball.h"
#include "resource.h" #include "resource.h"
#include "Sound.h" #include "Sound.h"
#include "winmain.h" #include "winmain.h"

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "pinball.h" #include <map>
struct optionsStruct struct optionsStruct
{ {

View File

@ -1,6 +1,9 @@
#include "pch.h" #include "pch.h"
#include "partman.h" #include "partman.h"
#include "fullscrn.h"
#include "gdrv.h" #include "gdrv.h"
#include "GroupData.h"
#include "memory.h" #include "memory.h"
#include "zdrv.h" #include "zdrv.h"
@ -9,7 +12,7 @@ short partman::_field_size[] =
2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0
}; };
datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool fullTiltMode) DatFile* partman::load_records(LPCSTR lpFileName, bool fullTiltMode)
{ {
datFileHeader header{}; datFileHeader header{};
dat8BitBmpHeader bmpHeader{}; dat8BitBmpHeader bmpHeader{};
@ -18,35 +21,23 @@ datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool ful
auto fileHandle = fopen(lpFileName, "rb"); auto fileHandle = fopen(lpFileName, "rb");
if (fileHandle == nullptr) if (fileHandle == nullptr)
return nullptr; return nullptr;
fread(&header, 1, sizeof header, fileHandle); fread(&header, 1, sizeof header, fileHandle);
if (strcmp("PARTOUT(4.0)RESOURCE", header.FileSignature) != 0) if (strcmp("PARTOUT(4.0)RESOURCE", header.FileSignature) != 0)
{ {
fclose(fileHandle); fclose(fileHandle);
return nullptr; return nullptr;
} }
auto datFile = memory::allocate<datFileStruct>();
auto datFile = new DatFile();
if (!datFile) if (!datFile)
{ {
fclose(fileHandle); fclose(fileHandle);
return nullptr; return nullptr;
} }
if (strlen(header.Description) <= 0)
{ datFile->AppName = header.AppName;
datFile->Description = nullptr; datFile->Description = header.Description;
}
else
{
auto lenOfStr = strlen(header.Description);
auto descriptionBuf = memory::allocate(lenOfStr + 1);
datFile->Description = descriptionBuf;
if (!descriptionBuf)
{
fclose(fileHandle);
memory::free(datFile);
return nullptr;
}
strncpy(descriptionBuf, header.Description, lenOfStr + 1);
}
if (header.Unknown) if (header.Unknown)
{ {
@ -54,102 +45,75 @@ datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool ful
if (!unknownBuf) if (!unknownBuf)
{ {
fclose(fileHandle); fclose(fileHandle);
if (datFile->Description) delete datFile;
memory::free(datFile->Description);
memory::free(datFile);
return nullptr; return nullptr;
} }
fread(unknownBuf, 1, header.Unknown, fileHandle); fread(unknownBuf, 1, header.Unknown, fileHandle);
memory::free(unknownBuf); memory::free(unknownBuf);
} }
auto groupDataBuf = memory::allocate<datGroupData*>(header.NumberOfGroups); datFile->Groups.reserve(header.NumberOfGroups);
datFile->GroupData = groupDataBuf;
if (!groupDataBuf)
{
if (datFile->Description)
memory::free(datFile->Description);
memory::free(datFile);
return nullptr;
}
bool abort = false; bool abort = false;
for (auto groupIndex = 0; !abort && groupIndex < header.NumberOfGroups; ++groupIndex) for (auto groupIndex = 0; !abort && groupIndex < header.NumberOfGroups; ++groupIndex)
{ {
auto entryCount = _lread_char(fileHandle); auto entryCount = _lread_char(fileHandle);
auto groupDataSize = entryCount <= 0 ? 0 : entryCount - 1; auto groupData = new GroupData(groupIndex);
auto groupData = memory::allocate<datGroupData>(1, sizeof(datEntryData) * groupDataSize); groupData->ReserveEntries(entryCount);
datFile->GroupData[groupIndex] = groupData;
if (!groupData)
break;
groupData->EntryCount = 0;
for (auto entryIndex = 0; entryIndex < entryCount; ++entryIndex) for (auto entryIndex = 0; entryIndex < entryCount; ++entryIndex)
{ {
auto entryData = &groupData->Entries[groupData->EntryCount]; auto entryData = new EntryData();
auto entryType = static_cast<datFieldTypes>(_lread_char(fileHandle)); auto entryType = static_cast<FieldTypes>(_lread_char(fileHandle));
entryData->EntryType = entryType; entryData->EntryType = entryType;
int fieldSize = _field_size[static_cast<int>(entryType)]; int fieldSize = _field_size[static_cast<int>(entryType)];
if (fieldSize < 0) if (fieldSize < 0)
fieldSize = _lread_long(fileHandle); fieldSize = _lread_long(fileHandle);
entryData->FieldSize = fieldSize;
if (entryType == datFieldTypes::Bitmap8bit) if (entryType == FieldTypes::Bitmap8bit)
{ {
fread(&bmpHeader, 1, sizeof(dat8BitBmpHeader), fileHandle); fread(&bmpHeader, 1, sizeof(dat8BitBmpHeader), fileHandle);
if (bmpHeader.Resolution != resolution && bmpHeader.Resolution != -1) assertm(bmpHeader.Size + sizeof(dat8BitBmpHeader) == fieldSize, "partman: Wrong bitmap field size");
{ assertm(bmpHeader.Resolution >= 0 && bmpHeader.Resolution <= 2,
fseek(fileHandle, bmpHeader.Size, SEEK_CUR); "partman: bitmap resolution out of bounds");
continue;
}
auto bmp = memory::allocate<gdrv_bitmap8>(); auto bmp = memory::allocate<gdrv_bitmap8>();
entryData->Buffer = reinterpret_cast<char*>(bmp); entryData->Buffer = reinterpret_cast<char*>(bmp);
if (!bmp) if (!bmp || gdrv::create_bitmap(*bmp, bmpHeader))
{ {
abort = true; abort = true;
break; break;
} }
int bmpRez; fread(bmp->IndexedBmpPtr, 1, bmpHeader.Size, fileHandle);
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;
}
fread(bmp->BmpBufPtr1, 1, bmpHeader.Size, fileHandle);
bmp->XPosition = bmpHeader.XPosition;
bmp->YPosition = bmpHeader.YPosition;
} }
else if (entryType == datFieldTypes::Bitmap16bit) else if (entryType == FieldTypes::Bitmap16bit)
{ {
/*Full tilt has extra byte(@0:resolution) in zMap*/ /*Full tilt has extra byte(@0:resolution) in zMap*/
char zMapResolution = 0;
if (fullTiltMode) if (fullTiltMode)
{ {
char zMapResolution = _lread_char(fileHandle); zMapResolution = _lread_char(fileHandle);
fieldSize--; fieldSize--;
if (zMapResolution != resolution && zMapResolution != -1) assertm(zMapResolution >= 0 && zMapResolution <= 2, "partman: zMap resolution out of bounds");
{
fseek(fileHandle, fieldSize, SEEK_CUR);
continue;
}
} }
fread(&zMapHeader, 1, sizeof(dat16BitBmpHeader), fileHandle); fread(&zMapHeader, 1, sizeof(dat16BitBmpHeader), fileHandle);
int length = fieldSize - sizeof(dat16BitBmpHeader); int length = fieldSize - sizeof(dat16BitBmpHeader);
auto zmap = memory::allocate<zmap_header_type>(1, length); auto zMap = memory::allocate<zmap_header_type>();
zmap->Width = zMapHeader.Width; zdrv::create_zmap(zMap, zMapHeader.Width, zMapHeader.Height, zMapHeader.Stride);
zmap->Height = zMapHeader.Height; zMap->Resolution = zMapResolution;
zmap->Stride = zMapHeader.Stride; if (zMapHeader.Stride * zMapHeader.Height * 2 == length)
fread(zmap->ZBuffer, 1, length, fileHandle); {
entryData->Buffer = reinterpret_cast<char*>(zmap); fread(zMap->ZPtr1, 1, length, fileHandle);
}
else
{
// 3DPB .dat has zeroed zMap headers, in groups 497 and 498, skip them.
fseek(fileHandle, length, SEEK_CUR);
}
entryData->Buffer = reinterpret_cast<char*>(zMap);
} }
else else
{ {
@ -163,122 +127,19 @@ datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool ful
fread(entryBuffer, 1, fieldSize, fileHandle); fread(entryBuffer, 1, fieldSize, fileHandle);
} }
entryData->FieldSize = fieldSize; groupData->AddEntry(entryData);
groupData->EntryCount++;
} }
datFile->NumberOfGroups = groupIndex + 1;
datFile->Groups.push_back(groupData);
} }
fclose(fileHandle); fclose(fileHandle);
if (datFile->NumberOfGroups == header.NumberOfGroups) if (datFile->Groups.size() == header.NumberOfGroups)
return datFile; return datFile;
unload_records(datFile); delete datFile;
return nullptr; return nullptr;
} }
void partman::unload_records(datFileStruct* datFile)
{
for (auto groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex)
{
auto group = datFile->GroupData[groupIndex];
if (!group)
continue;
for (auto entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
{
auto entry = &group->Entries[entryIndex];
if (entry->Buffer)
{
if (entry->EntryType == datFieldTypes::Bitmap8bit)
gdrv::destroy_bitmap(reinterpret_cast<gdrv_bitmap8*>(entry->Buffer));
memory::free(entry->Buffer);
}
}
memory::free(group);
}
if (datFile->Description)
memory::free(datFile->Description);
memory::free(datFile->GroupData);
memory::free(datFile);
}
char* partman::field(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType)
{
auto group = datFile->GroupData[groupIndex];
for (auto entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
{
auto entry = &group->Entries[entryIndex];
if (entry->EntryType == targetEntryType)
return entry->Buffer;
if (entry->EntryType > targetEntryType)
break;
}
return nullptr;
}
char* partman::field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN)
{
auto group = datFile->GroupData[groupIndex];
for (auto skipCount = 0, entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
{
auto entry = &group->Entries[entryIndex];
if (entry->EntryType > targetEntryType)
break;
if (entry->EntryType == targetEntryType)
if (skipCount++ == skipFirstN)
return entry->Buffer;
}
return nullptr;
}
int partman::field_size_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN)
{
auto group = datFile->GroupData[groupIndex];
for (auto skipCount = 0, entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
{
auto entry = &group->Entries[entryIndex];
if (entry->EntryType > targetEntryType)
return 0;
if (entry->EntryType == targetEntryType)
if (skipCount++ == skipFirstN)
return entry->FieldSize;
}
return 0;
}
int partman::field_size(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType)
{
return field_size_nth(datFile, groupIndex, targetEntryType, 0);
}
int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName)
{
auto targetLength = strlen(targetGroupName);
for (int groupIndex = datFile->NumberOfGroups - 1; groupIndex >= 0; --groupIndex)
{
auto groupName = field(datFile, groupIndex, datFieldTypes::GroupName);
if (!groupName)
continue;
int index;
for (index = 0; index < targetLength; index++)
if (targetGroupName[index] != groupName[index])
break;
if (index == targetLength && !targetGroupName[index] && !groupName[index])
return groupIndex;
}
return -1;
}
char* partman::field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType)
{
auto groupIndex = record_labeled(datFile, lpString);
return groupIndex < 0 ? nullptr : field(datFile, groupIndex, fieldType);
}
char partman::_lread_char(FILE* file) char partman::_lread_char(FILE* file)
{ {
char Buffer = 0; char Buffer = 0;

View File

@ -1,29 +1,8 @@
#pragma once #pragma once
enum class datFieldTypes : int16_t struct zmap_header_type;
{ struct gdrv_bitmap8;
ShortValue = 0,
//, does not have the 32bits size value, but a 16bits value(see above).
Bitmap8bit = 1,
// 8 bpp bitmap
Unknown2 = 2,
GroupName = 3,
// Group name
Unknown4 = 4,
Palette = 5,
// Palette(1 color is 1 DWORD, only present 1 time in PINBALL.DAT ,with a data size of 1024 bytes for 256 colors.Some colors are 0 ,because their indexes are reserved by Windows.)
Unknown6 = 6,
Unknown7 = 7,
Unknown8 = 8,
String = 9,
// String(content)
ShortArray = 10,
// Array of 16bits integer values
FloatArray = 11,
// Array of 32bits floating point values(collision box, ...)
Bitmap16bit = 12,
// 16 bpp bitmap(Heightmap ? )
};
enum class bmp8Flags : unsigned char enum class bmp8Flags : unsigned char
{ {
@ -33,8 +12,7 @@ enum class bmp8Flags : unsigned char
}; };
#pragma pack(push) #pragma pack(push, 1)
#pragma pack(1)
struct datFileHeader struct datFileHeader
{ {
char FileSignature[21]; char FileSignature[21];
@ -45,34 +23,10 @@ struct datFileHeader
int SizeOfBody; int SizeOfBody;
unsigned short Unknown; unsigned short Unknown;
}; };
#pragma pack(pop)
static_assert(sizeof(datFileHeader) == 183, "Wrong size of datFileHeader");
struct datEntryData
{
datFieldTypes EntryType;
int FieldSize;
char* Buffer;
};
struct datGroupData
{
int16_t EntryCount;
datEntryData Entries[1];
};
struct datFileStruct
{
unsigned short NumberOfGroups;
char* Description;
datGroupData** GroupData;
};
#pragma pack(push)
#pragma pack(1)
struct dat8BitBmpHeader struct dat8BitBmpHeader
{ {
char Resolution; uint8_t Resolution;
int16_t Width; int16_t Width;
int16_t Height; int16_t Height;
int16_t XPosition; int16_t XPosition;
@ -80,18 +34,12 @@ struct dat8BitBmpHeader
int Size; int Size;
bmp8Flags Flags; bmp8Flags Flags;
bool IsFlagSet(bmp8Flags flag) bool IsFlagSet(bmp8Flags flag) const
{ {
return static_cast<char>(Flags) & static_cast<char>(flag); return static_cast<char>(Flags) & static_cast<char>(flag);
} }
}; };
#pragma pack(pop)
static_assert(sizeof(dat8BitBmpHeader) == 14, "Wrong size of dat8BitBmpHeader");
#pragma pack(push, 1)
struct dat16BitBmpHeader struct dat16BitBmpHeader
{ {
int16_t Width; int16_t Width;
@ -101,22 +49,17 @@ struct dat16BitBmpHeader
int16_t Unknown1_0; int16_t Unknown1_0;
int16_t Unknown1_1; int16_t Unknown1_1;
}; };
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(dat8BitBmpHeader) == 14, "Wrong size of dat8BitBmpHeader");
static_assert(sizeof(datFileHeader) == 183, "Wrong size of datFileHeader");
static_assert(sizeof(dat16BitBmpHeader) == 14, "Wrong size of zmap_header_type"); static_assert(sizeof(dat16BitBmpHeader) == 14, "Wrong size of zmap_header_type");
class partman class partman
{ {
public: public:
static datFileStruct* load_records(LPCSTR lpFileName, int resolution, bool fullTiltMode); static struct DatFile* load_records(LPCSTR lpFileName, 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);
static int field_size_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN);
static int field_size(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType);
static int record_labeled(datFileStruct* datFile, LPCSTR targetGroupName);
static char* field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType);
private: private:
static short _field_size[]; static short _field_size[];
static char _lread_char(FILE* file); static char _lread_char(FILE* file);

View File

@ -24,9 +24,14 @@
#include "TLightGroup.h" #include "TLightGroup.h"
#include "TPlunger.h" #include "TPlunger.h"
#include "TTableLayer.h" #include "TTableLayer.h"
#include "GroupData.h"
#include "partman.h"
#include "score.h"
#include "TPinballTable.h"
#include "TTextBox.h"
TPinballTable* pb::MainTable = nullptr; TPinballTable* pb::MainTable = nullptr;
datFileStruct* pb::record_table = nullptr; DatFile* pb::record_table = nullptr;
int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_; int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_;
float pb::time_now, pb::time_next, pb::ball_speed_limit; float pb::time_now, pb::time_next, pb::ball_speed_limit;
high_score_struct pb::highscore_table[5]; high_score_struct pb::highscore_table[5];
@ -39,7 +44,7 @@ int pb::init()
++memory::critical_allocation; ++memory::critical_allocation;
auto dataFilePath = pinball::make_path_name(winmain::DatFileName); auto dataFilePath = pinball::make_path_name(winmain::DatFileName);
record_table = partman::load_records(dataFilePath.c_str(), fullscrn::GetResolution(), FullTiltMode); record_table = partman::load_records(dataFilePath.c_str(), FullTiltMode);
auto useBmpFont = 0; auto useBmpFont = 0;
pinball::get_rc_int(158, &useBmpFont); pinball::get_rc_int(158, &useBmpFont);
@ -49,12 +54,12 @@ int pb::init()
if (!record_table) if (!record_table)
return 1; return 1;
auto plt = (ColorRgba*)partman::field_labeled(record_table, "background", datFieldTypes::Palette); auto plt = (ColorRgba*)record_table->field_labeled("background", FieldTypes::Palette);
gdrv::display_palette(plt); gdrv::display_palette(plt);
auto backgroundBmp = (gdrv_bitmap8*)partman::field_labeled(record_table, "background", datFieldTypes::Bitmap8bit); auto backgroundBmp = record_table->GetBitmap(record_table->record_labeled("background"));
auto cameraInfoId = partman::record_labeled(record_table, "camera_info") + fullscrn::GetResolution(); auto cameraInfoId = record_table->record_labeled("camera_info") + fullscrn::GetResolution();
auto cameraInfo = (float*)partman::field(record_table, cameraInfoId, datFieldTypes::FloatArray); auto cameraInfo = (float*)record_table->field(cameraInfoId, FieldTypes::FloatArray);
/*Full tilt: table size depends on resolution*/ /*Full tilt: table size depends on resolution*/
auto resInfo = &fullscrn::resolution_array[fullscrn::GetResolution()]; auto resInfo = &fullscrn::resolution_array[fullscrn::GetResolution()];
@ -84,7 +89,6 @@ int pb::init()
0, 0,
0); 0);
gdrv::destroy_bitmap(backgroundBmp);
loader::loadfrom(record_table); loader::loadfrom(record_table);
if (pinball::quickFlag) if (pinball::quickFlag)
@ -108,7 +112,7 @@ int pb::uninit()
{ {
score::unload_msg_font(); score::unload_msg_font();
loader::unload(); loader::unload();
partman::unload_records(record_table); delete record_table;
high_score::write(highscore_table); high_score::write(highscore_table);
if (MainTable) if (MainTable)
delete MainTable; delete MainTable;
@ -287,8 +291,8 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
ball->Acceleration.Y = ball->Speed * ball->Acceleration.Y; ball->Acceleration.Y = ball->Speed * ball->Acceleration.Y;
maths::vector_add(&ball->Acceleration, &vec2); maths::vector_add(&ball->Acceleration, &vec2);
ball->Speed = maths::normalize_2d(&ball->Acceleration); ball->Speed = maths::normalize_2d(&ball->Acceleration);
ball->InvAcceleration.X = ball->Acceleration.X == 0.0f ? 1000000000.0f : 1.0f / ball->Acceleration.X; ball->InvAcceleration.X = ball->Acceleration.X == 0.0f ? 1.0e9f : 1.0f / ball->Acceleration.X;
ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0f ? 1000000000.0f : 1.0f / ball->Acceleration.Y; ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0f ? 1.0e9f : 1.0f / ball->Acceleration.Y;
} }
auto timeDelta2 = timeDelta; auto timeDelta2 = timeDelta;

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "high_score.h" #include "high_score.h"
#include "partman.h"
#include "TPinballTable.h"
class TPinballTable;
class DatFile;
class TBall; class TBall;
class pb class pb
@ -11,7 +11,7 @@ public:
static int time_ticks; static int time_ticks;
static float ball_speed_limit, time_now, time_next; static float ball_speed_limit, time_now, time_next;
static int cheat_mode, game_mode; static int cheat_mode, game_mode;
static datFileStruct* record_table; static DatFile* record_table;
static TPinballTable* MainTable; static TPinballTable* MainTable;
static high_score_struct highscore_table[5]; static high_score_struct highscore_table[5];
static bool FullTiltMode; static bool FullTiltMode;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "TTextBox.h"
class TTextBox;
class pinball class pinball
{ {

View File

@ -1,6 +1,9 @@
#include "pch.h" #include "pch.h"
#include "render.h" #include "render.h"
#include "GroupData.h"
#include "memory.h" #include "memory.h"
#include "pb.h"
int render::blit = 0; int render::blit = 0;
int render::many_dirty, render::many_sprites, render::many_balls; int render::many_dirty, render::many_sprites, render::many_balls;
@ -21,7 +24,7 @@ void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int h
sprite_list = memory::allocate<render_sprite_type_struct*>(1000); sprite_list = memory::allocate<render_sprite_type_struct*>(1000);
dirty_list = memory::allocate<render_sprite_type_struct*>(1000); dirty_list = memory::allocate<render_sprite_type_struct*>(1000);
ball_list = memory::allocate<render_sprite_type_struct*>(20); ball_list = memory::allocate<render_sprite_type_struct*>(20);
gdrv::create_bitmap(&vscreen, width, height); gdrv::create_bitmap(&vscreen, width, height, width, false);
zdrv::create_zmap(&zscreen, width, height); zdrv::create_zmap(&zscreen, width, height);
zdrv::fill(&zscreen, zscreen.Width, zscreen.Height, 0, 0, 0xFFFF); zdrv::fill(&zscreen, zscreen.Width, zscreen.Height, 0, 0, 0xFFFF);
vscreen_rect.YPosition = 0; vscreen_rect.YPosition = 0;
@ -33,7 +36,7 @@ void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int h
gdrv_bitmap8* ballBmp = ball_bitmap; gdrv_bitmap8* ballBmp = ball_bitmap;
while (ballBmp < &ball_bitmap[20]) while (ballBmp < &ball_bitmap[20])
{ {
gdrv::create_raw_bitmap(ballBmp, 64, 64, 1); gdrv::create_bitmap(ballBmp, 64, 64, 64, false);
++ballBmp; ++ballBmp;
} }
background_bitmap = bmp; background_bitmap = bmp;
@ -473,7 +476,7 @@ void render::paint_balls()
void render::unpaint_balls() void render::unpaint_balls()
{ {
for (int index = many_balls-1; index >= 0; index--) for (int index = many_balls - 1; index >= 0; index--)
{ {
auto curBall = ball_list[index]; auto curBall = ball_list[index];
if (curBall->DirtyRect.Width > 0) if (curBall->DirtyRect.Width > 0)
@ -554,3 +557,95 @@ void render::build_occlude_list()
--memory::critical_allocation; --memory::critical_allocation;
} }
void render::SpriteViewer(bool* show)
{
static const char* BitmapTypes[] =
{
"None",
"RawBitmap",
"DibBitmap",
"Spliced",
};
static float scale = 1.0f;
auto uv_min = ImVec2(0.0f, 0.0f); // Top-left
auto uv_max = ImVec2(1.0f, 1.0f); // Lower-right
auto tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
auto border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white
if (ImGui::Begin("Sprite viewer", show, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar))
{
if (ImGui::BeginMenuBar())
{
ImGui::SliderFloat("Sprite scale", &scale, 0.1f, 10.0f, "scale = %.3f");
ImGui::EndMenuBar();
}
for (const auto group : pb::record_table->Groups)
{
bool emptyGroup = true;
for (int i = 0; i <= 2; i++)
{
auto bmp = group->GetBitmap(i);
if (bmp)
{
emptyGroup = false;
break;
}
}
if (emptyGroup)
continue;
ImGui::Text("Group: %d, name:%s", group->GroupId, group->GroupName.c_str());
for (int i = 0; i <= 2; i++)
{
auto bmp = group->GetBitmap(i);
if (!bmp)
continue;
auto type = BitmapTypes[static_cast<char>(bmp->BitmapType)];
ImGui::Text("type:%s, size:%d, resolution: %dx%d, offset:%dx%d", type,
bmp->Resolution,
bmp->Width, bmp->Height, bmp->XPosition, bmp->YPosition);
}
for (int same = 0, i = 0; i <= 2; i++)
{
auto bmp = group->GetBitmap(i);
if (!bmp)
continue;
gdrv::CreatePreview(*bmp);
if (bmp->Texture)
{
if (!same)
same = true;
else
ImGui::SameLine();
ImGui::Image(bmp->Texture, ImVec2(bmp->Width * scale, bmp->Height * scale),
uv_min, uv_max, tint_col, border_col);
}
}
for (int same = 0, i = 0; i <= 2; i++)
{
auto zMap = group->GetZMap(i);
if (!zMap)
continue;
zdrv::CreatePreview(*zMap);
if (zMap->Texture)
{
if (!same)
same = true;
else
ImGui::SameLine();
ImGui::Image(zMap->Texture, ImVec2(zMap->Width * scale, zMap->Height * scale),
uv_min, uv_max, tint_col, border_col);
}
}
}
}
ImGui::End();
}

View File

@ -61,4 +61,5 @@ public:
static void unpaint_balls(); static void unpaint_balls();
static void shift(int offsetX, int offsetY, int xSrc, int ySrc, int DestWidth, int DestHeight); static void shift(int offsetX, int offsetY, int xSrc, int ySrc, int DestWidth, int DestHeight);
static void build_occlude_list(); static void build_occlude_list();
static void SpriteViewer(bool* show);
}; };

View File

@ -4,11 +4,9 @@
#include "fullscrn.h" #include "fullscrn.h"
#include "loader.h" #include "loader.h"
#include "memory.h" #include "memory.h"
#include "partman.h" #include "GroupData.h"
#include "pb.h" #include "pb.h"
#include "render.h" #include "render.h"
#include "TDrain.h"
#include "winmain.h"
// Todo: load font from file // Todo: load font from file
const uint8_t PB_MSGFT_bin[] const uint8_t PB_MSGFT_bin[]
@ -32,9 +30,9 @@ scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp)
score->BackgroundBmp = renderBgBmp; score->BackgroundBmp = renderBgBmp;
/*Full tilt: score box dimensions index is offset by resolution*/ /*Full tilt: score box dimensions index is offset by resolution*/
auto dimensionsId = partman::record_labeled(pb::record_table, fieldName) + fullscrn::GetResolution(); auto dimensionsId = pb::record_table->record_labeled(fieldName) + fullscrn::GetResolution();
auto dimensions = reinterpret_cast<int16_t*>(partman::field(loader::loader_table, dimensionsId, auto dimensions = reinterpret_cast<int16_t*>(loader::loader_table->field( dimensionsId,
datFieldTypes::ShortArray)); FieldTypes::ShortArray));
if (!dimensions) if (!dimensions)
{ {
memory::free(score); memory::free(score);
@ -48,8 +46,7 @@ scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp)
for (int index = 0; index < 10; index++) for (int index = 0; index < 10; index++)
{ {
score->CharBmp[index] = reinterpret_cast<gdrv_bitmap8*>(partman::field( score->CharBmp[index] = loader::loader_table->GetBitmap(groupIndex);
loader::loader_table, groupIndex, datFieldTypes::Bitmap8bit));
++groupIndex; ++groupIndex;
} }
return score; return score;
@ -122,7 +119,7 @@ void score::load_msg_font_3DPB(LPCSTR lpName)
break; break;
} }
if (gdrv::create_raw_bitmap(bmp, width, height, 0)) if (gdrv::create_bitmap(bmp, width, height, width))
{ {
memory::free(bmp); memory::free(bmp);
msg_fontp->Chars[charInd] = nullptr; msg_fontp->Chars[charInd] = nullptr;
@ -133,12 +130,12 @@ void score::load_msg_font_3DPB(LPCSTR lpName)
memcpy(tmpCharBur + 3, ptrToData, sizeInBytes); memcpy(tmpCharBur + 3, ptrToData, sizeInBytes);
ptrToData += sizeInBytes; ptrToData += sizeInBytes;
auto srcptr = tmpCharBur + 4; auto srcPtr = tmpCharBur + 4;
auto dstPtr = &bmp->BmpBufPtr1[bmp->Stride * (bmp->Height - 1)]; auto dstPtr = &bmp->IndexedBmpPtr[bmp->Stride * (bmp->Height - 1)];
for (auto y = 0; y < height; ++y) for (auto y = 0; y < height; ++y)
{ {
memcpy(dstPtr, srcptr, width); memcpy(dstPtr, srcPtr, width);
srcptr += width; srcPtr += width;
dstPtr -= bmp->Stride; dstPtr -= bmp->Stride;
} }
} }
@ -152,7 +149,7 @@ void score::load_msg_font_FT(LPCSTR lpName)
{ {
if (!pb::record_table) if (!pb::record_table)
return; return;
int groupIndex = partman::record_labeled(pb::record_table, lpName); int groupIndex = pb::record_table->record_labeled(lpName);
if (groupIndex < 0) if (groupIndex < 0)
return; return;
msg_fontp = reinterpret_cast<score_msg_font_type*>(memory::allocate(sizeof(score_msg_font_type))); msg_fontp = reinterpret_cast<score_msg_font_type*>(memory::allocate(sizeof(score_msg_font_type)));
@ -160,15 +157,14 @@ void score::load_msg_font_FT(LPCSTR lpName)
return; return;
memset(msg_fontp, 0, sizeof(score_msg_font_type)); memset(msg_fontp, 0, sizeof(score_msg_font_type));
auto gapArray = reinterpret_cast<int16_t*>(partman::field(pb::record_table, groupIndex, datFieldTypes::ShortArray)); auto gapArray = reinterpret_cast<int16_t*>(pb::record_table->field(groupIndex, FieldTypes::ShortArray));
if (gapArray) if (gapArray)
msg_fontp->GapWidth = gapArray[fullscrn::GetResolution()]; msg_fontp->GapWidth = gapArray[fullscrn::GetResolution()];
else else
msg_fontp->GapWidth = 0; msg_fontp->GapWidth = 0;
for (auto charIndex = 32; charIndex < 128; charIndex++, ++groupIndex) for (auto charIndex = 32; charIndex < 128; charIndex++, ++groupIndex)
{ {
auto bmp = reinterpret_cast<gdrv_bitmap8*>(partman::field(pb::record_table, groupIndex, auto bmp = pb::record_table->GetBitmap(groupIndex);
datFieldTypes::Bitmap8bit));
if (!bmp) if (!bmp)
break; break;
if (!msg_fontp->Height) if (!msg_fontp->Height)
@ -181,7 +177,7 @@ void score::unload_msg_font()
{ {
if (msg_fontp) if (msg_fontp)
{ {
/*3DB creates bitmaps, FT just references them from partman*/ /*3DBP creates bitmaps, FT just references them from partman*/
if (!pb::FullTiltMode) if (!pb::FullTiltMode)
for (int i = 0; i < 128; i++) for (int i = 0; i < 128; i++)
{ {
@ -314,3 +310,18 @@ void score::string_format(int score, char* str)
} }
} }
} }
void score::ApplyPalette()
{
if (!msg_fontp || pb::FullTiltMode)
return;
// Only 3DPB font needs this, because it is not loaded by partman
for (auto& Char : msg_fontp->Chars)
{
if (Char)
{
gdrv::ApplyPalette(*Char);
}
}
}

View File

@ -42,6 +42,7 @@ public:
static void set(scoreStruct* score, int value); static void set(scoreStruct* score, int value);
static void update(scoreStruct* score); static void update(scoreStruct* score);
static void string_format(int score, char* str); static void string_format(int score, char* str);
static void ApplyPalette();
private : private :
static void load_msg_font_3DPB(LPCSTR lpName); static void load_msg_font_3DPB(LPCSTR lpName);
static void load_msg_font_FT(LPCSTR lpName); static void load_msg_font_FT(LPCSTR lpName);

View File

@ -7,6 +7,7 @@
#include "pinball.h" #include "pinball.h"
#include "options.h" #include "options.h"
#include "pb.h" #include "pb.h"
#include "render.h"
#include "Sound.h" #include "Sound.h"
#include "resource.h" #include "resource.h"
@ -36,6 +37,7 @@ gdrv_bitmap8 winmain::gfr_display{};
std::string winmain::DatFileName; std::string winmain::DatFileName;
bool winmain::ShowAboutDialog = false; bool winmain::ShowAboutDialog = false;
bool winmain::ShowImGuiDemo = false; bool winmain::ShowImGuiDemo = false;
bool winmain::ShowSpriteViewer = false;
bool winmain::LaunchBallEnabled = true; bool winmain::LaunchBallEnabled = true;
bool winmain::HighScoresEnabled = true; bool winmain::HighScoresEnabled = true;
bool winmain::DemoActive = false; bool winmain::DemoActive = false;
@ -137,7 +139,7 @@ int winmain::WinMain(LPCSTR lpCmdLine)
if (pb::init()) if (pb::init())
{ {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not load game data", SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not load game data",
"The .dat file is missing", window); "The .dat file is missing", window);
return 1; return 1;
} }
@ -180,7 +182,7 @@ int winmain::WinMain(LPCSTR lpCmdLine)
char buf[60]; char buf[60];
auto elapsedSec = static_cast<float>(curTime - prevTime) * 0.001f; auto elapsedSec = static_cast<float>(curTime - prevTime) * 0.001f;
snprintf(buf, sizeof buf, "Updates/sec = %02.02f Frames/sec = %02.02f ", snprintf(buf, sizeof buf, "Updates/sec = %02.02f Frames/sec = %02.02f ",
300.0f / elapsedSec, frameCounter / elapsedSec); 300.0f / elapsedSec, frameCounter / elapsedSec);
SDL_SetWindowTitle(window, buf); SDL_SetWindowTitle(window, buf);
frameCounter = 0; frameCounter = 0;
@ -199,15 +201,14 @@ int winmain::WinMain(LPCSTR lpCmdLine)
redGreen = i1; redGreen = i1;
} }
auto clr = Rgba{redGreen, redGreen, blue, 0}; *pltPtr++ = ColorRgba{Rgba{redGreen, redGreen, blue, 0}};
*pltPtr++ = {*reinterpret_cast<uint32_t*>(&clr)};
} }
gdrv::display_palette(plt); gdrv::display_palette(plt);
free(plt); free(plt);
gdrv::create_bitmap(&gfr_display, 400, 15); gdrv::create_bitmap(&gfr_display, 400, 15, 400, false);
} }
gdrv::blit(&gfr_display, 0, 0, 0, 0, 300, 10); gdrv::blit(&gfr_display, 0, 0, 0, 30, 300, 10);
gdrv::fill_bitmap(&gfr_display, 300, 10, 0, 0, 0); gdrv::fill_bitmap(&gfr_display, 300, 10, 0, 0, 0);
} }
} }
@ -254,12 +255,12 @@ int winmain::WinMain(LPCSTR lpCmdLine)
if (gfr_display.BmpBufPtr1) if (gfr_display.BmpBufPtr1)
{ {
auto deltaT = now - then + 10; auto deltaT = now - then + 10;
auto fillChar = static_cast<char>(deltaT); auto fillChar = static_cast<uint8_t>(deltaT);
if (deltaT > 236) if (deltaT > 236)
{ {
fillChar = -7; fillChar = 1;
} }
gdrv::fill_bitmap(&gfr_display, 1, 10, 299 - updateCounter, 0, fillChar); gdrv::fill_bitmap(&gfr_display, 1, 10, 300 - updateCounter, 0, fillChar);
} }
--updateCounter; --updateCounter;
then = now; then = now;
@ -329,7 +330,7 @@ void winmain::RenderUi()
// No demo window in release to save space // No demo window in release to save space
#ifndef NDEBUG #ifndef NDEBUG
if (ShowImGuiDemo) if (ShowImGuiDemo)
ImGui::ShowDemoWindow(); ImGui::ShowDemoWindow(&ShowImGuiDemo);
#endif #endif
if (ImGui::BeginMainMenuBar()) if (ImGui::BeginMainMenuBar())
@ -444,6 +445,12 @@ void winmain::RenderUi()
ShowImGuiDemo ^= true; ShowImGuiDemo ^= true;
} }
#endif #endif
if (ImGui::MenuItem("Sprite Viewer", nullptr, ShowSpriteViewer))
{
if (!ShowSpriteViewer && !single_step)
pause();
ShowSpriteViewer ^= true;
}
if (ImGui::MenuItem("Help Topics", "F1")) if (ImGui::MenuItem("Help Topics", "F1"))
{ {
if (!single_step) if (!single_step)
@ -465,6 +472,8 @@ void winmain::RenderUi()
a_dialog(); a_dialog();
high_score::RenderHighScoreDialog(); high_score::RenderHighScoreDialog();
if (ShowSpriteViewer)
render::SpriteViewer(&ShowSpriteViewer);
} }
int winmain::event_handler(const SDL_Event* event) int winmain::event_handler(const SDL_Event* event)
@ -553,7 +562,7 @@ int winmain::event_handler(const SDL_Event* event)
switch (event->key.keysym.sym) switch (event->key.keysym.sym)
{ {
case SDLK_h: case SDLK_g:
DispGRhistory = 1; DispGRhistory = 1;
break; break;
case SDLK_y: case SDLK_y:
@ -627,7 +636,6 @@ int winmain::event_handler(const SDL_Event* event)
{ {
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_TAKE_FOCUS: case SDL_WINDOWEVENT_TAKE_FOCUS:
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SHOWN: case SDL_WINDOWEVENT_SHOWN:
activated = 1; activated = 1;
Sound::Activate(); Sound::Activate();

View File

@ -11,7 +11,7 @@ public:
static ImGuiIO* ImIO; static ImGuiIO* ImIO;
static bool LaunchBallEnabled; static bool LaunchBallEnabled;
static bool HighScoresEnabled; static bool HighScoresEnabled;
static bool DemoActive; static bool DemoActive;
static char* BasePath; static char* BasePath;
static int WinMain(LPCSTR lpCmdLine); static int WinMain(LPCSTR lpCmdLine);
@ -32,6 +32,7 @@ private:
static bool restart; static bool restart;
static bool ShowAboutDialog; static bool ShowAboutDialog;
static bool ShowImGuiDemo; static bool ShowImGuiDemo;
static bool ShowSpriteViewer;
static void RenderUi(); static void RenderUi();
}; };

View File

@ -2,20 +2,18 @@
#include "zdrv.h" #include "zdrv.h"
#include "memory.h" #include "memory.h"
#include "pb.h" #include "pb.h"
#include "winmain.h"
int zdrv::create_zmap(zmap_header_type* zmap, int width, int height) int zdrv::create_zmap(zmap_header_type* zmap, int width, int height, int stride)
{ {
int stride = pad(width);
zmap->Stride = stride;
auto bmpBuf = memory::allocate<unsigned short>(height * stride);
zmap->ZPtr1 = bmpBuf;
if (!bmpBuf)
return -1;
zmap->ZPtr2 = bmpBuf;
zmap->Width = width; zmap->Width = width;
zmap->Height = height; zmap->Height = height;
return 0; zmap->Stride = stride >= 0 ? stride : pad(width);
zmap->Texture = nullptr;
zmap->ZPtr1 = memory::allocate<unsigned short>(zmap->Stride * zmap->Height);
return zmap->ZPtr1 ? 0 : -1;
} }
int zdrv::pad(int width) int zdrv::pad(int width)
@ -32,20 +30,22 @@ int zdrv::destroy_zmap(zmap_header_type* zmap)
return -1; return -1;
if (zmap->ZPtr1) if (zmap->ZPtr1)
memory::free(zmap->ZPtr1); memory::free(zmap->ZPtr1);
if (zmap->Texture)
SDL_DestroyTexture(zmap->Texture);
memset(zmap, 0, sizeof(zmap_header_type)); memset(zmap, 0, sizeof(zmap_header_type));
return 0; return 0;
} }
void zdrv::fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, uint16_t fillWord) void zdrv::fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, uint16_t fillWord)
{ {
auto dstPtr = &zmap->ZPtr1[zmap->Stride * (zmap->Height - height - yOff) + xOff]; auto dstPtr = &zmap->ZPtr1[zmap->Stride * yOff + xOff];
for (int y = height; y > 0; --y) for (int y = height; y > 0; --y)
{ {
for (int x = width; x > 0; --x) for (int x = width; x > 0; --x)
{ {
*dstPtr++ = fillWord; *dstPtr++ = fillWord;
} }
dstPtr += zmap->Stride - width; dstPtr += zmap->Stride - width;
} }
} }
@ -54,19 +54,12 @@ void zdrv::paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, in
int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, int srcBmpYOff, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, int srcBmpYOff,
zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff) zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff)
{ {
if (srcBmp->BitmapType == BitmapTypes::Spliced) assertm(srcBmp->BitmapType != BitmapTypes::Spliced, "Wrong bmp type");
{
/*Spliced bitmap is also a zMap, how convenient*/
paint_spliced_bmp(srcBmp->XPosition, srcBmp->YPosition, dstBmp, dstZMap, srcBmp);
return;
}
int dstHeightAbs = abs(dstBmp->Height); auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcBmpYOff + srcBmpXOff];
int srcHeightAbs = abs(srcBmp->Height); auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * dstBmpYOff + dstBmpXOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff]; auto srcPtrZ = &srcZMap->ZPtr1[srcZMap->Stride * srcZMapYOff + srcZMapXOff];
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeightAbs - height - dstBmpYOff) + dstBmpXOff]; auto dstPtrZ = &dstZMap->ZPtr1[dstZMap->Stride * dstZMapYOff + dstZMapXOff];
auto srcPtrZ = &srcZMap->ZPtr1[srcZMap->Stride * (srcZMap->Height - height - srcZMapYOff) + srcZMapXOff];
auto dstPtrZ = &dstZMap->ZPtr1[dstZMap->Stride * (dstZMap->Height - height - dstZMapYOff) + dstZMapXOff];
for (int y = height; y > 0; y--) for (int y = height; y > 0; y--)
{ {
@ -94,17 +87,17 @@ void zdrv::paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOf
zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff,
int srcBmpYOff, uint16_t depth) int srcBmpYOff, uint16_t depth)
{ {
int dstHeightAbs = abs(dstBmp->Height); assertm(srcBmp->BitmapType != BitmapTypes::Spliced, "Wrong bmp type");
int srcHeightAbs = abs(srcBmp->Height);
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeightAbs - height - dstBmpYOff) + dstBmpXOff]; auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * dstBmpYOff + dstBmpXOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff]; auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcBmpYOff + srcBmpXOff];
auto zPtr = &zMap->ZPtr1[zMap->Stride * (zMap->Height - height - dstZMapYOff) + dstZMapXOff]; auto zPtr = &zMap->ZPtr1[zMap->Stride * dstZMapYOff + dstZMapXOff];
for (int y = height; y > 0; y--) for (int y = height; y > 0; y--)
{ {
for (int x = width; x > 0; --x) for (int x = width; x > 0; --x)
{ {
if (*srcPtr && *zPtr > depth) if ((*srcPtr).Color && *zPtr > depth)
{ {
*dstPtr = *srcPtr; *dstPtr = *srcPtr;
} }
@ -119,40 +112,58 @@ void zdrv::paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOf
} }
} }
void zdrv::paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap, gdrv_bitmap8* srcBmp) void zdrv::CreatePreview(zmap_header_type& zMap)
{ {
assertm(srcBmp->BitmapType == BitmapTypes::Spliced, "Wrong bmp type"); if (zMap.Texture)
int xOffset = xPos - pb::MainTable->XOffset;
int yOffset = dstBmp->Height - srcBmp->Height - (yPos - pb::MainTable->YOffset);
if (yOffset < 0)
return; return;
auto bmpDstPtr = &dstBmp->BmpBufPtr1[xOffset + yOffset * dstBmp->Stride]; auto tmpBuff = new ColorRgba[zMap.Width * zMap.Height];
auto zMapDstPtr = &dstZmap->ZPtr2[xOffset + yOffset * dstZmap->Stride];
auto bmpSrcPtr = reinterpret_cast<unsigned short*>(srcBmp->BmpBufPtr1);
while (true) ColorRgba color{};
auto dst = tmpBuff;
auto src = zMap.ZPtr1;
for (auto y = 0; y < zMap.Height; y++)
{ {
auto stride = static_cast<short>(*bmpSrcPtr++); for (auto x = 0; x < zMap.Width; x++)
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 depth = static_cast<uint8_t>((0xffff - *src++) / 0xff);
auto charPtr = reinterpret_cast<char**>(&bmpSrcPtr); color.rgba.peRed = depth;
if (*zMapDstPtr >= depth) color.rgba.peGreen = depth;
{ color.rgba.peBlue = depth;
*bmpDstPtr = **charPtr;
*zMapDstPtr = depth;
}
(*charPtr)++; /*auto depth = static_cast<float>(*src++) /0xffff;
++zMapDstPtr; color.rgba.peRed = (1-depth) * 0xff;
++bmpDstPtr; color.rgba.peBlue = (depth) * 0xff;*/
*dst++ = color;
} }
src += zMap.Stride - zMap.Width;
}
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
auto texture = SDL_CreateTexture
(
winmain::Renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
zMap.Width, zMap.Height
);
SDL_UpdateTexture(texture, nullptr, tmpBuff, zMap.Width * 4);
zMap.Texture = texture;
delete[] tmpBuff;
}
void zdrv::FlipZMapHorizontally(const zmap_header_type& zMap)
{
// Flip in-place, iterate over Height/2 lines
auto dst = zMap.ZPtr1;
auto src = zMap.ZPtr1 + zMap.Stride * (zMap.Height - 1);
for (auto y = zMap.Height - 1; y >= zMap.Height / 2; y--)
{
for (auto x = 0; x < zMap.Width; x++)
{
std::swap(*dst++, *src++);
}
dst += zMap.Stride - zMap.Width;
src -= zMap.Stride + zMap.Width;
} }
} }

View File

@ -6,16 +6,16 @@ struct zmap_header_type
int Width; int Width;
int Height; int Height;
int Stride; int Stride;
unsigned Resolution;
uint16_t* ZPtr1; uint16_t* ZPtr1;
uint16_t* ZPtr2; SDL_Texture* Texture;
uint16_t ZBuffer[1];
}; };
class zdrv class zdrv
{ {
public: public:
static int pad(int width); static int pad(int width);
static int create_zmap(zmap_header_type* zmap, int width, int height); static int create_zmap(zmap_header_type* zmap, int width, int height, int stride = -1);
static int destroy_zmap(zmap_header_type* zmap); static int destroy_zmap(zmap_header_type* zmap);
static void fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, uint16_t fillWord); static void fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, uint16_t fillWord);
static void paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff, static void paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff,
@ -24,6 +24,6 @@ public:
static void paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff, 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, zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp,
int srcBmpXOff, int srcBmpYOff, uint16_t depth); int srcBmpXOff, int srcBmpYOff, uint16_t depth);
static void paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap, static void CreatePreview(zmap_header_type& zMap);
gdrv_bitmap8* srcBmp); static void FlipZMapHorizontally(const zmap_header_type& zMap);
}; };