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/gdrv.cpp
SpaceCadetPinball/gdrv.h
SpaceCadetPinball/GroupData.cpp
SpaceCadetPinball/GroupData.h
SpaceCadetPinball/high_score.cpp
SpaceCadetPinball/high_score.h
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 "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"
int main(int argc, char* argv[])
@ -24,57 +15,6 @@ int main(int argc, char* argv[])
winmain::WinMain(cmdLine.c_str());
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

View file

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

View file

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

View file

@ -1,11 +1,15 @@
#include "pch.h"
#include "gdrv.h"
#include "GroupData.h"
#include "memory.h"
#include "partman.h"
#include "pb.h"
#include "score.h"
#include "winmain.h"
SDL_Texture* gdrv::vScreenTex = nullptr;
char* gdrv::vScreenPixels = nullptr;
ColorRgba* gdrv::vScreenPixels = nullptr;
int gdrv::vScreenWidth, gdrv::vScreenHeight;
ColorRgba gdrv::current_palette[256]{};
SDL_Rect gdrv::DestinationRect{};
@ -20,7 +24,7 @@ int gdrv::init(int width, int height)
SDL_TEXTUREACCESS_STREAMING,
width, height
);
vScreenPixels = memory::allocate(width * height * 4);
vScreenPixels = memory::allocate<ColorRgba>(width * height);
vScreenWidth = width;
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;
bmp->Stride = width;
if (width % 4)
bmp->Stride = 4 - width % 4 + width;
assertm(width >= 0 && height >= 0, "Negative bitmap8 dimensions");
bmp->Width = width;
bmp->Height = height;
bmp->Stride = width;
bmp->BitmapType = BitmapTypes::DibBitmap;
bmp->BmpBufPtr1 = memory::allocate(bmp->Height * bmp->Stride);
return 0;
bmp->Texture = nullptr;
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;
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;
}
assertm(header.Width >= 0 && header.Height >= 0, "Negative bitmap8 dimensions");
int gdrv::create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size)
{
bmp->Width = width;
bmp->Stride = width;
bmp->BitmapType = BitmapTypes::Spliced;
bmp->Height = height;
char* buf = memory::allocate(size);
bmp->BmpBufPtr1 = buf;
if (!buf)
return -1;
return 0;
if (header.IsFlagSet(bmp8Flags::Spliced))
bmp.BitmapType = BitmapTypes::Spliced;
else if (header.IsFlagSet(bmp8Flags::DibBitmap))
bmp.BitmapType = BitmapTypes::DibBitmap;
else
bmp.BitmapType = BitmapTypes::RawBitmap;
bmp.Width = header.Width;
bmp.Stride = header.Width;
bmp.IndexedStride = header.Width;
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)
{
const uint32_t sysPaletteColors[]
{
0x00000000,
0x00000000, // Color 0: transparent
0x00000080,
0x00008000,
0x00008080,
@ -122,6 +157,19 @@ int gdrv::display_palette(ColorRgba* plt)
current_palette[255].rgba.peGreen = -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;
}
@ -134,6 +182,10 @@ int gdrv::destroy_bitmap(gdrv_bitmap8* bmp)
if (bmp->BitmapType != BitmapTypes::None)
{
memory::free(bmp->BmpBufPtr1);
if (bmp->IndexedBmpPtr)
memory::free(bmp->IndexedBmpPtr);
if (bmp->Texture)
SDL_DestroyTexture(bmp->Texture);
}
memset(bmp, 0, sizeof(gdrv_bitmap8));
return 0;
@ -151,7 +203,7 @@ void gdrv::blit(gdrv_bitmap8* bmp, int xSrc, int ySrc, int xDest, int yDest, int
{
StretchDIBitsScaled(
xSrc,
ySrc ,
ySrc,
xDest,
yDest,
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;
if (bmpHeight < 0)
bmpHeight = -bmpHeight;
char* bmpPtr = &bmp->BmpBufPtr1[bmp->Width * (bmpHeight - height - yOff) + xOff];
auto color = current_palette[fillChar];
auto bmpPtr = &bmp->BmpBufPtr1[bmp->Width * yOff + xOff];
for (; height > 0; --height)
{
if (width > 0)
memset(bmpPtr, fillChar, width);
bmpPtr += bmp->Stride;
for (int x = width; x > 0; --x)
*bmpPtr++ = color;
bmpPtr += bmp->Stride - width;
}
}
void gdrv::copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp,
int srcXOff, int srcYOff)
{
int dstHeight = abs(dstBmp->Height);
int srcHeight = abs(srcBmp->Height);
char* srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeight - height - srcYOff) + srcXOff];
char* dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeight - height - yOff) + xOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcYOff + srcXOff];
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * yOff + xOff];
for (int y = height; y > 0; --y)
{
for (int x = width; x > 0; --x)
*dstPtr++ = *srcPtr++;
srcPtr += srcBmp->Stride - width;
dstPtr += dstBmp->Stride - width;
std::memcpy(dstPtr, srcPtr, width * sizeof(ColorRgba));
srcPtr += srcBmp->Stride;
dstPtr += dstBmp->Stride;
}
}
void gdrv::copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff,
gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff)
{
int dstHeight = abs(dstBmp->Height);
int srcHeight = abs(srcBmp->Height);
char* srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeight - height - srcYOff) + srcXOff];
char* dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeight - height - yOff) + xOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcYOff + srcXOff];
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * yOff + xOff];
for (int y = height; y > 0; --y)
{
for (int x = width; x > 0; --x)
{
if (*srcPtr)
if ((*srcPtr).Color)
*dstPtr = *srcPtr;
++srcPtr;
++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)
{
{
}
int gdrv::StretchDIBitsScaled(int xSrc, int ySrc, int xDst, int yDst,
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
if (xDst < 0)
{
{
xSrc -= xDst;
xDst = 0;
}
@ -258,27 +298,22 @@ int gdrv::StretchDIBitsScaled(int xSrc, int ySrc, int xDst, int yDst,
if (xSrc + width > bmp->Width)
width = bmp->Width - xSrc;
if (ySrc + height > bmp->Height)
height = bmp->Height - ySrc;
height = bmp->Height - ySrc;
xDst = std::max(0, std::min(xDst, vScreenWidth));
yDst = std::max(0, std::min(yDst, vScreenHeight));
if (xDst + width > vScreenWidth)
width = vScreenWidth - xDst;
if (yDst + height > vScreenHeight)
height = vScreenHeight - yDst;
height = vScreenHeight - yDst;
auto srcPtr = reinterpret_cast<uint8_t*>(&bmp->BmpBufPtr1[bmp->Stride * ySrc + xSrc]);
auto dstPtr = &reinterpret_cast<uint32_t*>(vScreenPixels)[vScreenWidth * yDst + xDst];
auto srcPtr = &bmp->BmpBufPtr1[bmp->Stride * ySrc + xSrc];
auto dstPtr = &vScreenPixels[vScreenWidth * yDst + xDst];
for (int y = height; y > 0; --y)
{
for (int x = width; x > 0; --x)
{
*dstPtr++ = current_palette[*srcPtr++].Color;
}
srcPtr += bmp->Stride - width;
dstPtr += vScreenWidth - width;
std::memcpy(dstPtr, srcPtr, width * sizeof(ColorRgba));
srcPtr += bmp->Stride;
dstPtr += vScreenWidth;
}
return 0;
@ -297,5 +332,41 @@ void gdrv::BlitScreen()
);
std::memcpy(lockedPixels, vScreenPixels, vScreenWidth * vScreenHeight * 4);
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
enum class BitmapTypes : char
enum class BitmapTypes : uint8_t
{
None = 0,
RawBitmap = 1,
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
{
@ -26,13 +16,43 @@ struct Rgba
uint8_t peBlue;
uint8_t peFlags;
};
union ColorRgba
{
ColorRgba() = default;
explicit ColorRgba(uint32_t color)
: Color(color)
{
}
explicit ColorRgba(Rgba rgba)
: rgba(rgba)
{
}
uint32_t Color;
Rgba rgba;
};
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
{
@ -42,25 +62,26 @@ public:
static int init(int width, int height);
static int uninit();
static void get_focus();
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 create_bitmap(gdrv_bitmap8* bmp, int width, int height, int stride = -1, bool indexed = true);
static int create_bitmap(gdrv_bitmap8& bmp, const struct dat8BitBmpHeader& header);
static int destroy_bitmap(gdrv_bitmap8* bmp);
static int display_palette(ColorRgba* plt);
static void start_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 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,
int srcXOff, int srcYOff);
static void copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff,
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 BlitScreen();
static void ApplyPalette(gdrv_bitmap8& bmp);
static void CreatePreview(gdrv_bitmap8& bmp);
private:
static SDL_Texture* vScreenTex;
static char* vScreenPixels;
static ColorRgba* vScreenPixels;
static int vScreenWidth, vScreenHeight;
static ColorRgba current_palette[256];

View file

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

View file

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

View file

@ -1,7 +1,7 @@
#include "pch.h"
#include "loader.h"
#include "memory.h"
#include "partman.h"
#include "GroupData.h"
#include "pb.h"
#include "pinball.h"
#include "Sound.h"
@ -12,7 +12,7 @@ errorMsg loader::loader_errors[] =
{
errorMsg{0, "Bad Handle"},
errorMsg{1, "No Type Field"},
errorMsg{2, "No Attributes Field"},
errorMsg{2, "No Attributes Field"},
errorMsg{3, "Wrong Type: MATERIAL Expected"},
errorMsg{4, "Wrong Type: KICKER Expected"},
errorMsg{5, "Wrong Type: AN_OBJECT Expected"},
@ -42,8 +42,8 @@ errorMsg loader::loader_errors[] =
int loader::sound_count = 1;
int loader::loader_sound_count;
datFileStruct* loader::loader_table;
datFileStruct* loader::sound_record_table;
DatFile* loader::loader_table;
DatFile* loader::sound_record_table;
soundListStruct loader::sound_list[65];
int loader::error(int errorCode, int captionCode)
@ -82,14 +82,14 @@ void loader::default_vsi(visualStruct* visual)
visual->SoundIndex4 = 0;
}
void loader::loadfrom(datFileStruct* datFile)
void loader::loadfrom(DatFile* datFile)
{
loader_table = datFile;
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 (sound_count < 65)
@ -136,26 +136,27 @@ int loader::get_sound_id(int groupIndex)
if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr)
{
WaveHeader wavHeader{};
int soundGroupId = sound_list[soundIndex].GroupIndex;
sound_list[soundIndex].Duration = 0.0;
if (soundGroupId > 0 && !pinball::quickFlag)
{
auto value = reinterpret_cast<int16_t*>(partman::field(loader_table, soundGroupId,
datFieldTypes::ShortValue));
auto value = reinterpret_cast<int16_t*>(loader_table->field(soundGroupId,
FieldTypes::ShortValue));
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.
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)
{
// FT sounds are in SOUND subfolder
fileName.insert(0, 1, PathSeparator);
fileName.insert(0, "SOUND");
}
auto filePath = pinball::make_path_name(fileName);
auto file = fopen(filePath.c_str(), "rb");
if (file)
@ -163,7 +164,7 @@ int loader::get_sound_id(int groupIndex)
fread(&wavHeader, 1, sizeof wavHeader, file);
fclose(file);
}
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].WavePtr = Sound::LoadWaveFile(filePath);
@ -178,7 +179,7 @@ int loader::get_sound_id(int groupIndex)
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)
@ -186,7 +187,7 @@ short loader::query_visual_states(int groupIndex)
short result;
if (groupIndex < 0)
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)
result = shortArr[1];
else
@ -202,7 +203,7 @@ char* loader::query_name(int groupIndex)
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)
@ -215,13 +216,13 @@ int16_t* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize
for (auto skipIndex = 0;; ++skipIndex)
{
auto shortArr = reinterpret_cast<int16_t*>(partman::field_nth(loader_table, groupIndex,
datFieldTypes::ShortArray, skipIndex));
auto shortArr = reinterpret_cast<int16_t*>(loader_table->field_nth(groupIndex,
FieldTypes::ShortArray, skipIndex));
if (!shortArr)
break;
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;
}
}
@ -248,8 +249,8 @@ float* loader::query_float_attribute(int groupIndex, int groupIndexOffset, int f
for (auto skipIndex = 0;; ++skipIndex)
{
auto floatArr = reinterpret_cast<float*>(partman::field_nth(loader_table, stateId, datFieldTypes::FloatArray,
skipIndex));
auto floatArr = reinterpret_cast<float*>(loader_table->field_nth(stateId, FieldTypes::FloatArray,
skipIndex));
if (!floatArr)
break;
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)
{
auto floatArr = reinterpret_cast<float*>(partman::field_nth(loader_table, stateId,
datFieldTypes::FloatArray, skipIndex));
auto floatArr = reinterpret_cast<float*>(loader_table->field_nth(stateId,
FieldTypes::FloatArray, skipIndex));
if (!floatArr)
break;
if (static_cast<int16_t>(floor(*floatArr)) == firstValue)
@ -295,16 +296,16 @@ int loader::material(int groupIndex, visualStruct* visual)
{
if (groupIndex < 0)
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)
return error(1, 21);
if (*shortArr != 300)
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)
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)
{
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);
if (visualState <= 0)
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)
return error(1, 24);
if (*shortArr != 200)
@ -350,7 +351,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset)
return groupIndex;
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)
return error(1, 24);
if (*shortArr != 201)
@ -362,15 +363,15 @@ int loader::kicker(int groupIndex, visualKickerStruct* kicker)
{
if (groupIndex < 0)
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)
return error(1, 20);
if (*shortArr != 400)
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)
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)
return 0;
@ -421,19 +422,13 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vis
if (stateId < 0)
return error(16, 18);
visual->Bitmap = reinterpret_cast<gdrv_bitmap8*>(partman::field(loader_table, stateId, datFieldTypes::Bitmap8bit));
visual->ZMap = reinterpret_cast<zmap_header_type*>(partman::field(loader_table, stateId, datFieldTypes::Bitmap16bit)
);
if (visual->ZMap)
{
visual->ZMap->ZPtr1 = visual->ZMap->ZBuffer;
visual->ZMap->ZPtr2 = visual->ZMap->ZPtr1;
}
visual->Bitmap = loader_table->GetBitmap(stateId);
visual->ZMap = loader_table->GetZMap(stateId);
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)
{
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;)
{
switch (shortArr[0])
@ -479,13 +474,13 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vis
if (!visual->CollisionGroup)
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)
return 0;
if (*floatArr != 600.0f)
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);
switch (floatVal)
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,29 +1,8 @@
#pragma once
enum class datFieldTypes : int16_t
{
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 ? )
};
struct zmap_header_type;
struct gdrv_bitmap8;
enum class bmp8Flags : unsigned char
{
@ -33,8 +12,7 @@ enum class bmp8Flags : unsigned char
};
#pragma pack(push)
#pragma pack(1)
#pragma pack(push, 1)
struct datFileHeader
{
char FileSignature[21];
@ -45,34 +23,10 @@ struct datFileHeader
int SizeOfBody;
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
{
char Resolution;
uint8_t Resolution;
int16_t Width;
int16_t Height;
int16_t XPosition;
@ -80,18 +34,12 @@ struct dat8BitBmpHeader
int Size;
bmp8Flags Flags;
bool IsFlagSet(bmp8Flags flag)
bool IsFlagSet(bmp8Flags flag) const
{
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
{
int16_t Width;
@ -101,22 +49,17 @@ struct dat16BitBmpHeader
int16_t Unknown1_0;
int16_t Unknown1_1;
};
#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");
class partman
{
public:
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);
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);
static struct DatFile* load_records(LPCSTR lpFileName, bool fullTiltMode);
private:
static short _field_size[];
static char _lread_char(FILE* file);

View file

@ -24,9 +24,14 @@
#include "TLightGroup.h"
#include "TPlunger.h"
#include "TTableLayer.h"
#include "GroupData.h"
#include "partman.h"
#include "score.h"
#include "TPinballTable.h"
#include "TTextBox.h"
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_;
float pb::time_now, pb::time_next, pb::ball_speed_limit;
high_score_struct pb::highscore_table[5];
@ -39,7 +44,7 @@ int pb::init()
++memory::critical_allocation;
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;
pinball::get_rc_int(158, &useBmpFont);
@ -49,12 +54,12 @@ int pb::init()
if (!record_table)
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);
auto backgroundBmp = (gdrv_bitmap8*)partman::field_labeled(record_table, "background", datFieldTypes::Bitmap8bit);
auto cameraInfoId = partman::record_labeled(record_table, "camera_info") + fullscrn::GetResolution();
auto cameraInfo = (float*)partman::field(record_table, cameraInfoId, datFieldTypes::FloatArray);
auto backgroundBmp = record_table->GetBitmap(record_table->record_labeled("background"));
auto cameraInfoId = record_table->record_labeled("camera_info") + fullscrn::GetResolution();
auto cameraInfo = (float*)record_table->field(cameraInfoId, FieldTypes::FloatArray);
/*Full tilt: table size depends on resolution*/
auto resInfo = &fullscrn::resolution_array[fullscrn::GetResolution()];
@ -84,7 +89,6 @@ int pb::init()
0,
0);
gdrv::destroy_bitmap(backgroundBmp);
loader::loadfrom(record_table);
if (pinball::quickFlag)
@ -108,7 +112,7 @@ int pb::uninit()
{
score::unload_msg_font();
loader::unload();
partman::unload_records(record_table);
delete record_table;
high_score::write(highscore_table);
if (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;
maths::vector_add(&ball->Acceleration, &vec2);
ball->Speed = maths::normalize_2d(&ball->Acceleration);
ball->InvAcceleration.X = ball->Acceleration.X == 0.0f ? 1000000000.0f : 1.0f / ball->Acceleration.X;
ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0f ? 1000000000.0f : 1.0f / ball->Acceleration.Y;
ball->InvAcceleration.X = ball->Acceleration.X == 0.0f ? 1.0e9f : 1.0f / ball->Acceleration.X;
ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0f ? 1.0e9f : 1.0f / ball->Acceleration.Y;
}
auto timeDelta2 = timeDelta;

View file

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

View file

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

View file

@ -1,6 +1,9 @@
#include "pch.h"
#include "render.h"
#include "GroupData.h"
#include "memory.h"
#include "pb.h"
int render::blit = 0;
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);
dirty_list = memory::allocate<render_sprite_type_struct*>(1000);
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::fill(&zscreen, zscreen.Width, zscreen.Height, 0, 0, 0xFFFF);
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;
while (ballBmp < &ball_bitmap[20])
{
gdrv::create_raw_bitmap(ballBmp, 64, 64, 1);
gdrv::create_bitmap(ballBmp, 64, 64, 64, false);
++ballBmp;
}
background_bitmap = bmp;
@ -473,7 +476,7 @@ void render::paint_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];
if (curBall->DirtyRect.Width > 0)
@ -554,3 +557,95 @@ void render::build_occlude_list()
--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 shift(int offsetX, int offsetY, int xSrc, int ySrc, int DestWidth, int DestHeight);
static void build_occlude_list();
static void SpriteViewer(bool* show);
};

View file

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

View file

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

View file

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

View file

@ -2,20 +2,18 @@
#include "zdrv.h"
#include "memory.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->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)
@ -32,20 +30,22 @@ int zdrv::destroy_zmap(zmap_header_type* zmap)
return -1;
if (zmap->ZPtr1)
memory::free(zmap->ZPtr1);
if (zmap->Texture)
SDL_DestroyTexture(zmap->Texture);
memset(zmap, 0, sizeof(zmap_header_type));
return 0;
}
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 x = width; x > 0; --x)
{
*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,
zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff)
{
if (srcBmp->BitmapType == BitmapTypes::Spliced)
{
/*Spliced bitmap is also a zMap, how convenient*/
paint_spliced_bmp(srcBmp->XPosition, srcBmp->YPosition, dstBmp, dstZMap, srcBmp);
return;
}
assertm(srcBmp->BitmapType != BitmapTypes::Spliced, "Wrong bmp type");
int dstHeightAbs = abs(dstBmp->Height);
int srcHeightAbs = abs(srcBmp->Height);
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff];
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeightAbs - height - dstBmpYOff) + dstBmpXOff];
auto srcPtrZ = &srcZMap->ZPtr1[srcZMap->Stride * (srcZMap->Height - height - srcZMapYOff) + srcZMapXOff];
auto dstPtrZ = &dstZMap->ZPtr1[dstZMap->Stride * (dstZMap->Height - height - dstZMapYOff) + dstZMapXOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcBmpYOff + srcBmpXOff];
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * dstBmpYOff + dstBmpXOff];
auto srcPtrZ = &srcZMap->ZPtr1[srcZMap->Stride * srcZMapYOff + srcZMapXOff];
auto dstPtrZ = &dstZMap->ZPtr1[dstZMap->Stride * dstZMapYOff + dstZMapXOff];
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,
int srcBmpYOff, uint16_t depth)
{
int dstHeightAbs = abs(dstBmp->Height);
int srcHeightAbs = abs(srcBmp->Height);
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * (dstHeightAbs - height - dstBmpYOff) + dstBmpXOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff];
auto zPtr = &zMap->ZPtr1[zMap->Stride * (zMap->Height - height - dstZMapYOff) + dstZMapXOff];
assertm(srcBmp->BitmapType != BitmapTypes::Spliced, "Wrong bmp type");
auto dstPtr = &dstBmp->BmpBufPtr1[dstBmp->Stride * dstBmpYOff + dstBmpXOff];
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * srcBmpYOff + srcBmpXOff];
auto zPtr = &zMap->ZPtr1[zMap->Stride * dstZMapYOff + dstZMapXOff];
for (int y = height; y > 0; y--)
{
for (int x = width; x > 0; --x)
{
if (*srcPtr && *zPtr > depth)
if ((*srcPtr).Color && *zPtr > depth)
{
*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");
int xOffset = xPos - pb::MainTable->XOffset;
int yOffset = dstBmp->Height - srcBmp->Height - (yPos - pb::MainTable->YOffset);
if (yOffset < 0)
if (zMap.Texture)
return;
auto bmpDstPtr = &dstBmp->BmpBufPtr1[xOffset + yOffset * dstBmp->Stride];
auto zMapDstPtr = &dstZmap->ZPtr2[xOffset + yOffset * dstZmap->Stride];
auto bmpSrcPtr = reinterpret_cast<unsigned short*>(srcBmp->BmpBufPtr1);
auto tmpBuff = new ColorRgba[zMap.Width * zMap.Height];
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++);
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--)
for (auto x = 0; x < zMap.Width; x++)
{
auto depth = *bmpSrcPtr++;
auto charPtr = reinterpret_cast<char**>(&bmpSrcPtr);
if (*zMapDstPtr >= depth)
{
*bmpDstPtr = **charPtr;
*zMapDstPtr = depth;
}
auto depth = static_cast<uint8_t>((0xffff - *src++) / 0xff);
color.rgba.peRed = depth;
color.rgba.peGreen = depth;
color.rgba.peBlue = depth;
(*charPtr)++;
++zMapDstPtr;
++bmpDstPtr;
/*auto depth = static_cast<float>(*src++) /0xffff;
color.rgba.peRed = (1-depth) * 0xff;
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 Height;
int Stride;
unsigned Resolution;
uint16_t* ZPtr1;
uint16_t* ZPtr2;
uint16_t ZBuffer[1];
SDL_Texture* Texture;
};
class zdrv
{
public:
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 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,
@ -24,6 +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, uint16_t depth);
static void paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap,
gdrv_bitmap8* srcBmp);
static void CreatePreview(zmap_header_type& zMap);
static void FlipZMapHorizontally(const zmap_header_type& zMap);
};