[RDY] Cpp fmt (#1562)

* Hand formatted changes before automatic formatting

* Break up / shorten some long lines

* Add some missing braces for clarity

* Multiline strings are merged to let clang-format split them
appropriately.

* sdl_core's frame_count changed from a C style array to std::array
which made the length checks simpler.

* Add includes and forward declairs to avoid transitive dependencies

* Remove th_gfx_font.h include from th_gfx.h - circular dependencies

* using to shorten lines in th_map.cpp

* Avoid non-portable reinterpret_cast for parcels in th_map.

* Use more constants in th_map.

* Use class initializer for th_map classes

* Add clang files to ignore list

* Add clang-format file

* Reformat all files with clang-format

Also includes some manual braces.

* Disable clang-format for backdrop.h

* Clang-format AnimView src files

* clang-format common code

* Fix anonymous struct in union warning

Anonymous structs in anonymous unions are not supported by the standard.

* Check clang-format in travis

* Bin pack parameters

* Bin pack arguments too

* Full Google style

2 space indent, no forced break on braces.

* A couple format overrides

Order of usings in config.h.in since 8 is smaller than 16.
Table layout, since 0x80 nicely fits in 8 columns.
This commit is contained in:
Stephen E. Baker
2019-10-06 08:18:25 -04:00
committed by GitHub
parent 326e2fa622
commit 4a1c98a716
68 changed files with 21334 additions and 23075 deletions

22
.clang-format Normal file
View File

@@ -0,0 +1,22 @@
---
Language: Cpp
BasedOnStyle: Google
MacroBlockBegin: "^\
BEGIN_EVENT_TABLE.*"
MacroBlockEnd: "^\
END_EVENT_TABLE()"
DerivePointerAlignment: false
PointerAlignment: Left
IncludeCategories:
- Regex: '^"config.h"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
- Regex: '.*'
Priority: 4

3
.gitignore vendored
View File

@@ -77,6 +77,9 @@ CMakeFiles
Makefile
CMakeScripts/
# Clang tools
compile_commands.json
# This is for the CMake-generated Visual Studio project
*.vcxproj
*.vcxproj.user

View File

@@ -44,7 +44,6 @@ before_script:
# Don't ask for confirmation when using scp
- echo -e "Host armedpineapple.co.uk\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- echo -e "Host server2.armedpineapple.co.uk\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- cd fresh
script:
# Check if there are trailing whitespaces.
- ${TRAVIS_BUILD_DIR}/scripts/check_trailing_whitespaces.py $TRAVIS_BUILD_DIR
@@ -52,7 +51,12 @@ script:
- ${TRAVIS_BUILD_DIR}/scripts/check_language_files_not_BOM.py $TRAVIS_BUILD_DIR/CorsixTH/Lua/languages
# Check if there are lua classes with invalid/improper declarations.
- ${TRAVIS_BUILD_DIR}/scripts/check_lua_classes.py
# Check cpp format
- cd ${TRAVIS_BUILD_DIR}
- clang-format -i CorsixTH/Src/*{.cpp,.h} AnimView/*{.cpp,.h} common/*{.cpp,.h} CorsixTH/SrcUnshared/main.cpp
- git diff --exit-code
# Build CorsixTH
- cd fresh
- make VERBOSE=1
# Validate lua files
- find $TRAVIS_BUILD_DIR -path $TRAVIS_BUILD_DIR/CorsixTH/Lua/languages -prune -o -name '*.lua' -print0 | xargs -0 luac -p --

View File

@@ -20,17 +20,17 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "app.h"
#include "config.h"
#include "frmMain.h"
#include "frmSprites.h"
IMPLEMENT_APP(ThemeHospitalAnimViewApp)
bool ThemeHospitalAnimViewApp::OnInit()
{
bool ThemeHospitalAnimViewApp::OnInit() {
wxTopLevelWindow* pForm;
if(::wxMessageBox(L"Launch animation viewer? (No -> sprite viewer)", L"AnimView", wxYES_NO) == wxYES)
if (::wxMessageBox(L"Launch animation viewer? (No -> sprite viewer)",
L"AnimView", wxYES_NO) == wxYES)
pForm = new frmMain;
else
pForm = new frmSprites;

View File

@@ -37,8 +37,7 @@ SOFTWARE.
#endif
// ----------------------------
class ThemeHospitalAnimViewApp : public wxApp
{
class ThemeHospitalAnimViewApp : public wxApp {
virtual bool OnInit();
};

View File

@@ -1,4 +1,5 @@
/* XPM */
// clang-format off
static const char *const backdrop_xpm[] = {
"126 64 12 1",
"f c #695D7D",
@@ -78,3 +79,4 @@ static const char *const backdrop_xpm[] = {
" bfffff bfffff ",
" .f .f "
};
// clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -22,27 +22,25 @@ SOFTWARE.
#pragma once
#include "config.h"
#include <wx/frame.h>
#include <wx/button.h>
#include <wx/spinctrl.h>
#include <wx/checkbox.h>
#include <wx/textctrl.h>
#include <wx/panel.h>
#include <wx/timer.h>
#include <wx/listbox.h>
#include <wx/dcclient.h>
#include <wx/frame.h>
#include <wx/listbox.h>
#include <wx/panel.h>
#include <wx/spinctrl.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
#include <wx/txtstrm.h>
#include "th.h"
//#include <vector>
class frmMain : public wxFrame
{
class frmMain : public wxFrame {
public:
frmMain();
~frmMain();
enum
{
enum {
ID_FIRST_ANIM = wxID_HIGHEST + 1,
ID_PREV_ANIM,
ID_ANIM_INDEX,
@@ -70,7 +68,9 @@ public:
void load();
void export_png();
void exportSpritesPage(bool bComplex, wxString sPath, wxString sFilename, wxString spPath=L"", wxString sPalette=L"MPALETTE.DAT");
void exportSpritesPage(bool bComplex, wxString sPath, wxString sFilename,
wxString spPath = L"",
wxString sPalette = L"MPALETTE.DAT");
// std::vector<_sprite_t> m_vSprites;
protected:
@@ -101,7 +101,8 @@ protected:
void _onAnimChange(size_t iIndex);
void _drawCoordinates(wxPaintDC& DC, int i, int j);
wxString _getCaseSensitivePath(const wxString& sInsensitivePathPart, const wxString& sPath);
wxString _getCaseSensitivePath(const wxString& sInsensitivePathPart,
const wxString& sPath);
THAnimations m_oAnims;
THLayerMask m_mskLayers;

View File

@@ -20,15 +20,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "frmSprites.h"
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/msgdlg.h>
#include "config.h"
#include <wx/dcclient.h>
#include <wx/dirdlg.h>
#include <wx/filedlg.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/vscroll.h>
#include <wx/dcclient.h>
BEGIN_EVENT_TABLE(frmSprites, wxFrame)
EVT_BUTTON(ID_LOAD, frmSprites::_onLoad)
@@ -40,71 +40,75 @@ BEGIN_EVENT_TABLE(frmSprites, wxFrame)
END_EVENT_TABLE()
frmSprites::frmSprites()
: wxFrame(NULL, wxID_ANY, L"Theme Hospital Sprite Viewer")
{
: wxFrame(NULL, wxID_ANY, L"Theme Hospital Sprite Viewer") {
wxBoxSizer* pMainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* pFiles = new wxStaticBoxSizer(wxVERTICAL, this, L"Files");
wxFlexGridSizer* pFilesGrid = new wxFlexGridSizer(4, 3, 2, 1);
pFilesGrid->AddGrowableCol(1, 1);
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Table:"), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
pFilesGrid->Add(m_txtTable = new wxTextCtrl(this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\QData\\Font00V.tab"), 1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
pFilesGrid->Add(new wxButton(this, ID_BROWSE_TABLE, L"Browse..."), 0, wxALIGN_CENTER_VERTICAL);
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Data:"), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
pFilesGrid->Add(m_txtData = new wxTextCtrl(this, wxID_ANY, L""), 1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
pFilesGrid->Add(new wxButton(this, ID_BROWSE_DATA, L"Browse..."), 0, wxALIGN_CENTER_VERTICAL);
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Palette:"), 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
pFilesGrid->Add(m_txtPalette = new wxTextCtrl(this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\Data\\MPalette.dat"), 1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
pFilesGrid->Add(new wxButton(this, ID_BROWSE_PALETTE, L"Browse..."), 0, wxALIGN_CENTER_VERTICAL);
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Table:"), 0,
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
pFilesGrid->Add(
m_txtTable = new wxTextCtrl(
this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\QData\\Font00V.tab"),
1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
pFilesGrid->Add(new wxButton(this, ID_BROWSE_TABLE, L"Browse..."), 0,
wxALIGN_CENTER_VERTICAL);
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Data:"), 0,
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
pFilesGrid->Add(m_txtData = new wxTextCtrl(this, wxID_ANY, L""), 1,
wxALIGN_CENTER_VERTICAL | wxEXPAND);
pFilesGrid->Add(new wxButton(this, ID_BROWSE_DATA, L"Browse..."), 0,
wxALIGN_CENTER_VERTICAL);
pFilesGrid->Add(new wxStaticText(this, wxID_ANY, L"Palette:"), 0,
wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
pFilesGrid->Add(
m_txtPalette = new wxTextCtrl(
this, wxID_ANY, L"X:\\ThemeHospital\\hospital\\Data\\MPalette.dat"),
1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
pFilesGrid->Add(new wxButton(this, ID_BROWSE_PALETTE, L"Browse..."), 0,
wxALIGN_CENTER_VERTICAL);
pFiles->Add(pFilesGrid, 0, wxEXPAND | wxALL, 1);
wxButton* pTmp;
pFiles->Add(pTmp = new wxButton(this, ID_LOAD, L"Load Simple"), 0, wxALIGN_CENTER | wxALL, 1);
pFiles->Add(pTmp = new wxButton(this, ID_LOAD_COMPLEX, L"Load Complex"), 0, wxALIGN_CENTER | wxALL, 1);
pFiles->Add(pTmp = new wxButton(this, ID_NEXT, L"Next"), 0, wxALIGN_CENTER | wxALL, 1);
pFiles->Add(pTmp = new wxButton(this, ID_LOAD, L"Load Simple"), 0,
wxALIGN_CENTER | wxALL, 1);
pFiles->Add(pTmp = new wxButton(this, ID_LOAD_COMPLEX, L"Load Complex"), 0,
wxALIGN_CENTER | wxALL, 1);
pFiles->Add(pTmp = new wxButton(this, ID_NEXT, L"Next"), 0,
wxALIGN_CENTER | wxALL, 1);
SetBackgroundColour(pTmp->GetBackgroundColour());
pMainSizer->Add(pFiles, 0, wxEXPAND | wxALL, 2);
wxStaticBoxSizer *pSprites = new wxStaticBoxSizer(wxVERTICAL, this, L"Sprites");
wxStaticBoxSizer* pSprites =
new wxStaticBoxSizer(wxVERTICAL, this, L"Sprites");
pSprites->Add(m_panFrame = new MyVScrolled(this), 1, wxEXPAND);
pMainSizer->Add(pSprites, 1, wxEXPAND | wxALL, 2);
m_panFrame->Connect(wxEVT_PAINT, (wxObjectEventFunction)&frmSprites::_onPanelPaint, NULL, this);
m_panFrame->Connect(wxEVT_PAINT,
(wxObjectEventFunction)&frmSprites::_onPanelPaint, NULL,
this);
SetSizer(pMainSizer);
load(true);
}
frmSprites::~frmSprites()
{
}
frmSprites::~frmSprites() {}
void frmSprites::_onLoad(wxCommandEvent& evt)
{
load(false);
}
void frmSprites::_onLoad(wxCommandEvent& evt) { load(false); }
void frmSprites::_onLoadComplex(wxCommandEvent& evt)
{
load(true);
}
void frmSprites::_onLoadComplex(wxCommandEvent& evt) { load(true); }
void frmSprites::_onNext(wxCommandEvent& evt)
{
void frmSprites::_onNext(wxCommandEvent& evt) {
wxString s = m_txtTable->GetValue();
while(true)
{
while (true) {
const wxChar* sc = s.c_str();
for(size_t i = s.Length(); i > 0;)
{
for (size_t i = s.Length(); i > 0;) {
--i;
if('0' <= sc[i] && sc[i] <= '9')
{
if ('0' <= sc[i] && sc[i] <= '9') {
s.SetChar(i, sc[i] + 1);
if(sc[i] > '9')
{
if (sc[i] > '9') {
s.SetChar(i, '0');
if(sc[i - 1] == '9')
{
if (sc[i - 1] == '9') {
s.SetChar(i - 1, '0');
return;
}
@@ -113,33 +117,34 @@ void frmSprites::_onNext(wxCommandEvent& evt)
break;
}
}
if(::wxFileExists(s))
{
if (::wxFileExists(s)) {
m_txtTable->SetValue(s);
return;
}
}
}
void frmSprites::load(bool bComplex)
{
if(!m_oAnims.loadTableFile(m_txtTable->GetValue())
||!m_oAnims.loadSpriteFile(m_txtData->GetValue().IsEmpty() ? m_txtTable->GetValue().BeforeLast('.')+L".DAT" : m_txtData->GetValue())
||!m_oAnims.loadPaletteFile(m_txtPalette->GetValue()))
{
void frmSprites::load(bool bComplex) {
if (!m_oAnims.loadTableFile(m_txtTable->GetValue()) ||
!m_oAnims.loadSpriteFile(m_txtData->GetValue().IsEmpty()
? m_txtTable->GetValue().BeforeLast('.') +
L".DAT"
: m_txtData->GetValue()) ||
!m_oAnims.loadPaletteFile(m_txtPalette->GetValue())) {
::wxMessageBox(L"Cannot load files");
return;
}
m_vSprites.clear();
for(size_t i = 0; i < m_oAnims.getSpriteCount(); ++i)
{
for (size_t i = 0; i < m_oAnims.getSpriteCount(); ++i) {
_sprite_t oSprite;
Bitmap* pSpriteBitmap = m_oAnims.getSpriteBitmap(i, bComplex);
oSprite.caption = wxString::Format(L"#%i (%ix%i)", (int)i, pSpriteBitmap->getWidth(), pSpriteBitmap->getHeight());
if(pSpriteBitmap->getWidth() * pSpriteBitmap->getHeight() > 0)
{
wxImage imgSprite(pSpriteBitmap->getWidth(), pSpriteBitmap->getHeight(), false);
oSprite.caption =
wxString::Format(L"#%i (%ix%i)", (int)i, pSpriteBitmap->getWidth(),
pSpriteBitmap->getHeight());
if (pSpriteBitmap->getWidth() * pSpriteBitmap->getHeight() > 0) {
wxImage imgSprite(pSpriteBitmap->getWidth(), pSpriteBitmap->getHeight(),
false);
pSpriteBitmap->blit(imgSprite, 0, 0, NULL, m_oAnims.getPalette(), 0x8000);
oSprite.bitmap = wxBitmap(imgSprite);
}
@@ -149,8 +154,7 @@ void frmSprites::load(bool bComplex)
m_panFrame->Refresh();
}
void frmSprites::_onPanelPaint(wxPaintEvent& evt)
{
void frmSprites::_onPanelPaint(wxPaintEvent& evt) {
wxPaintDC dc(m_panFrame);
int iAvailableWidth, iAvailableHeight;
@@ -160,14 +164,15 @@ void frmSprites::_onPanelPaint(wxPaintEvent& evt)
int iTotal = 0;
int iY = -m_panFrame->GetVisibleRowsBegin();
for(std::vector<_sprite_t>::iterator itr = m_vSprites.begin(), itrEnd = m_vSprites.end();
itr != itrEnd; ++itr)
{
for (std::vector<_sprite_t>::iterator itr = m_vSprites.begin(),
itrEnd = m_vSprites.end();
itr != itrEnd; ++itr) {
wxSize szLabel = dc.GetTextExtent(itr->caption);
int iWidth = wxMax(szLabel.GetWidth(), itr->bitmap.IsOk() ? itr->bitmap.GetWidth() : 0);
int iHeight = (itr->bitmap.IsOk() ? itr->bitmap.GetHeight() : 0) + szLabel.GetHeight() + 2;
if(iWidth + iX > iAvailableWidth)
{
int iWidth = wxMax(szLabel.GetWidth(),
itr->bitmap.IsOk() ? itr->bitmap.GetWidth() : 0);
int iHeight = (itr->bitmap.IsOk() ? itr->bitmap.GetHeight() : 0) +
szLabel.GetHeight() + 2;
if (iWidth + iX > iAvailableWidth) {
iY += iTallest;
iTotal += iTallest;
iX = iTallest = 0;
@@ -192,19 +197,20 @@ void frmSprites::_onPanelPaint(wxPaintEvent& evt)
}
}
void frmSprites::_onBrowseTable(wxCommandEvent& WXUNUSED(evt))
{
m_txtTable->SetValue(::wxFileSelector(L"Select location of Font00V.tab (DATA)",
m_txtTable->GetValue(),L"Font00V.tab",L"tab",L"Tab files (*.tab)|*.[tT][aA][bB]"
,0, this));
void frmSprites::_onBrowseTable(wxCommandEvent& WXUNUSED(evt)) {
m_txtTable->SetValue(::wxFileSelector(
L"Select location of Font00V.tab (DATA)", m_txtTable->GetValue(),
L"Font00V.tab", L"tab", L"Tab files (*.tab)|*.[tT][aA][bB]", 0, this));
}
void frmSprites::_onBrowseData(wxCommandEvent& WXUNUSED(evt))
{
m_txtData->SetValue(::wxFileSelector(L"Choose Theme Hospital data file",
m_txtData->GetValue(),L"",L"dat",L"Dat files (*.dat)|*.[dD][aA][tT]", 0, this));
void frmSprites::_onBrowseData(wxCommandEvent& WXUNUSED(evt)) {
m_txtData->SetValue(::wxFileSelector(
L"Choose Theme Hospital data file", m_txtData->GetValue(), L"", L"dat",
L"Dat files (*.dat)|*.[dD][aA][tT]", 0, this));
}
void frmSprites::_onBrowsePalette(wxCommandEvent& WXUNUSED(evt))
{
m_txtPalette->SetValue(::wxFileSelector(L"Select location of MPalette.dat (QDATA)",
m_txtPalette->GetValue(),L"MPalette.dat",L"dat",L"Dat or Pal files (*.dat, *.pal)|*.[dD][aA][tT];*.[pP][aA][lL]", 0, this));
void frmSprites::_onBrowsePalette(wxCommandEvent& WXUNUSED(evt)) {
m_txtPalette->SetValue(::wxFileSelector(
L"Select location of MPalette.dat (QDATA)", m_txtPalette->GetValue(),
L"MPalette.dat", L"dat",
L"Dat or Pal files (*.dat, *.pal)|*.[dD][aA][tT];*.[pP][aA][lL]", 0,
this));
}

View File

@@ -24,23 +24,25 @@ SOFTWARE.
#include "config.h"
#include <wx/bitmap.h>
#include <wx/frame.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/textctrl.h>
#include <wx/panel.h>
#include <wx/timer.h>
#include <wx/frame.h>
#include <wx/listbox.h>
#include <wx/panel.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
#include <wx/vscroll.h>
#include "th.h"
#include <vector>
#include "th.h"
static const int ROW_COUNT = 1000;
// Derived class to add scrollbars to the window.
class MyVScrolled : public wxVScrolledWindow {
public:
MyVScrolled(wxWindow *parent) : wxVScrolledWindow(parent, wxID_ANY) { iMyCount = ROW_COUNT; }
MyVScrolled(wxWindow* parent) : wxVScrolledWindow(parent, wxID_ANY) {
iMyCount = ROW_COUNT;
}
wxCoord OnGetRowHeight(size_t row) const { return 1; }
@@ -49,14 +51,12 @@ public:
int iMyCount;
};
class frmSprites : public wxFrame
{
class frmSprites : public wxFrame {
public:
frmSprites();
~frmSprites();
enum
{
enum {
ID_LOAD = wxID_HIGHEST + 1,
ID_BROWSE_TABLE,
ID_BROWSE_DATA,
@@ -66,9 +66,9 @@ public:
};
void load(bool bComplex);
protected:
struct _sprite_t
{
struct _sprite_t {
wxBitmap bitmap;
wxString caption;
};

View File

@@ -20,34 +20,30 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "th.h"
#include "../common/rnc.h"
#include "config.h"
#include <wx/app.h>
#include <wx/toplevel.h>
#include <wx/filename.h>
#include <wx/toplevel.h>
#include <algorithm>
#include <array>
#include <set>
#include <stdexcept>
#include <vector>
#include "../common/rnc.h"
static const unsigned char palette_upscale_map[0x40] = {
0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
0x20, 0x24, 0x28, 0x2D, 0x31, 0x35, 0x39, 0x3D,
0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
0xC2, 0xC6, 0xCA, 0xCE, 0xD2, 0xD7, 0xDB, 0xDF,
0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF,
0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28,
0x2D, 0x31, 0x35, 0x39, 0x3D, 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55,
0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, 0x82,
0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, 0xA2, 0xA6, 0xAA, 0xAE,
0xB2, 0xB6, 0xBA, 0xBE, 0xC2, 0xC6, 0xCA, 0xCE, 0xD2, 0xD7, 0xDB,
0xDF, 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF,
};
class ChunkRenderer
{
class ChunkRenderer {
public:
ChunkRenderer(int width, int height, unsigned char *buffer = NULL)
{
ChunkRenderer(int width, int height, unsigned char* buffer = NULL) {
m_data = buffer ? buffer : new unsigned char[width * height];
m_ptr = m_data;
m_end = m_data + width * height;
@@ -58,73 +54,51 @@ public:
m_skip_eol = false;
}
~ChunkRenderer()
{
delete[] m_data;
}
~ChunkRenderer() { delete[] m_data; }
bool isDone() const
{
return m_ptr == m_end;
}
bool isDone() const { return m_ptr == m_end; }
unsigned char* takeData()
{
unsigned char* takeData() {
unsigned char* buffer = m_data;
m_data = 0;
return buffer;
}
const unsigned char* getData() const
{
return m_data;
}
const unsigned char* getData() const { return m_data; }
void chunkFillToEndOfLine(unsigned char value)
{
if(m_x != 0 || !m_skip_eol)
{
void chunkFillToEndOfLine(unsigned char value) {
if (m_x != 0 || !m_skip_eol) {
chunkFill(m_width - m_x, value);
}
m_skip_eol = false;
}
void chunkFinish(unsigned char value)
{
chunkFill(m_end - m_ptr, value);
}
void chunkFinish(unsigned char value) { chunkFill(m_end - m_ptr, value); }
void chunkFill(int npixels, unsigned char value)
{
void chunkFill(int npixels, unsigned char value) {
_fixNpixels(npixels);
if(npixels > 0)
{
if (npixels > 0) {
memset(m_ptr, value, npixels);
_incrementPosition(npixels);
}
}
void chunkCopy(int npixels, const unsigned char* data)
{
void chunkCopy(int npixels, const unsigned char* data) {
_fixNpixels(npixels);
if(npixels > 0)
{
if (npixels > 0) {
memcpy(m_ptr, data, npixels);
_incrementPosition(npixels);
}
}
protected:
inline void _fixNpixels(int& npixels) const
{
if(m_ptr + npixels > m_end)
{
inline void _fixNpixels(int& npixels) const {
if (m_ptr + npixels > m_end) {
npixels = m_end - m_ptr;
}
}
inline void _incrementPosition(int npixels)
{
inline void _incrementPosition(int npixels) {
m_ptr += npixels;
m_x += npixels;
m_y += m_x / m_width;
@@ -137,78 +111,58 @@ protected:
bool m_skip_eol;
};
static void decode_chunks(ChunkRenderer& renderer, const unsigned char* data, int datalen, unsigned char transparent)
{
while(!renderer.isDone() && datalen > 0)
{
static void decode_chunks(ChunkRenderer& renderer, const unsigned char* data,
int datalen, unsigned char transparent) {
while (!renderer.isDone() && datalen > 0) {
unsigned char b = *data;
--datalen;
++data;
if(b == 0)
{
if (b == 0) {
renderer.chunkFillToEndOfLine(transparent);
}
else if(b < 0x80)
{
} else if (b < 0x80) {
int amt = b;
if(datalen < amt)
amt = datalen;
if (datalen < amt) amt = datalen;
renderer.chunkCopy(amt, data);
data += amt;
datalen -= amt;
}
else
{
} else {
renderer.chunkFill(0x100 - b, transparent);
}
}
renderer.chunkFinish(transparent);
}
static void decode_chunks_complex(ChunkRenderer& renderer, const unsigned char* data, int datalen, unsigned char transparent)
{
while(!renderer.isDone() && datalen > 0)
{
static void decode_chunks_complex(ChunkRenderer& renderer,
const unsigned char* data, int datalen,
unsigned char transparent) {
while (!renderer.isDone() && datalen > 0) {
unsigned char b = *data;
--datalen;
++data;
if(b == 0)
{
if (b == 0) {
renderer.chunkFillToEndOfLine(transparent);
}
else if(b < 0x40)
{
} else if (b < 0x40) {
int amt = b;
if(datalen < amt)
amt = datalen;
if (datalen < amt) amt = datalen;
renderer.chunkCopy(amt, data);
data += amt;
datalen -= amt;
}
else if((b & 0xC0) == 0x80)
{
} else if ((b & 0xC0) == 0x80) {
renderer.chunkFill(b - 0x80, transparent);
}
else
{
} else {
int amt;
unsigned char colour = 0;
if(b == 0xFF)
{
if(datalen < 2)
{
if (b == 0xFF) {
if (datalen < 2) {
break;
}
amt = (int)data[0];
colour = data[1];
data += 2;
datalen -= 2;
}
else
{
} else {
amt = b - 60 - (b & 0x80) / 2;
if(datalen > 0)
{
if (datalen > 0) {
colour = *data;
++data;
--datalen;
@@ -220,19 +174,13 @@ static void decode_chunks_complex(ChunkRenderer& renderer, const unsigned char*
renderer.chunkFinish(transparent);
}
THLayerMask::THLayerMask()
{
clear();
THLayerMask::THLayerMask() { clear(); }
void THLayerMask::clear() {
for (int i = 0; i < 13; ++i) m_iMask[i] = 0;
}
void THLayerMask::clear()
{
for(int i = 0; i < 13; ++i)
m_iMask[i] = 0;
}
THAnimations::THAnimations()
{
THAnimations::THAnimations() {
anims = std::vector<th_anim_t>();
frames = std::vector<th_frame_t>();
elementList = std::vector<uint16_t>();
@@ -242,39 +190,31 @@ THAnimations::THAnimations()
chunks = std::vector<uint8_t>();
colours = std::vector<th_colour_t>();
ghostMaps = std::array<unsigned char, 256 * 256 * 4>();
for(int iMap = 0; iMap < 256 * 4; ++iMap)
{
for(int iCol = 0; iCol < 256; ++iCol)
{
for (int iMap = 0; iMap < 256 * 4; ++iMap) {
for (int iCol = 0; iCol < 256; ++iCol) {
ghostMaps[iMap * 256 + iCol] = iCol;
}
}
m_iGhostMapOffset = 0;
}
THAnimations::~THAnimations()
{
}
THAnimations::~THAnimations() {}
bool THAnimations::isAnimationDuplicate(size_t iAnimation)
{
bool THAnimations::isAnimationDuplicate(size_t iAnimation) {
if (iAnimation < anims.size())
return anims.at(iAnimation).unknown == 1;
else
return true;
}
size_t THAnimations::markDuplicates()
{
size_t THAnimations::markDuplicates() {
size_t iNonDuplicateCount = 0;
std::set<uint16_t> seen;
for(th_anim_t& anim : anims)
{
for (th_anim_t& anim : anims) {
uint16_t iFrame = anim.frame;
uint16_t iFirstFrame = iFrame;
do
{
do {
if (seen.find(iFrame) != seen.end()) {
anim.unknown = 1;
} else {
@@ -283,8 +223,7 @@ size_t THAnimations::markDuplicates()
iFrame = frames.at(iFrame).next;
} while (iFrame != iFirstFrame);
if(anim.unknown == 0)
{
if (anim.unknown == 0) {
++iNonDuplicateCount;
}
}
@@ -292,10 +231,8 @@ size_t THAnimations::markDuplicates()
return iNonDuplicateCount;
}
bool THAnimations::loadFrameFile(wxString sFilename)
{
if(!loadVector(frames, sFilename))
return false;
bool THAnimations::loadFrameFile(wxString sFilename) {
if (!loadVector(frames, sFilename)) return false;
/*
256 is a common flag - could be x-flip.
@@ -306,21 +243,16 @@ bool THAnimations::loadFrameFile(wxString sFilename)
return true;
}
bool THAnimations::loadTableFile(wxString sFilename)
{
bool THAnimations::loadTableFile(wxString sFilename) {
spriteBitmaps.clear();
if(!loadVector(sprites, sFilename))
return false;
if (!loadVector(sprites, sFilename)) return false;
spriteBitmaps.resize(sprites.size());
return true;
}
bool THAnimations::loadPaletteFile(wxString sFilename)
{
if (!loadVector(colours, sFilename))
return false;
for (th_colour_t& colour : colours)
{
bool THAnimations::loadPaletteFile(wxString sFilename) {
if (!loadVector(colours, sFilename)) return false;
for (th_colour_t& colour : colours) {
colour.r = palette_upscale_map[colour.r & 0x3F];
colour.g = palette_upscale_map[colour.g & 0x3F];
colour.b = palette_upscale_map[colour.b & 0x3F];
@@ -328,15 +260,12 @@ bool THAnimations::loadPaletteFile(wxString sFilename)
return true;
}
bool THAnimations::loadGhostFile(wxString sFilename, int iIndex)
{
if(iIndex < 0 || iIndex >= 4)
return false;
bool THAnimations::loadGhostFile(wxString sFilename, int iIndex) {
if (iIndex < 0 || iIndex >= 4) return false;
std::vector<unsigned char> data;
if (!loadVector(data, sFilename))
return false;
if (!loadVector(data, sFilename)) return false;
if (data.size() != 256 * 256) {
return false;
@@ -346,62 +275,43 @@ bool THAnimations::loadGhostFile(wxString sFilename, int iIndex)
return true;
}
void THAnimations::setGhost(int iFile, int iIndex)
{
void THAnimations::setGhost(int iFile, int iIndex) {
m_iGhostMapOffset = iFile * 256 * 256 + iIndex * 256;
}
size_t THAnimations::getAnimationCount()
{
return anims.size();
}
size_t THAnimations::getAnimationCount() { return anims.size(); }
size_t THAnimations::getSpriteCount()
{
return sprites.size();
}
size_t THAnimations::getSpriteCount() { return sprites.size(); }
void THAnimations::setSpritePath(wxString aPath)
{
m_sSpritePath = aPath;
}
void THAnimations::setSpritePath(wxString aPath) { m_sSpritePath = aPath; }
void THAnimations::getAnimationMask(size_t iAnimation, THLayerMask& mskLayers)
{
void THAnimations::getAnimationMask(size_t iAnimation, THLayerMask& mskLayers) {
mskLayers.clear();
if(iAnimation >= anims.size())
return;
if (iAnimation >= anims.size()) return;
uint16_t iFrameIndex = anims.at(iAnimation).frame;
if(iFrameIndex >= frames.size())
return;
if (iFrameIndex >= frames.size()) return;
uint16_t iFirstFrameIndex = iFrameIndex;
do
{
do {
th_frame_t* pFrame = &(frames.at(iFrameIndex));
uint32_t iListIndex = pFrame->list_index;
th_element_t* pElement;
while((pElement = _getElement(iListIndex++)))
{
while ((pElement = _getElement(iListIndex++))) {
mskLayers.set(pElement->flags >> 4, pElement->layerid);
}
iFrameIndex = frames.at(iFrameIndex).next;
} while (iFrameIndex < frames.size() && iFrameIndex != iFirstFrameIndex);
}
size_t THAnimations::getFrameCount(size_t iAnimation)
{
if(iAnimation >= anims.size())
return 0;
size_t THAnimations::getFrameCount(size_t iAnimation) {
if (iAnimation >= anims.size()) return 0;
size_t iCount = 0;
uint16_t iFirstFrame = anims.at(iAnimation).frame;
if(iFirstFrame < frames.size())
{
if (iFirstFrame < frames.size()) {
++iCount;
uint16_t iFrame = frames.at(iFirstFrame).next;
while(iFrame != iFirstFrame && iFrame < frames.size() && iCount < 1024)
{
while (iFrame != iFirstFrame && iFrame < frames.size() && iCount < 1024) {
++iCount;
iFrame = frames.at(iFrame).next;
}
@@ -409,60 +319,52 @@ size_t THAnimations::getFrameCount(size_t iAnimation)
return iCount;
}
bool THAnimations::doesAnimationIncludeFrame(size_t iAnimation, size_t iFrame)
{
if(iAnimation >= anims.size() || iFrame >= frames.size())
return 0;
bool THAnimations::doesAnimationIncludeFrame(size_t iAnimation, size_t iFrame) {
if (iAnimation >= anims.size() || iFrame >= frames.size()) return 0;
uint16_t iFirstFrame = anims.at(iAnimation).frame;
uint16_t iFrameNow = iFirstFrame;
do
{
if(iFrameNow >= frames.size())
break;
if(iFrame == iFrameNow)
return true;
do {
if (iFrameNow >= frames.size()) break;
if (iFrame == iFrameNow) return true;
iFrameNow = frames.at(iFrameNow).next;
} while (iFrameNow != iFirstFrame);
return false;
}
Bitmap* THAnimations::getSpriteBitmap(size_t iSprite, bool bComplex)
{
if(iSprite >= sprites.size())
return nullptr;
Bitmap* THAnimations::getSpriteBitmap(size_t iSprite, bool bComplex) {
if (iSprite >= sprites.size()) return nullptr;
if (!spriteBitmaps.at(iSprite).IsOk())
{
wxString spriteFile = m_sSpritePath + wxString::Format(L"a%04ue.png", (int)iSprite);
if (!spriteBitmaps.at(iSprite).IsOk()) {
wxString spriteFile =
m_sSpritePath + wxString::Format(L"a%04ue.png", (int)iSprite);
th_sprite_t* pSprite = &(sprites.at(iSprite));
ChunkRenderer oRenderer(pSprite->width, pSprite->height);
(bComplex ? decode_chunks_complex : decode_chunks)(oRenderer, (const unsigned char*)chunks.data() + pSprite->offset, chunks.size() - pSprite->offset, 0xFF);
spriteBitmaps[iSprite].create(pSprite->width, pSprite->height, oRenderer.getData());
(bComplex ? decode_chunks_complex : decode_chunks)(
oRenderer, (const unsigned char*)chunks.data() + pSprite->offset,
chunks.size() - pSprite->offset, 0xFF);
spriteBitmaps[iSprite].create(pSprite->width, pSprite->height,
oRenderer.getData());
}
return &(spriteBitmaps.at(iSprite));
}
th_frame_t* THAnimations::getFrameStruct(size_t iAnimation, size_t iFrame)
{
if(iAnimation >= anims.size())
return 0;
th_frame_t* THAnimations::getFrameStruct(size_t iAnimation, size_t iFrame) {
if (iAnimation >= anims.size()) return 0;
uint16_t iFrameIndex = anims.at(iAnimation).frame;
while(iFrame--)
{
while (iFrame--) {
iFrameIndex = frames.at(iFrameIndex).next;
}
return &(frames.at(iFrameIndex));
}
void THAnimations::drawFrame(wxImage& imgCanvas, size_t iAnimation, size_t iFrame, const THLayerMask* pMask, wxSize& size, int iXOffset, int iYOffset)
{
if(iAnimation >= anims.size())
return;
void THAnimations::drawFrame(wxImage& imgCanvas, size_t iAnimation,
size_t iFrame, const THLayerMask* pMask,
wxSize& size, int iXOffset, int iYOffset) {
if (iAnimation >= anims.size()) return;
uint16_t iFrameIndex = anims.at(iAnimation).frame;
while(iFrame--)
{
while (iFrame--) {
iFrameIndex = frames.at(iFrameIndex).next;
}
@@ -471,37 +373,33 @@ void THAnimations::drawFrame(wxImage& imgCanvas, size_t iAnimation, size_t iFram
uint32_t iListIndex = pFrame->list_index;
int iFarX = 0;
int iFarY = 0;
while((pElement = _getElement(iListIndex++)))
{
while ((pElement = _getElement(iListIndex++))) {
if (pMask != NULL && !pMask->isSet(pElement->flags >> 4, pElement->layerid))
continue;
uint16_t iSpriteIndex = pElement->table_position / sizeof(th_sprite_t);
th_sprite_t* pSprite = &(sprites.at(iSpriteIndex));
int iRight = pElement->offx + pSprite->width;
int iBottom = pElement->offy + pSprite->height;
if(iRight > iFarX)
iFarX = iRight;
if(iBottom > iFarY)
iFarY = iBottom;
if (iRight > iFarX) iFarX = iRight;
if (iBottom > iFarY) iFarY = iBottom;
getSpriteBitmap(iSpriteIndex)->blit(imgCanvas, pElement->offx + iXOffset, pElement->offy + iYOffset, ghostMaps.data() + m_iGhostMapOffset, colours.data(), pElement->flags & 0xF);
getSpriteBitmap(iSpriteIndex)
->blit(imgCanvas, pElement->offx + iXOffset, pElement->offy + iYOffset,
ghostMaps.data() + m_iGhostMapOffset, colours.data(),
pElement->flags & 0xF);
}
size.x = iFarX;
size.y = iFarY;
}
th_element_t* THAnimations::_getElement(uint32_t iListIndex)
{
if(iListIndex >= elementList.size())
return nullptr;
th_element_t* THAnimations::_getElement(uint32_t iListIndex) {
if (iListIndex >= elementList.size()) return nullptr;
uint16_t iElementIndex = elementList.at(iListIndex);
if(iElementIndex >= elements.size())
return nullptr;
if (iElementIndex >= elements.size()) return nullptr;
return &(elements.at(iElementIndex));
}
unsigned char* THAnimations::Decompress(unsigned char* pData, size_t& iLength)
{
unsigned char* THAnimations::Decompress(unsigned char* pData, size_t& iLength) {
if (rnc_input_size(pData) != iLength) {
throw std::length_error("rnc data does not match the expected length");
}
@@ -509,14 +407,11 @@ unsigned char* THAnimations::Decompress(unsigned char* pData, size_t& iLength)
unsigned long outlen = rnc_output_size(pData);
unsigned char* outbuf = new unsigned char[outlen];
if(rnc_unpack(pData, outbuf) == rnc_status::ok)
{
if (rnc_unpack(pData, outbuf) == rnc_status::ok) {
delete[] pData;
iLength = outlen;
return outbuf;
}
else
{
} else {
delete[] pData;
delete[] outbuf;
iLength = 0;
@@ -524,20 +419,11 @@ unsigned char* THAnimations::Decompress(unsigned char* pData, size_t& iLength)
}
}
Bitmap::Bitmap() :
m_iWidth(0),
m_iHeight(0),
m_pData(nullptr)
{
}
Bitmap::Bitmap() : m_iWidth(0), m_iHeight(0), m_pData(nullptr) {}
Bitmap::~Bitmap()
{
delete[] m_pData;
}
Bitmap::~Bitmap() { delete[] m_pData; }
void Bitmap::create(int iWidth, int iHeight)
{
void Bitmap::create(int iWidth, int iHeight) {
delete[] m_pData;
m_pData = new uint8_t[iWidth * iHeight];
m_iWidth = iWidth;
@@ -545,8 +431,7 @@ void Bitmap::create(int iWidth, int iHeight)
memset(m_pData, 0xFF, iWidth * iHeight);
}
void Bitmap::create(int iWidth, int iHeight, const uint8_t* pData)
{
void Bitmap::create(int iWidth, int iHeight, const uint8_t* pData) {
delete[] m_pData;
m_pData = new uint8_t[iWidth * iHeight];
m_iWidth = iWidth;
@@ -554,69 +439,52 @@ void Bitmap::create(int iWidth, int iHeight, const uint8_t* pData)
memcpy(m_pData, pData, iWidth * iHeight);
}
void Bitmap::blit(Bitmap& bmpCanvas, int iX, int iY, int iFlags) const
{
for(int y = 0; y < m_iHeight; ++y)
{
for(int x = 0; x < m_iWidth; ++x)
{
void Bitmap::blit(Bitmap& bmpCanvas, int iX, int iY, int iFlags) const {
for (int y = 0; y < m_iHeight; ++y) {
for (int x = 0; x < m_iWidth; ++x) {
uint8_t src = pixel(x, y);
if(src == 0xFF)
continue;
if (src == 0xFF) continue;
int iDstX = iX + x;
int iDstY = iY + y;
if(iFlags & 0x2)
iDstY = iY + m_iHeight - 1 - y;
if(iFlags & 0x1)
iDstX = iX + m_iWidth - 1 - x;
if (iFlags & 0x2) iDstY = iY + m_iHeight - 1 - y;
if (iFlags & 0x1) iDstX = iX + m_iWidth - 1 - x;
bmpCanvas.pixel(iDstX, iDstY) = src;
}
}
}
static inline void _merge(th_colour_t& dst, const th_colour_t& src)
{
static inline void _merge(th_colour_t& dst, const th_colour_t& src) {
dst.r = (uint8_t)(((unsigned int)dst.r + (unsigned int)src.r) / 2);
dst.g = (uint8_t)(((unsigned int)dst.g + (unsigned int)src.g) / 2);
dst.b = (uint8_t)(((unsigned int)dst.b + (unsigned int)src.b) / 2);
}
void Bitmap::blit(wxImage& imgCanvas, int iX, int iY, const unsigned char* pColourTranslate, const th_colour_t* pPalette, int iFlags) const
{
if(m_iHeight == 0 || m_iWidth == 0)
return;
void Bitmap::blit(wxImage& imgCanvas, int iX, int iY,
const unsigned char* pColourTranslate,
const th_colour_t* pPalette, int iFlags) const {
if (m_iHeight == 0 || m_iWidth == 0) return;
th_colour_t* pCanvas = (th_colour_t*)imgCanvas.GetData();
int iCanvasWidth = imgCanvas.GetWidth();
if(m_iHeight > 256 || m_iWidth > 256)
{
if (m_iHeight > 256 || m_iWidth > 256) {
return;
}
for(int y = 0; y < m_iHeight; ++y)
{
for(int x = 0; x < m_iWidth; ++x)
{
for (int y = 0; y < m_iHeight; ++y) {
for (int x = 0; x < m_iWidth; ++x) {
uint8_t src = pixel(x, y);
if(src == 0xFF && (iFlags & 0x8000) == 0)
continue;
if(pColourTranslate != NULL)
{
if (src == 0xFF && (iFlags & 0x8000) == 0) continue;
if (pColourTranslate != NULL) {
src = pColourTranslate[src];
if(src == 0xFF && (iFlags & 0x8000) == 0)
continue;
if (src == 0xFF && (iFlags & 0x8000) == 0) continue;
}
int iDstX = iX + x;
int iDstY = iY + y;
if(iFlags & 0x2)
iDstY = iY + m_iHeight - 1 - y;
if(iFlags & 0x1)
iDstX = iX + m_iWidth - 1 - x;
if (iFlags & 0x2) iDstY = iY + m_iHeight - 1 - y;
if (iFlags & 0x1) iDstX = iX + m_iWidth - 1 - x;
th_colour_t srcc = pPalette[src];
if(iFlags & 0xC)
{
if (iFlags & 0xC) {
th_colour_t dstc = pCanvas[iDstY * iCanvasWidth + iDstX];
switch(iFlags & 0xC)
{
switch (iFlags & 0xC) {
case 0x8:
_merge(srcc, dstc);
// fall-through
@@ -626,8 +494,7 @@ void Bitmap::blit(wxImage& imgCanvas, int iX, int iY, const unsigned char* pColo
}
}
pCanvas[iDstY * iCanvasWidth + iDstX] = srcc;
if(imgCanvas.HasAlpha())
{
if (imgCanvas.HasAlpha()) {
// set completely opaque
imgCanvas.SetAlpha(iDstX, iDstY, (unsigned char)255);
}

View File

@@ -36,25 +36,23 @@ SOFTWARE.
#pragma once
#include "config.h"
#include <wx/string.h>
#include <stdint.h>
#include <wx/file.h>
#include <wx/image.h>
#include <wx/string.h>
#include <wx/txtstrm.h>
#include <array>
#include <stdint.h>
#include <vector>
#pragma pack(push)
#pragma pack(1)
struct th_anim_t
{
struct th_anim_t {
uint16_t frame;
uint16_t unknown;
};
struct th_frame_t
{
struct th_frame_t {
uint32_t list_index;
uint8_t width;
uint8_t height;
@@ -62,8 +60,7 @@ struct th_frame_t
uint16_t next;
};
struct th_element_t
{
struct th_element_t {
uint16_t table_position;
uint8_t offx;
uint8_t offy;
@@ -71,15 +68,13 @@ struct th_element_t
uint8_t layerid;
};
struct th_sprite_t
{
struct th_sprite_t {
uint32_t offset;
uint8_t width;
uint8_t height;
};
struct th_colour_t
{
struct th_colour_t {
uint8_t r;
uint8_t g;
uint8_t b;
@@ -87,37 +82,31 @@ struct th_colour_t
#pragma pack(pop)
class THLayerMask
{
class THLayerMask {
public:
THLayerMask();
inline void set(int iLayer, int iID)
{
inline void set(int iLayer, int iID) {
if (0 <= iLayer && iLayer < 13 && 0 <= iID && iID < 32)
m_iMask[iLayer] |= (1 << iID);
}
void clear();
inline void clear(int iLayer, int iID)
{
inline void clear(int iLayer, int iID) {
if (0 <= iLayer && iLayer < 13 && 0 <= iID && iID < 32)
m_iMask[iLayer] &= ~(1 << iID);
}
inline bool isSet(int iLayer, int iID) const
{
inline bool isSet(int iLayer, int iID) const {
if (0 <= iLayer && iLayer < 13 && 0 <= iID && iID < 32)
return (m_iMask[iLayer] & (1 << iID)) != 0;
else
return false;
}
inline bool isSet(int iLayer) const
{
inline bool isSet(int iLayer) const {
if (0 <= iLayer && iLayer < 13)
for(int iId = 0; iId < 32; ++iId)
{
for (int iId = 0; iId < 32; ++iId) {
if ((m_iMask[iLayer] & (static_cast<std::uint32_t>(1) << iId)) != 0)
return true;
}
@@ -128,8 +117,7 @@ protected:
uint32_t m_iMask[13];
};
class Bitmap
{
class Bitmap {
public:
Bitmap();
~Bitmap();
@@ -137,14 +125,18 @@ public:
void create(int iWidth, int iHeight);
void create(int iWidth, int iHeight, const uint8_t* pData);
inline uint8_t pixel(int iX, int iY) const {return m_pData[iY * m_iWidth + iX];}
inline uint8_t pixel(int iX, int iY) const {
return m_pData[iY * m_iWidth + iX];
}
inline uint8_t& pixel(int iX, int iY) { return m_pData[iY * m_iWidth + iX]; }
int getWidth() const { return m_iWidth; }
int getHeight() const { return m_iHeight; }
void blit(Bitmap& bmpCanvas, int iX, int iY, int iFlags = 0) const;
void blit(wxImage& imgCanvas, int iX, int iY, const unsigned char* pColourTranslate, const th_colour_t* pPalette, int iFlags = 0) const;
void blit(wxImage& imgCanvas, int iX, int iY,
const unsigned char* pColourTranslate, const th_colour_t* pPalette,
int iFlags = 0) const;
bool IsOk() { return m_pData != nullptr; }
@@ -154,8 +146,7 @@ protected:
uint8_t* m_pData;
};
class THAnimations
{
class THAnimations {
public:
THAnimations();
~THAnimations();
@@ -189,8 +180,12 @@ public:
size_t getAnimationCount();
size_t getSpriteCount();
size_t getFrameCount(size_t iAnimation);
uint16_t getUnknownField(size_t iAnimation) {return anims.at(iAnimation).unknown; }
uint16_t getFrameField(size_t iAnimation) {return anims.at(iAnimation).frame; }
uint16_t getUnknownField(size_t iAnimation) {
return anims.at(iAnimation).unknown;
}
uint16_t getFrameField(size_t iAnimation) {
return anims.at(iAnimation).frame;
}
th_frame_t* getFrameStruct(size_t iAnimation, size_t iFrame);
bool isAnimationDuplicate(size_t iAnimation);
bool doesAnimationIncludeFrame(size_t iAnimation, size_t iFrame);
@@ -201,27 +196,28 @@ public:
th_colour_t* getPalette() { return colours.data(); }
void setGhost(int iFile, int iIndex);
void drawFrame(wxImage& imgCanvas, size_t iAnimation, size_t iFrame, const THLayerMask* pMask, wxSize& size, int iXOffset = 0, int iYOffset = 0);
void copySpriteToCanvas(wxString spriteFile, int iSpriteIndex, wxImage& imgCanvas, int iX, int iY, int iFlags = 0);
void drawFrame(wxImage& imgCanvas, size_t iAnimation, size_t iFrame,
const THLayerMask* pMask, wxSize& size, int iXOffset = 0,
int iYOffset = 0);
void copySpriteToCanvas(wxString spriteFile, int iSpriteIndex,
wxImage& imgCanvas, int iX, int iY, int iFlags = 0);
static unsigned char* Decompress(unsigned char* pData, size_t& iLength);
protected:
template <class T>
bool loadVector(std::vector<T>& vector, wxString sFilename) {
vector.clear();
wxFile oFile(sFilename);
if (!oFile.IsOpened())
return false;
if (!oFile.IsOpened()) return false;
size_t iLen = oFile.Length();
unsigned char* pBuffer = new unsigned char[iLen];
oFile.Read(pBuffer, iLen);
if(memcmp(pBuffer, "RNC\001", 4) == 0)
{
if (memcmp(pBuffer, "RNC\001", 4) == 0) {
pBuffer = Decompress(pBuffer, iLen);
if(!pBuffer)
{
if (!pBuffer) {
return false;
}
}

View File

@@ -19,11 +19,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include <array>
#include <cstring>
#include "lua.hpp"
#include "th_lua.h"
#include "config.h"
#include <cstring>
#include <array>
/* Often, an error occurs during the CorsixTH startup process. Examples of
such errors include:
@@ -42,9 +42,10 @@ homemade bitmap font, as we cannot rely on TH fonts being present).
namespace {
// clang-format off
constexpr int first_bootstrap_code_line_number = __LINE__ + 2;
constexpr std::array<const char*, 45> bootstrap_code {{
"local lines, dat, tab, pal, err = {}, ...",
constexpr std::array<const char*, 45> bootstrap_code{
{"local lines, dat, tab, pal, err = {}, ...",
"local function t(s) return s:gsub('\\t', ' ') end",
"for s in tostring(err):gmatch'[^\\r\\n]+' do lines[#lines+1] = t(s) end",
"local TH, SDL, rnc = require'TH', require'sdl', require'rnc'.decompress",
@@ -88,203 +89,207 @@ constexpr std::array<const char*, 45> bootstrap_code {{
" end))",
" if running then print(e) end",
"until where ~= 'callback'",
nullptr
}};
nullptr}};
// clang-format on
/* Start autogenerated content */
/* Data from bootstrap_font.tab inserted by mkbootstrap.lua: */
constexpr std::array<uint8_t, 499> bootstrap_font_tab{
0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x05, 0x46, 0x00, 0x00, 0x01, 0xE1, 0xFB,
0xF2, 0x66, 0x51, 0xBE, 0xEF, 0x0C, 0x09, 0x59, 0x60, 0x10, 0x34, 0x43, 0x54,
0xA6, 0x46, 0xA2, 0x08, 0x00, 0xA0, 0xC4, 0x01, 0xF6, 0x3D, 0x00, 0x00, 0xAF,
0xAE, 0x05, 0x01, 0x03, 0x01, 0x0C, 0x0B, 0xAE, 0x9E, 0x03, 0x0C, 0x16, 0x08,
0x0C, 0x47, 0x63, 0xEA, 0x0C, 0x74, 0x07, 0x0C, 0x9A, 0xEA, 0xEA, 0x06, 0x0C,
0xC8, 0x02, 0x0C, 0xD1, 0x1D, 0x92, 0xEE, 0x4B, 0x43, 0x09, 0x01, 0x3B, 0xD5,
0x34, 0x4F, 0xAA, 0xF4, 0xCC, 0xA4, 0x56, 0x60, 0xDA, 0x66, 0x54, 0x1D, 0x66,
0xA3, 0x3E, 0x7C, 0x04, 0x0C, 0x9B, 0xD3, 0x4C, 0xB5, 0xD5, 0x52, 0x93, 0xF2,
0x13, 0x24, 0x12, 0x02, 0x31, 0x52, 0x49, 0x92, 0x71, 0x97, 0x54, 0x7B, 0xB9,
0x8C, 0x6A, 0xC3, 0xB3, 0x51, 0xCD, 0xB5, 0x4E, 0xE5, 0x4E, 0x33, 0xF6, 0x1D,
0xAD, 0x0F, 0x34, 0xAA, 0x29, 0xDB, 0x8C, 0x4E, 0xAA, 0xBB, 0x12, 0x9A, 0x91,
0x49, 0x4A, 0xB1, 0xD7, 0x48, 0x2E, 0xF5, 0x10, 0x04, 0x01, 0x49, 0x34, 0x58,
0x92, 0x54, 0x76, 0x97, 0xE9, 0x91, 0xB9, 0x12, 0x4E, 0xDB, 0x03, 0x05, 0x50,
0x6D, 0x2B, 0x36, 0xAA, 0x50, 0xDC, 0xA8, 0x6E, 0x2E, 0x3D, 0x9C, 0x33, 0xA5,
0xBD, 0x25, 0xC9, 0xDD, 0xF8, 0x09, 0x92, 0x1F, 0x06, 0x45, 0x6D, 0xAA, 0x69,
0x66, 0x92, 0x97, 0xB7, 0x54, 0xB7, 0xDB, 0x1F, 0x39, 0xF8, 0x12, 0x07, 0x41,
0x95, 0x2F, 0x1B, 0x49, 0x41, 0x4B, 0x75, 0xDD, 0x99, 0x49, 0x55, 0x70, 0x75,
0xBF, 0x92, 0x24, 0xA7, 0xC4, 0x49, 0x92, 0xD9, 0xF5, 0x6B, 0x82, 0x14, 0x08,
0x38, 0xEA, 0x65, 0x8C, 0x6A, 0x43, 0x9B, 0x51, 0x5D, 0xE5, 0x46, 0x7F, 0xB5,
0xC7, 0xA4, 0x95, 0x91, 0xAE, 0xD0, 0x4C, 0xC6, 0xE2, 0x33, 0xC9, 0xFF, 0x09,
0x92, 0x1F, 0x09, 0x34, 0x47, 0x24, 0xA9, 0x65, 0x7D, 0x9A, 0x46, 0x99, 0x92,
0x72, 0xB6, 0xD4, 0x9A, 0xB9, 0xF4, 0x10, 0x0A, 0x19, 0x54, 0x32, 0x1B, 0xCF,
0x3E, 0x4C, 0xAA, 0x5E, 0x97, 0x31, 0x6D, 0xAA, 0xF4, 0x48, 0x39, 0x87, 0xB0,
0x49, 0x09, 0xCF, 0xE9, 0xFB, 0x99, 0x90, 0x46, 0x2C, 0x92, 0x54, 0x4B, 0x6D,
0xE9, 0x91, 0x8A, 0x24, 0x49, 0xA6, 0xC0, 0xD9, 0x75, 0xC5, 0x91, 0xBD, 0xF0,
0x9C, 0x75, 0x45, 0xA8, 0x19, 0xFA, 0x46, 0x3A, 0x52, 0x75, 0x5A, 0x8C, 0x2A,
0x75, 0x3B, 0xAA, 0x95, 0xBD, 0x27, 0xBF, 0x27, 0x39, 0xE3, 0x04, 0x0D, 0x41,
0xD5, 0x24, 0x31, 0x92, 0x42, 0x5E, 0xA4, 0x6A, 0x85, 0x9A, 0xB4, 0xAA, 0x12,
0x9A, 0xD0, 0xF3, 0x39, 0x41, 0x15, 0x0E, 0x37, 0x92, 0x24, 0x5F, 0x84, 0xA5,
0xD5, 0xDE, 0x33, 0x93, 0xB6, 0xD9, 0xAA, 0x6F, 0xE4, 0x2E, 0xF6, 0x14, 0x0F,
0x61, 0x92, 0x52, 0xA4, 0xCA, 0x6C, 0xCD, 0x4C, 0x86, 0x94, 0x92, 0xEA, 0xA5,
0x7F, 0x39, 0xD9, 0x72, 0xAF, 0x11, 0x10, 0x04, 0xAA, 0x1C, 0xED, 0x47, 0x3D,
0xF6, 0x97, 0x3D, 0xF4, 0x7D, 0x0A, 0x5E, 0xAF, 0x44, 0x80, 0xAA, 0x57, 0x35,
0xAA, 0xA1, 0xF7, 0x34, 0xBA, 0x92, 0xA4, 0xD6, 0xF7, 0x7A, 0xF7, 0x5B, 0x1A,
0x18, 0x11, 0x35, 0xAA, 0xC4, 0x48, 0xAA, 0x4C, 0x6E, 0xD6, 0x91, 0x93, 0x12,
0x52, 0xBA, 0xE0, 0x35, 0x8D, 0xFF, 0x5C, 0x1F, 0x27, 0x12, 0x54, 0xE9, 0x44,
0x51, 0xA5, 0x67, 0x47, 0x92, 0x7F, 0x99, 0x64, 0x37, 0xBA, 0x38, 0x49, 0xE2,
0xA8, 0xCF, 0xF2, 0x75, 0x53, 0x0D, 0x13, 0xFA, 0x24, 0x1E, 0x51, 0xB9, 0xC9,
0x29, 0x40, 0x52, 0x7D, 0x0F
};
0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x05, 0x46, 0x00, 0x00, 0x01, 0xE1,
0xFB, 0xF2, 0x66, 0x51, 0xBE, 0xEF, 0x0C, 0x09, 0x59, 0x60, 0x10, 0x34,
0x43, 0x54, 0xA6, 0x46, 0xA2, 0x08, 0x00, 0xA0, 0xC4, 0x01, 0xF6, 0x3D,
0x00, 0x00, 0xAF, 0xAE, 0x05, 0x01, 0x03, 0x01, 0x0C, 0x0B, 0xAE, 0x9E,
0x03, 0x0C, 0x16, 0x08, 0x0C, 0x47, 0x63, 0xEA, 0x0C, 0x74, 0x07, 0x0C,
0x9A, 0xEA, 0xEA, 0x06, 0x0C, 0xC8, 0x02, 0x0C, 0xD1, 0x1D, 0x92, 0xEE,
0x4B, 0x43, 0x09, 0x01, 0x3B, 0xD5, 0x34, 0x4F, 0xAA, 0xF4, 0xCC, 0xA4,
0x56, 0x60, 0xDA, 0x66, 0x54, 0x1D, 0x66, 0xA3, 0x3E, 0x7C, 0x04, 0x0C,
0x9B, 0xD3, 0x4C, 0xB5, 0xD5, 0x52, 0x93, 0xF2, 0x13, 0x24, 0x12, 0x02,
0x31, 0x52, 0x49, 0x92, 0x71, 0x97, 0x54, 0x7B, 0xB9, 0x8C, 0x6A, 0xC3,
0xB3, 0x51, 0xCD, 0xB5, 0x4E, 0xE5, 0x4E, 0x33, 0xF6, 0x1D, 0xAD, 0x0F,
0x34, 0xAA, 0x29, 0xDB, 0x8C, 0x4E, 0xAA, 0xBB, 0x12, 0x9A, 0x91, 0x49,
0x4A, 0xB1, 0xD7, 0x48, 0x2E, 0xF5, 0x10, 0x04, 0x01, 0x49, 0x34, 0x58,
0x92, 0x54, 0x76, 0x97, 0xE9, 0x91, 0xB9, 0x12, 0x4E, 0xDB, 0x03, 0x05,
0x50, 0x6D, 0x2B, 0x36, 0xAA, 0x50, 0xDC, 0xA8, 0x6E, 0x2E, 0x3D, 0x9C,
0x33, 0xA5, 0xBD, 0x25, 0xC9, 0xDD, 0xF8, 0x09, 0x92, 0x1F, 0x06, 0x45,
0x6D, 0xAA, 0x69, 0x66, 0x92, 0x97, 0xB7, 0x54, 0xB7, 0xDB, 0x1F, 0x39,
0xF8, 0x12, 0x07, 0x41, 0x95, 0x2F, 0x1B, 0x49, 0x41, 0x4B, 0x75, 0xDD,
0x99, 0x49, 0x55, 0x70, 0x75, 0xBF, 0x92, 0x24, 0xA7, 0xC4, 0x49, 0x92,
0xD9, 0xF5, 0x6B, 0x82, 0x14, 0x08, 0x38, 0xEA, 0x65, 0x8C, 0x6A, 0x43,
0x9B, 0x51, 0x5D, 0xE5, 0x46, 0x7F, 0xB5, 0xC7, 0xA4, 0x95, 0x91, 0xAE,
0xD0, 0x4C, 0xC6, 0xE2, 0x33, 0xC9, 0xFF, 0x09, 0x92, 0x1F, 0x09, 0x34,
0x47, 0x24, 0xA9, 0x65, 0x7D, 0x9A, 0x46, 0x99, 0x92, 0x72, 0xB6, 0xD4,
0x9A, 0xB9, 0xF4, 0x10, 0x0A, 0x19, 0x54, 0x32, 0x1B, 0xCF, 0x3E, 0x4C,
0xAA, 0x5E, 0x97, 0x31, 0x6D, 0xAA, 0xF4, 0x48, 0x39, 0x87, 0xB0, 0x49,
0x09, 0xCF, 0xE9, 0xFB, 0x99, 0x90, 0x46, 0x2C, 0x92, 0x54, 0x4B, 0x6D,
0xE9, 0x91, 0x8A, 0x24, 0x49, 0xA6, 0xC0, 0xD9, 0x75, 0xC5, 0x91, 0xBD,
0xF0, 0x9C, 0x75, 0x45, 0xA8, 0x19, 0xFA, 0x46, 0x3A, 0x52, 0x75, 0x5A,
0x8C, 0x2A, 0x75, 0x3B, 0xAA, 0x95, 0xBD, 0x27, 0xBF, 0x27, 0x39, 0xE3,
0x04, 0x0D, 0x41, 0xD5, 0x24, 0x31, 0x92, 0x42, 0x5E, 0xA4, 0x6A, 0x85,
0x9A, 0xB4, 0xAA, 0x12, 0x9A, 0xD0, 0xF3, 0x39, 0x41, 0x15, 0x0E, 0x37,
0x92, 0x24, 0x5F, 0x84, 0xA5, 0xD5, 0xDE, 0x33, 0x93, 0xB6, 0xD9, 0xAA,
0x6F, 0xE4, 0x2E, 0xF6, 0x14, 0x0F, 0x61, 0x92, 0x52, 0xA4, 0xCA, 0x6C,
0xCD, 0x4C, 0x86, 0x94, 0x92, 0xEA, 0xA5, 0x7F, 0x39, 0xD9, 0x72, 0xAF,
0x11, 0x10, 0x04, 0xAA, 0x1C, 0xED, 0x47, 0x3D, 0xF6, 0x97, 0x3D, 0xF4,
0x7D, 0x0A, 0x5E, 0xAF, 0x44, 0x80, 0xAA, 0x57, 0x35, 0xAA, 0xA1, 0xF7,
0x34, 0xBA, 0x92, 0xA4, 0xD6, 0xF7, 0x7A, 0xF7, 0x5B, 0x1A, 0x18, 0x11,
0x35, 0xAA, 0xC4, 0x48, 0xAA, 0x4C, 0x6E, 0xD6, 0x91, 0x93, 0x12, 0x52,
0xBA, 0xE0, 0x35, 0x8D, 0xFF, 0x5C, 0x1F, 0x27, 0x12, 0x54, 0xE9, 0x44,
0x51, 0xA5, 0x67, 0x47, 0x92, 0x7F, 0x99, 0x64, 0x37, 0xBA, 0x38, 0x49,
0xE2, 0xA8, 0xCF, 0xF2, 0x75, 0x53, 0x0D, 0x13, 0xFA, 0x24, 0x1E, 0x51,
0xB9, 0xC9, 0x29, 0x40, 0x52, 0x7D, 0x0F};
/* Data from bootstrap_font.dat inserted by mkbootstrap.lua: */
constexpr std::array<uint8_t, 1534> bootstrap_font_dat{
0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x13, 0x68, 0x00, 0x00, 0x05, 0xEC, 0xD3,
0x6C, 0x7E, 0xAB, 0xBE, 0xEF, 0x94, 0x90, 0x81, 0x61, 0x50, 0x34, 0x44, 0x33,
0x33, 0x53, 0x66, 0x64, 0x64, 0x26, 0x20, 0x60, 0x47, 0x1E, 0x01, 0xFF, 0x84,
0x41, 0x01, 0x02, 0xFF, 0x01, 0x84, 0x09, 0xFF, 0xFF, 0x14, 0x2F, 0x06, 0xCD,
0x9B, 0xCC, 0x8C, 0x89, 0x04, 0x1B, 0x42, 0x06, 0x65, 0x64, 0x71, 0x3B, 0x44,
0x01, 0x06, 0x78, 0xE0, 0xE9, 0xD9, 0x9A, 0x2B, 0x36, 0x72, 0xB0, 0x43, 0x84,
0x59, 0x1B, 0x4D, 0x0A, 0xB6, 0x75, 0x87, 0x91, 0x32, 0xAB, 0x86, 0x02, 0xCC,
0xDE, 0x84, 0x07, 0x82, 0x31, 0x85, 0xCC, 0x45, 0x90, 0x4A, 0x84, 0xE7, 0xC4,
0x9C, 0x42, 0xFC, 0x29, 0x66, 0x0C, 0xA4, 0x94, 0x9D, 0xD9, 0x38, 0x75, 0x35,
0x42, 0x98, 0x07, 0x6D, 0x70, 0x91, 0x1B, 0x03, 0x8E, 0x54, 0x40, 0x9B, 0xED,
0x89, 0x19, 0x44, 0x87, 0x02, 0x9D, 0x8B, 0x5C, 0x3A, 0x15, 0x19, 0xF8, 0xB7,
0xAC, 0x43, 0x01, 0x15, 0x93, 0x0B, 0x5D, 0x03, 0x83, 0x40, 0x1A, 0x56, 0xA5,
0x1D, 0x03, 0xF2, 0x93, 0xA2, 0x50, 0x03, 0xB6, 0x11, 0x1C, 0xF2, 0x8E, 0x8E,
0x60, 0x87, 0x42, 0x89, 0x93, 0x40, 0x93, 0x64, 0xA2, 0x81, 0x04, 0x29, 0x23,
0x11, 0x4F, 0x36, 0xA0, 0xBA, 0x8E, 0xA2, 0xA4, 0x1A, 0x08, 0x75, 0x65, 0x6E,
0x9C, 0xAC, 0x14, 0xC3, 0x18, 0x67, 0x33, 0x16, 0x4E, 0x10, 0x31, 0x8C, 0x11,
0x9B, 0x17, 0x7C, 0xCC, 0x44, 0x57, 0x8F, 0xF7, 0x74, 0x0E, 0x3F, 0x71, 0x80,
0x64, 0x08, 0x39, 0x90, 0xBC, 0x28, 0x87, 0x3A, 0x15, 0x8B, 0x70, 0x30, 0x9D,
0x04, 0x14, 0x0B, 0x89, 0x1C, 0x95, 0x21, 0x8F, 0x50, 0xB5, 0x2D, 0xD9, 0x85,
0x1B, 0x80, 0x72, 0xEC, 0x0A, 0xCE, 0x6B, 0xA8, 0xDB, 0x86, 0x05, 0x35, 0x93,
0x84, 0x12, 0x8B, 0xE6, 0xEC, 0x84, 0xBF, 0x79, 0x5F, 0xDA, 0xA4, 0xC8, 0x97,
0xF8, 0x84, 0x42, 0x9B, 0x19, 0xB4, 0x96, 0xCB, 0xD4, 0x85, 0x21, 0x84, 0x08,
0xB3, 0x5B, 0x1F, 0x88, 0x60, 0xCE, 0x85, 0x0F, 0x56, 0x92, 0x92, 0xA4, 0x05,
0xA6, 0x43, 0x46, 0x9E, 0x94, 0x08, 0x8B, 0x58, 0x17, 0x3B, 0x87, 0xC9, 0xAA,
0x86, 0x48, 0x83, 0x23, 0x12, 0x83, 0x52, 0x90, 0x89, 0x38, 0x4A, 0x50, 0x89,
0x52, 0x32, 0x98, 0x45, 0xB9, 0x84, 0x48, 0x6D, 0x98, 0x17, 0x9E, 0xA2, 0x37,
0x66, 0xC2, 0xA2, 0xB4, 0x5A, 0x2C, 0x54, 0xE5, 0xC5, 0x15, 0x74, 0x44, 0x67,
0x06, 0x50, 0x6E, 0xE1, 0x06, 0x2F, 0x2D, 0xC8, 0x99, 0x0D, 0xB6, 0x4D, 0x79,
0x24, 0x0E, 0x07, 0x1D, 0xE8, 0x91, 0x94, 0x0F, 0xDE, 0x62, 0x3F, 0x60, 0x0F,
0x27, 0x63, 0xE5, 0x40, 0x78, 0x85, 0xB8, 0x15, 0x09, 0xCA, 0x22, 0x2B, 0x19,
0x09, 0x53, 0xF9, 0x84, 0x69, 0x6D, 0x32, 0x6B, 0xAE, 0x45, 0xCA, 0x90, 0xE6,
0x12, 0x6A, 0xB4, 0xA2, 0xD8, 0x4C, 0xFA, 0xA1, 0x5D, 0xEF, 0xC2, 0xE4, 0x02,
0x00, 0xF9, 0x5B, 0x05, 0x13, 0x6B, 0xC2, 0xB9, 0xAA, 0x17, 0xD8, 0xBA, 0xB1,
0xF9, 0xA0, 0x05, 0x4C, 0x2F, 0x9A, 0x61, 0xBA, 0x52, 0x94, 0x63, 0xB9, 0x16,
0x9D, 0xA3, 0x65, 0x84, 0x3D, 0x4A, 0x64, 0x9C, 0x96, 0x20, 0xF6, 0x30, 0x85,
0x68, 0x5A, 0x50, 0x95, 0xE5, 0x30, 0xFD, 0x90, 0x1C, 0xE2, 0xE6, 0x43, 0x0B,
0x6A, 0x9F, 0x23, 0x12, 0x27, 0xC2, 0x81, 0x9D, 0x55, 0x85, 0xC7, 0x01, 0xA5,
0x58, 0x01, 0xC7, 0xD3, 0xF3, 0xFD, 0x87, 0x0B, 0x58, 0x7C, 0x52, 0xCA, 0x6C,
0x47, 0xF1, 0x39, 0x19, 0x8A, 0x9A, 0xF7, 0x21, 0x0A, 0x67, 0x06, 0xBE, 0xD3,
0x88, 0xCF, 0x47, 0x34, 0x94, 0x09, 0x04, 0x40, 0x64, 0x09, 0xE6, 0x4F, 0xEA,
0xA5, 0x55, 0x4E, 0xA5, 0x95, 0xE5, 0x50, 0x0D, 0x06, 0x46, 0x61, 0x85, 0x23,
0x08, 0xAB, 0xF9, 0x48, 0x09, 0x33, 0x44, 0x50, 0x07, 0x21, 0x3C, 0xA8, 0x61,
0x9D, 0x34, 0x84, 0x22, 0x5C, 0x44, 0xFD, 0xA0, 0x6D, 0xE2, 0x6E, 0x56, 0x3A,
0xA3, 0x19, 0x62, 0x4A, 0x82, 0x0C, 0x98, 0x25, 0xCF, 0x24, 0xC8, 0x35, 0x35,
0x1A, 0x12, 0x59, 0x5D, 0x98, 0xD6, 0x2E, 0x76, 0x7F, 0x2B, 0xF4, 0x30, 0x24,
0xAF, 0x4C, 0x5C, 0x28, 0x2E, 0x28, 0xAA, 0x24, 0xE5, 0x17, 0xFF, 0x55, 0x42,
0xC9, 0x54, 0x1B, 0x75, 0xDD, 0xBE, 0x47, 0x9B, 0x11, 0x22, 0x0E, 0xCC, 0xAA,
0x88, 0x88, 0x66, 0x64, 0xCA, 0xD0, 0x88, 0x08, 0x41, 0x06, 0xF0, 0x17, 0x45,
0x82, 0x07, 0xAE, 0x80, 0x9F, 0xB2, 0x23, 0x23, 0xAB, 0x8C, 0xE9, 0xFA, 0xC3,
0x53, 0xD0, 0x06, 0x88, 0x67, 0x59, 0xB3, 0x92, 0xD2, 0xE9, 0xA8, 0x82, 0x0A,
0xA7, 0xC9, 0x44, 0x8E, 0x47, 0x15, 0x82, 0x37, 0x80, 0x9B, 0x88, 0xF9, 0x08,
0x27, 0xDC, 0x05, 0xC2, 0xD3, 0x94, 0x59, 0x55, 0x41, 0x7F, 0x91, 0xFF, 0xDB,
0x16, 0x8C, 0x0C, 0x27, 0x76, 0x6E, 0x26, 0x81, 0xAA, 0xA1, 0x8F, 0xC1, 0x20,
0x63, 0x0B, 0xC3, 0x89, 0x49, 0x31, 0x42, 0x93, 0x8C, 0x69, 0x07, 0x7B, 0x3F,
0x9E, 0x0E, 0x45, 0x56, 0x85, 0x91, 0xE9, 0x78, 0xCC, 0xF9, 0x08, 0xA4, 0xD5,
0x92, 0x70, 0x89, 0x16, 0xC3, 0x0C, 0x92, 0x18, 0xA7, 0x59, 0xF2, 0x08, 0xCD,
0xE0, 0xF2, 0xA8, 0x97, 0x4C, 0xF3, 0x83, 0xA7, 0x1C, 0x68, 0x54, 0x17, 0x03,
0x8A, 0x20, 0x57, 0x50, 0x58, 0x31, 0x11, 0x72, 0x87, 0x71, 0x25, 0x2E, 0xE7,
0xE4, 0x79, 0x90, 0x10, 0x50, 0x1D, 0x54, 0x88, 0xE1, 0xB7, 0x8F, 0x18, 0x02,
0x77, 0xA8, 0x0C, 0x64, 0x11, 0x8C, 0xC9, 0x21, 0xE6, 0x07, 0xCB, 0x5E, 0x8F,
0xB2, 0x25, 0x0B, 0x7B, 0x0A, 0x25, 0x8B, 0x95, 0xD0, 0x82, 0xF4, 0xE2, 0x34,
0x20, 0xEA, 0x5F, 0x36, 0x8C, 0xA1, 0x94, 0x50, 0xFD, 0x69, 0x1B, 0xCB, 0xB0,
0x8B, 0x4F, 0xBF, 0xB5, 0xC7, 0x0B, 0xC2, 0xC5, 0x17, 0xEE, 0x8C, 0x91, 0xFB,
0xD3, 0x0D, 0xD1, 0xE1, 0x98, 0x3A, 0xC9, 0x4D, 0x08, 0xF4, 0xB8, 0x59, 0x11,
0x78, 0x48, 0x20, 0x8B, 0x25, 0x08, 0xBF, 0xF2, 0x89, 0x59, 0xDB, 0x31, 0xD6,
0x17, 0x9E, 0xCA, 0x74, 0x20, 0x8E, 0x0E, 0xD5, 0x07, 0x3B, 0x5D, 0x51, 0x8E,
0x86, 0x71, 0xCE, 0xE6, 0x2C, 0x54, 0xB2, 0xC6, 0x8B, 0x02, 0x7D, 0x7F, 0xC2,
0x61, 0xC2, 0x0B, 0xF0, 0x85, 0x84, 0xCC, 0x98, 0x11, 0x4A, 0x8D, 0x66, 0x03,
0xF8, 0x54, 0x57, 0xB0, 0xF0, 0x45, 0x8C, 0xFF, 0xD3, 0x61, 0xA8, 0x82, 0x09,
0xFF, 0x00, 0xCA, 0x0B, 0x8C, 0x9B, 0x75, 0x24, 0x09, 0x07, 0x00, 0xF9, 0xAC,
0xC1, 0xBB, 0xB7, 0x9E, 0xE8, 0x41, 0xE4, 0x2B, 0xCE, 0xAB, 0x2D, 0x9D, 0xEA,
0xFD, 0x41, 0x00, 0x42, 0x8F, 0xC9, 0xF4, 0x87, 0x54, 0x61, 0x2D, 0x42, 0x51,
0x3F, 0x52, 0x29, 0xCB, 0x87, 0x0F, 0x1F, 0xE4, 0x11, 0x33, 0x8E, 0xE5, 0xCD,
0x86, 0x6F, 0x96, 0x30, 0x40, 0x06, 0xF5, 0x7F, 0x42, 0xB2, 0x61, 0x93, 0x55,
0x87, 0xFE, 0x86, 0xE3, 0x67, 0x49, 0xA2, 0xC3, 0x1F, 0x6F, 0xEF, 0x76, 0x4E,
0xE5, 0x12, 0x89, 0x3E, 0x10, 0xFF, 0x90, 0x99, 0xBF, 0x40, 0x45, 0xAA, 0xFC,
0x10, 0xDC, 0xC1, 0xF1, 0x44, 0x13, 0x50, 0x58, 0x29, 0x61, 0x28, 0x95, 0x70,
0x05, 0x7E, 0x21, 0x8D, 0xE3, 0x83, 0xB2, 0x8F, 0xB2, 0xA2, 0x10, 0xE0, 0x93,
0xAC, 0xFD, 0x88, 0x38, 0x38, 0xC4, 0x46, 0x23, 0x4A, 0x41, 0xF8, 0x0F, 0xA8,
0x12, 0xD5, 0x88, 0x7F, 0x92, 0xA2, 0x21, 0xBE, 0xF1, 0x0A, 0x11, 0x92, 0x11,
0x99, 0xAB, 0xEA, 0xC3, 0x85, 0x22, 0x1B, 0xA2, 0xDF, 0xE9, 0x7E, 0x18, 0x95,
0xB6, 0x48, 0xD1, 0x9F, 0x50, 0xCF, 0x11, 0xBE, 0xF9, 0xB9, 0x1E, 0xC7, 0x9B,
0x00, 0xE3, 0x62, 0xAA, 0x98, 0x0E, 0x01, 0x87, 0xC0, 0x27, 0x59, 0x53, 0x83,
0x47, 0xBA, 0x96, 0xEA, 0xFF, 0x88, 0x68, 0xEA, 0x08, 0xD3, 0x58, 0xCE, 0x0F,
0x05, 0x8A, 0xDA, 0x27, 0x6E, 0x15, 0x18, 0xF2, 0xAF, 0x38, 0xEA, 0x54, 0xA0,
0x89, 0x74, 0xA1, 0x4B, 0x16, 0x9A, 0x14, 0x4D, 0x06, 0x85, 0x1D, 0xEC, 0xEF,
0x52, 0x54, 0x93, 0x2C, 0x09, 0xA3, 0xE9, 0xC6, 0x1C, 0x75, 0xAD, 0xD8, 0x14,
0x2E, 0x31, 0x58, 0x15, 0xCF, 0xB8, 0x44, 0x04, 0xAC, 0x1C, 0xF0, 0x22, 0xA9,
0x3B, 0x99, 0xD9, 0x44, 0x9D, 0x8E, 0xF8, 0x05, 0xE1, 0x04, 0x7B, 0x0B, 0x32,
0x13, 0x85, 0x22, 0xDE, 0x87, 0xAC, 0x27, 0xAB, 0x2A, 0x66, 0x75, 0xA1, 0x9B,
0xC0, 0x51, 0xE1, 0x59, 0x43, 0x5B, 0xC2, 0x37, 0xDF, 0x00, 0xD5, 0x98, 0x53,
0xE3, 0x95, 0xD0, 0xD2, 0x88, 0xF6, 0x8F, 0xFD, 0x28, 0x5D, 0xFE, 0x50, 0x34,
0xF4, 0x85, 0xEA, 0xA1, 0xC9, 0x0F, 0xA6, 0x72, 0xA8, 0x57, 0xF8, 0xEA, 0x50,
0x96, 0xC8, 0x84, 0x1E, 0xF8, 0x1F, 0x2C, 0xEB, 0xA9, 0xA3, 0x64, 0xE1, 0xAC,
0xE4, 0x2B, 0x50, 0xA4, 0x66, 0x54, 0x87, 0x63, 0xA2, 0x87, 0x00, 0x04, 0x29,
0x2F, 0x1E, 0x89, 0x51, 0xC1, 0xC0, 0xD0, 0xA4, 0xC7, 0x14, 0x52, 0xBA, 0x58,
0xF1, 0xC4, 0x41, 0x40, 0x57, 0xD5, 0xF2, 0xA6, 0x80, 0xEC, 0xB0, 0x30, 0xB1,
0x71, 0xDB, 0x45, 0xA4, 0x86, 0xAC, 0xA7, 0x98, 0xD4, 0xB3, 0x26, 0x42, 0xF1,
0x24, 0x31, 0x0C, 0x54, 0x4F, 0x68, 0x03, 0xB3, 0x0E, 0xD8, 0xB7, 0xE5, 0x8D,
0x1C, 0x8B, 0xD5, 0x08, 0x2D, 0x9E, 0xD0, 0x9C, 0x06, 0x62, 0xA1, 0xD5, 0x41,
0x3B, 0xA0, 0x5C, 0x7E, 0x92, 0x75, 0x84, 0x57, 0x38, 0x41, 0xA0, 0x25, 0xB3,
0xA6, 0xA3, 0x89, 0x33, 0xC2, 0xD1, 0x60, 0x72, 0x57, 0xB1, 0xC2, 0xC0, 0x2A,
0x79, 0xB0, 0xC2, 0x6C, 0x13, 0x01, 0x51, 0x21, 0xCB, 0x13, 0xA3, 0x32, 0x3E,
0x16, 0x49, 0xEF, 0x6C, 0xF1, 0x30, 0x90, 0x05, 0x5D, 0x85, 0x27, 0x1B, 0xAA,
0xC0, 0x74, 0x7A, 0x5C, 0x37, 0x01, 0x27, 0x05, 0xEA, 0x3C, 0x4A, 0x4B, 0x9F,
0x0D, 0xC8, 0x18, 0xA2, 0xD4, 0x20, 0x59, 0xCB, 0x19, 0x7D, 0x9C, 0x5F, 0x6C,
0x04, 0xCA, 0x28, 0x6E, 0x6B, 0xAC, 0x7B, 0x0C, 0xCE, 0xE5, 0x9E, 0x49, 0x84,
0x18, 0xDD, 0x1D, 0xAA, 0x39, 0x29, 0x9F, 0x30, 0xFA, 0x22, 0x67, 0x7C, 0x93,
0x92, 0x09, 0x13, 0x52, 0x2F, 0x1E, 0x4E, 0x6E, 0x61, 0x05, 0x18, 0x85, 0x07,
0xA9, 0x33, 0x1E, 0x68, 0xBD, 0x95, 0x31, 0x20, 0x8B, 0x2A, 0xA6, 0x70, 0x96,
0xC4, 0x5E, 0x3D, 0x95, 0x50, 0x79, 0x67, 0x46, 0xCA, 0x50, 0x20, 0xDF, 0x10,
0x2F, 0x08, 0xA0, 0x03, 0xBD, 0x2D, 0x50, 0xEE, 0x55, 0x2C, 0xEC, 0xC9, 0x5F,
0xB9, 0x11, 0x44, 0xEF, 0x4A, 0x21, 0x74, 0x74, 0x75, 0xF3, 0x86, 0xA2, 0x8A,
0x88, 0xA3, 0x77, 0x21, 0xC6, 0xC3, 0x21, 0x27, 0x8A, 0x42, 0x2C, 0x16, 0x3A,
0x88, 0x8A, 0x7F, 0x73, 0xEA, 0xD8, 0x79, 0x46, 0x1C, 0x67, 0x9B, 0x79, 0x61,
0x95, 0xF3, 0x44, 0x63, 0x65, 0x12, 0x8C, 0xA5, 0xBB, 0x88, 0x12, 0x67, 0x9F,
0x90, 0x5D, 0x95, 0x66, 0xA1, 0x9C, 0x57, 0x2A, 0x09, 0x34, 0x07, 0x7B, 0xD6,
0x02, 0xAC, 0x9A, 0x43, 0x10, 0xB5, 0x0A, 0xA0, 0x17, 0x1C, 0xA6, 0x00, 0x9B
};
0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x13, 0x68, 0x00, 0x00, 0x05, 0xEC,
0xD3, 0x6C, 0x7E, 0xAB, 0xBE, 0xEF, 0x94, 0x90, 0x81, 0x61, 0x50, 0x34,
0x44, 0x33, 0x33, 0x53, 0x66, 0x64, 0x64, 0x26, 0x20, 0x60, 0x47, 0x1E,
0x01, 0xFF, 0x84, 0x41, 0x01, 0x02, 0xFF, 0x01, 0x84, 0x09, 0xFF, 0xFF,
0x14, 0x2F, 0x06, 0xCD, 0x9B, 0xCC, 0x8C, 0x89, 0x04, 0x1B, 0x42, 0x06,
0x65, 0x64, 0x71, 0x3B, 0x44, 0x01, 0x06, 0x78, 0xE0, 0xE9, 0xD9, 0x9A,
0x2B, 0x36, 0x72, 0xB0, 0x43, 0x84, 0x59, 0x1B, 0x4D, 0x0A, 0xB6, 0x75,
0x87, 0x91, 0x32, 0xAB, 0x86, 0x02, 0xCC, 0xDE, 0x84, 0x07, 0x82, 0x31,
0x85, 0xCC, 0x45, 0x90, 0x4A, 0x84, 0xE7, 0xC4, 0x9C, 0x42, 0xFC, 0x29,
0x66, 0x0C, 0xA4, 0x94, 0x9D, 0xD9, 0x38, 0x75, 0x35, 0x42, 0x98, 0x07,
0x6D, 0x70, 0x91, 0x1B, 0x03, 0x8E, 0x54, 0x40, 0x9B, 0xED, 0x89, 0x19,
0x44, 0x87, 0x02, 0x9D, 0x8B, 0x5C, 0x3A, 0x15, 0x19, 0xF8, 0xB7, 0xAC,
0x43, 0x01, 0x15, 0x93, 0x0B, 0x5D, 0x03, 0x83, 0x40, 0x1A, 0x56, 0xA5,
0x1D, 0x03, 0xF2, 0x93, 0xA2, 0x50, 0x03, 0xB6, 0x11, 0x1C, 0xF2, 0x8E,
0x8E, 0x60, 0x87, 0x42, 0x89, 0x93, 0x40, 0x93, 0x64, 0xA2, 0x81, 0x04,
0x29, 0x23, 0x11, 0x4F, 0x36, 0xA0, 0xBA, 0x8E, 0xA2, 0xA4, 0x1A, 0x08,
0x75, 0x65, 0x6E, 0x9C, 0xAC, 0x14, 0xC3, 0x18, 0x67, 0x33, 0x16, 0x4E,
0x10, 0x31, 0x8C, 0x11, 0x9B, 0x17, 0x7C, 0xCC, 0x44, 0x57, 0x8F, 0xF7,
0x74, 0x0E, 0x3F, 0x71, 0x80, 0x64, 0x08, 0x39, 0x90, 0xBC, 0x28, 0x87,
0x3A, 0x15, 0x8B, 0x70, 0x30, 0x9D, 0x04, 0x14, 0x0B, 0x89, 0x1C, 0x95,
0x21, 0x8F, 0x50, 0xB5, 0x2D, 0xD9, 0x85, 0x1B, 0x80, 0x72, 0xEC, 0x0A,
0xCE, 0x6B, 0xA8, 0xDB, 0x86, 0x05, 0x35, 0x93, 0x84, 0x12, 0x8B, 0xE6,
0xEC, 0x84, 0xBF, 0x79, 0x5F, 0xDA, 0xA4, 0xC8, 0x97, 0xF8, 0x84, 0x42,
0x9B, 0x19, 0xB4, 0x96, 0xCB, 0xD4, 0x85, 0x21, 0x84, 0x08, 0xB3, 0x5B,
0x1F, 0x88, 0x60, 0xCE, 0x85, 0x0F, 0x56, 0x92, 0x92, 0xA4, 0x05, 0xA6,
0x43, 0x46, 0x9E, 0x94, 0x08, 0x8B, 0x58, 0x17, 0x3B, 0x87, 0xC9, 0xAA,
0x86, 0x48, 0x83, 0x23, 0x12, 0x83, 0x52, 0x90, 0x89, 0x38, 0x4A, 0x50,
0x89, 0x52, 0x32, 0x98, 0x45, 0xB9, 0x84, 0x48, 0x6D, 0x98, 0x17, 0x9E,
0xA2, 0x37, 0x66, 0xC2, 0xA2, 0xB4, 0x5A, 0x2C, 0x54, 0xE5, 0xC5, 0x15,
0x74, 0x44, 0x67, 0x06, 0x50, 0x6E, 0xE1, 0x06, 0x2F, 0x2D, 0xC8, 0x99,
0x0D, 0xB6, 0x4D, 0x79, 0x24, 0x0E, 0x07, 0x1D, 0xE8, 0x91, 0x94, 0x0F,
0xDE, 0x62, 0x3F, 0x60, 0x0F, 0x27, 0x63, 0xE5, 0x40, 0x78, 0x85, 0xB8,
0x15, 0x09, 0xCA, 0x22, 0x2B, 0x19, 0x09, 0x53, 0xF9, 0x84, 0x69, 0x6D,
0x32, 0x6B, 0xAE, 0x45, 0xCA, 0x90, 0xE6, 0x12, 0x6A, 0xB4, 0xA2, 0xD8,
0x4C, 0xFA, 0xA1, 0x5D, 0xEF, 0xC2, 0xE4, 0x02, 0x00, 0xF9, 0x5B, 0x05,
0x13, 0x6B, 0xC2, 0xB9, 0xAA, 0x17, 0xD8, 0xBA, 0xB1, 0xF9, 0xA0, 0x05,
0x4C, 0x2F, 0x9A, 0x61, 0xBA, 0x52, 0x94, 0x63, 0xB9, 0x16, 0x9D, 0xA3,
0x65, 0x84, 0x3D, 0x4A, 0x64, 0x9C, 0x96, 0x20, 0xF6, 0x30, 0x85, 0x68,
0x5A, 0x50, 0x95, 0xE5, 0x30, 0xFD, 0x90, 0x1C, 0xE2, 0xE6, 0x43, 0x0B,
0x6A, 0x9F, 0x23, 0x12, 0x27, 0xC2, 0x81, 0x9D, 0x55, 0x85, 0xC7, 0x01,
0xA5, 0x58, 0x01, 0xC7, 0xD3, 0xF3, 0xFD, 0x87, 0x0B, 0x58, 0x7C, 0x52,
0xCA, 0x6C, 0x47, 0xF1, 0x39, 0x19, 0x8A, 0x9A, 0xF7, 0x21, 0x0A, 0x67,
0x06, 0xBE, 0xD3, 0x88, 0xCF, 0x47, 0x34, 0x94, 0x09, 0x04, 0x40, 0x64,
0x09, 0xE6, 0x4F, 0xEA, 0xA5, 0x55, 0x4E, 0xA5, 0x95, 0xE5, 0x50, 0x0D,
0x06, 0x46, 0x61, 0x85, 0x23, 0x08, 0xAB, 0xF9, 0x48, 0x09, 0x33, 0x44,
0x50, 0x07, 0x21, 0x3C, 0xA8, 0x61, 0x9D, 0x34, 0x84, 0x22, 0x5C, 0x44,
0xFD, 0xA0, 0x6D, 0xE2, 0x6E, 0x56, 0x3A, 0xA3, 0x19, 0x62, 0x4A, 0x82,
0x0C, 0x98, 0x25, 0xCF, 0x24, 0xC8, 0x35, 0x35, 0x1A, 0x12, 0x59, 0x5D,
0x98, 0xD6, 0x2E, 0x76, 0x7F, 0x2B, 0xF4, 0x30, 0x24, 0xAF, 0x4C, 0x5C,
0x28, 0x2E, 0x28, 0xAA, 0x24, 0xE5, 0x17, 0xFF, 0x55, 0x42, 0xC9, 0x54,
0x1B, 0x75, 0xDD, 0xBE, 0x47, 0x9B, 0x11, 0x22, 0x0E, 0xCC, 0xAA, 0x88,
0x88, 0x66, 0x64, 0xCA, 0xD0, 0x88, 0x08, 0x41, 0x06, 0xF0, 0x17, 0x45,
0x82, 0x07, 0xAE, 0x80, 0x9F, 0xB2, 0x23, 0x23, 0xAB, 0x8C, 0xE9, 0xFA,
0xC3, 0x53, 0xD0, 0x06, 0x88, 0x67, 0x59, 0xB3, 0x92, 0xD2, 0xE9, 0xA8,
0x82, 0x0A, 0xA7, 0xC9, 0x44, 0x8E, 0x47, 0x15, 0x82, 0x37, 0x80, 0x9B,
0x88, 0xF9, 0x08, 0x27, 0xDC, 0x05, 0xC2, 0xD3, 0x94, 0x59, 0x55, 0x41,
0x7F, 0x91, 0xFF, 0xDB, 0x16, 0x8C, 0x0C, 0x27, 0x76, 0x6E, 0x26, 0x81,
0xAA, 0xA1, 0x8F, 0xC1, 0x20, 0x63, 0x0B, 0xC3, 0x89, 0x49, 0x31, 0x42,
0x93, 0x8C, 0x69, 0x07, 0x7B, 0x3F, 0x9E, 0x0E, 0x45, 0x56, 0x85, 0x91,
0xE9, 0x78, 0xCC, 0xF9, 0x08, 0xA4, 0xD5, 0x92, 0x70, 0x89, 0x16, 0xC3,
0x0C, 0x92, 0x18, 0xA7, 0x59, 0xF2, 0x08, 0xCD, 0xE0, 0xF2, 0xA8, 0x97,
0x4C, 0xF3, 0x83, 0xA7, 0x1C, 0x68, 0x54, 0x17, 0x03, 0x8A, 0x20, 0x57,
0x50, 0x58, 0x31, 0x11, 0x72, 0x87, 0x71, 0x25, 0x2E, 0xE7, 0xE4, 0x79,
0x90, 0x10, 0x50, 0x1D, 0x54, 0x88, 0xE1, 0xB7, 0x8F, 0x18, 0x02, 0x77,
0xA8, 0x0C, 0x64, 0x11, 0x8C, 0xC9, 0x21, 0xE6, 0x07, 0xCB, 0x5E, 0x8F,
0xB2, 0x25, 0x0B, 0x7B, 0x0A, 0x25, 0x8B, 0x95, 0xD0, 0x82, 0xF4, 0xE2,
0x34, 0x20, 0xEA, 0x5F, 0x36, 0x8C, 0xA1, 0x94, 0x50, 0xFD, 0x69, 0x1B,
0xCB, 0xB0, 0x8B, 0x4F, 0xBF, 0xB5, 0xC7, 0x0B, 0xC2, 0xC5, 0x17, 0xEE,
0x8C, 0x91, 0xFB, 0xD3, 0x0D, 0xD1, 0xE1, 0x98, 0x3A, 0xC9, 0x4D, 0x08,
0xF4, 0xB8, 0x59, 0x11, 0x78, 0x48, 0x20, 0x8B, 0x25, 0x08, 0xBF, 0xF2,
0x89, 0x59, 0xDB, 0x31, 0xD6, 0x17, 0x9E, 0xCA, 0x74, 0x20, 0x8E, 0x0E,
0xD5, 0x07, 0x3B, 0x5D, 0x51, 0x8E, 0x86, 0x71, 0xCE, 0xE6, 0x2C, 0x54,
0xB2, 0xC6, 0x8B, 0x02, 0x7D, 0x7F, 0xC2, 0x61, 0xC2, 0x0B, 0xF0, 0x85,
0x84, 0xCC, 0x98, 0x11, 0x4A, 0x8D, 0x66, 0x03, 0xF8, 0x54, 0x57, 0xB0,
0xF0, 0x45, 0x8C, 0xFF, 0xD3, 0x61, 0xA8, 0x82, 0x09, 0xFF, 0x00, 0xCA,
0x0B, 0x8C, 0x9B, 0x75, 0x24, 0x09, 0x07, 0x00, 0xF9, 0xAC, 0xC1, 0xBB,
0xB7, 0x9E, 0xE8, 0x41, 0xE4, 0x2B, 0xCE, 0xAB, 0x2D, 0x9D, 0xEA, 0xFD,
0x41, 0x00, 0x42, 0x8F, 0xC9, 0xF4, 0x87, 0x54, 0x61, 0x2D, 0x42, 0x51,
0x3F, 0x52, 0x29, 0xCB, 0x87, 0x0F, 0x1F, 0xE4, 0x11, 0x33, 0x8E, 0xE5,
0xCD, 0x86, 0x6F, 0x96, 0x30, 0x40, 0x06, 0xF5, 0x7F, 0x42, 0xB2, 0x61,
0x93, 0x55, 0x87, 0xFE, 0x86, 0xE3, 0x67, 0x49, 0xA2, 0xC3, 0x1F, 0x6F,
0xEF, 0x76, 0x4E, 0xE5, 0x12, 0x89, 0x3E, 0x10, 0xFF, 0x90, 0x99, 0xBF,
0x40, 0x45, 0xAA, 0xFC, 0x10, 0xDC, 0xC1, 0xF1, 0x44, 0x13, 0x50, 0x58,
0x29, 0x61, 0x28, 0x95, 0x70, 0x05, 0x7E, 0x21, 0x8D, 0xE3, 0x83, 0xB2,
0x8F, 0xB2, 0xA2, 0x10, 0xE0, 0x93, 0xAC, 0xFD, 0x88, 0x38, 0x38, 0xC4,
0x46, 0x23, 0x4A, 0x41, 0xF8, 0x0F, 0xA8, 0x12, 0xD5, 0x88, 0x7F, 0x92,
0xA2, 0x21, 0xBE, 0xF1, 0x0A, 0x11, 0x92, 0x11, 0x99, 0xAB, 0xEA, 0xC3,
0x85, 0x22, 0x1B, 0xA2, 0xDF, 0xE9, 0x7E, 0x18, 0x95, 0xB6, 0x48, 0xD1,
0x9F, 0x50, 0xCF, 0x11, 0xBE, 0xF9, 0xB9, 0x1E, 0xC7, 0x9B, 0x00, 0xE3,
0x62, 0xAA, 0x98, 0x0E, 0x01, 0x87, 0xC0, 0x27, 0x59, 0x53, 0x83, 0x47,
0xBA, 0x96, 0xEA, 0xFF, 0x88, 0x68, 0xEA, 0x08, 0xD3, 0x58, 0xCE, 0x0F,
0x05, 0x8A, 0xDA, 0x27, 0x6E, 0x15, 0x18, 0xF2, 0xAF, 0x38, 0xEA, 0x54,
0xA0, 0x89, 0x74, 0xA1, 0x4B, 0x16, 0x9A, 0x14, 0x4D, 0x06, 0x85, 0x1D,
0xEC, 0xEF, 0x52, 0x54, 0x93, 0x2C, 0x09, 0xA3, 0xE9, 0xC6, 0x1C, 0x75,
0xAD, 0xD8, 0x14, 0x2E, 0x31, 0x58, 0x15, 0xCF, 0xB8, 0x44, 0x04, 0xAC,
0x1C, 0xF0, 0x22, 0xA9, 0x3B, 0x99, 0xD9, 0x44, 0x9D, 0x8E, 0xF8, 0x05,
0xE1, 0x04, 0x7B, 0x0B, 0x32, 0x13, 0x85, 0x22, 0xDE, 0x87, 0xAC, 0x27,
0xAB, 0x2A, 0x66, 0x75, 0xA1, 0x9B, 0xC0, 0x51, 0xE1, 0x59, 0x43, 0x5B,
0xC2, 0x37, 0xDF, 0x00, 0xD5, 0x98, 0x53, 0xE3, 0x95, 0xD0, 0xD2, 0x88,
0xF6, 0x8F, 0xFD, 0x28, 0x5D, 0xFE, 0x50, 0x34, 0xF4, 0x85, 0xEA, 0xA1,
0xC9, 0x0F, 0xA6, 0x72, 0xA8, 0x57, 0xF8, 0xEA, 0x50, 0x96, 0xC8, 0x84,
0x1E, 0xF8, 0x1F, 0x2C, 0xEB, 0xA9, 0xA3, 0x64, 0xE1, 0xAC, 0xE4, 0x2B,
0x50, 0xA4, 0x66, 0x54, 0x87, 0x63, 0xA2, 0x87, 0x00, 0x04, 0x29, 0x2F,
0x1E, 0x89, 0x51, 0xC1, 0xC0, 0xD0, 0xA4, 0xC7, 0x14, 0x52, 0xBA, 0x58,
0xF1, 0xC4, 0x41, 0x40, 0x57, 0xD5, 0xF2, 0xA6, 0x80, 0xEC, 0xB0, 0x30,
0xB1, 0x71, 0xDB, 0x45, 0xA4, 0x86, 0xAC, 0xA7, 0x98, 0xD4, 0xB3, 0x26,
0x42, 0xF1, 0x24, 0x31, 0x0C, 0x54, 0x4F, 0x68, 0x03, 0xB3, 0x0E, 0xD8,
0xB7, 0xE5, 0x8D, 0x1C, 0x8B, 0xD5, 0x08, 0x2D, 0x9E, 0xD0, 0x9C, 0x06,
0x62, 0xA1, 0xD5, 0x41, 0x3B, 0xA0, 0x5C, 0x7E, 0x92, 0x75, 0x84, 0x57,
0x38, 0x41, 0xA0, 0x25, 0xB3, 0xA6, 0xA3, 0x89, 0x33, 0xC2, 0xD1, 0x60,
0x72, 0x57, 0xB1, 0xC2, 0xC0, 0x2A, 0x79, 0xB0, 0xC2, 0x6C, 0x13, 0x01,
0x51, 0x21, 0xCB, 0x13, 0xA3, 0x32, 0x3E, 0x16, 0x49, 0xEF, 0x6C, 0xF1,
0x30, 0x90, 0x05, 0x5D, 0x85, 0x27, 0x1B, 0xAA, 0xC0, 0x74, 0x7A, 0x5C,
0x37, 0x01, 0x27, 0x05, 0xEA, 0x3C, 0x4A, 0x4B, 0x9F, 0x0D, 0xC8, 0x18,
0xA2, 0xD4, 0x20, 0x59, 0xCB, 0x19, 0x7D, 0x9C, 0x5F, 0x6C, 0x04, 0xCA,
0x28, 0x6E, 0x6B, 0xAC, 0x7B, 0x0C, 0xCE, 0xE5, 0x9E, 0x49, 0x84, 0x18,
0xDD, 0x1D, 0xAA, 0x39, 0x29, 0x9F, 0x30, 0xFA, 0x22, 0x67, 0x7C, 0x93,
0x92, 0x09, 0x13, 0x52, 0x2F, 0x1E, 0x4E, 0x6E, 0x61, 0x05, 0x18, 0x85,
0x07, 0xA9, 0x33, 0x1E, 0x68, 0xBD, 0x95, 0x31, 0x20, 0x8B, 0x2A, 0xA6,
0x70, 0x96, 0xC4, 0x5E, 0x3D, 0x95, 0x50, 0x79, 0x67, 0x46, 0xCA, 0x50,
0x20, 0xDF, 0x10, 0x2F, 0x08, 0xA0, 0x03, 0xBD, 0x2D, 0x50, 0xEE, 0x55,
0x2C, 0xEC, 0xC9, 0x5F, 0xB9, 0x11, 0x44, 0xEF, 0x4A, 0x21, 0x74, 0x74,
0x75, 0xF3, 0x86, 0xA2, 0x8A, 0x88, 0xA3, 0x77, 0x21, 0xC6, 0xC3, 0x21,
0x27, 0x8A, 0x42, 0x2C, 0x16, 0x3A, 0x88, 0x8A, 0x7F, 0x73, 0xEA, 0xD8,
0x79, 0x46, 0x1C, 0x67, 0x9B, 0x79, 0x61, 0x95, 0xF3, 0x44, 0x63, 0x65,
0x12, 0x8C, 0xA5, 0xBB, 0x88, 0x12, 0x67, 0x9F, 0x90, 0x5D, 0x95, 0x66,
0xA1, 0x9C, 0x57, 0x2A, 0x09, 0x34, 0x07, 0x7B, 0xD6, 0x02, 0xAC, 0x9A,
0x43, 0x10, 0xB5, 0x0A, 0xA0, 0x17, 0x1C, 0xA6, 0x00, 0x9B};
/* Data from bootstrap_font.pal inserted by mkbootstrap.lua: */
constexpr std::array<uint8_t, 47> bootstrap_font_pal{
0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB7,
0xFF, 0x76, 0x79, 0xBE, 0xEF, 0x90, 0x10, 0x90, 0x05, 0x01, 0x02, 0x00, 0x00,
0x20, 0x2B, 0x04, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0xB6, 0x00, 0x00, 0x00,
0x3F, 0x3F, 0x3F, 0x62, 0x79, 0xBE, 0x27, 0x3F
};
0x52, 0x4E, 0x43, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x1D,
0xB7, 0xFF, 0x76, 0x79, 0xBE, 0xEF, 0x90, 0x10, 0x90, 0x05, 0x01, 0x02,
0x00, 0x00, 0x20, 0x2B, 0x04, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0xB6,
0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x62, 0x79, 0xBE, 0x27, 0x3F};
/* End autogenerated content */
// Lua reader function for loading bootstrap_code
const char* read_bootstrap_line(lua_State *L, void *data, size_t *size)
{
const char* read_bootstrap_line(lua_State* L, void* data, size_t* size) {
int& iLine = *reinterpret_cast<int*>(data);
++iLine;
if(iLine < 0 || (iLine & 1))
{
if (iLine < 0 || (iLine & 1)) {
*size = 1;
return "\n";
}
else
{
} else {
const char* s = bootstrap_code[iLine / 2];
if(s == nullptr)
{
if (s == nullptr) {
*size = 0;
return nullptr;
}
else
{
} else {
*size = std::strlen(s);
return s;
}
@@ -292,31 +297,26 @@ const char* read_bootstrap_line(lua_State *L, void *data, size_t *size)
}
template <typename Array>
inline void push(lua_State *L, Array data)
{
inline void push(lua_State* L, Array data) {
lua_pushlstring(L, reinterpret_cast<const char*>(data.data()), data.size());
}
} // namespace
int bootstrap_lua_resources(lua_State *L)
{
int bootstrap_lua_resources(lua_State* L) {
push(L, bootstrap_font_dat);
push(L, bootstrap_font_tab);
push(L, bootstrap_font_pal);
return 3;
}
int bootstrap_lua_error_report(lua_State *L)
{
int bootstrap_lua_error_report(lua_State* L) {
int iLine = -first_bootstrap_code_line_number;
if(luaT_load(L, read_bootstrap_line, &iLine, "@bootstrap.cpp", "t") == 0)
{
if (luaT_load(L, read_bootstrap_line, &iLine, "@bootstrap.cpp", "t") == 0) {
bootstrap_lua_resources(L);
lua_pushvalue(L, 1);
lua_call(L, 4, 0);
return 0;
}
else
} else
return lua_error(L);
}

View File

@@ -74,15 +74,17 @@ SOFTWARE.
#endif
// We bring in the most common stddef and stdint types to avoid typing
// clang-format off
using std::int8_t;
using std::int16_t;
using std::int32_t;
using std::int64_t;
using std::size_t;
using std::uint8_t;
using std::uint16_t;
using std::uint32_t;
using std::uint64_t;
using std::int8_t;
using std::int16_t;
using std::int32_t;
using std::int64_t;
// clang-format on
/** Visual Leak Detector **/
// In Visual Studio, Visual Leak Detector can be used to find memory leaks.

View File

@@ -3,6 +3,7 @@
#include <array>
// clang-format off
constexpr std::array<uint16_t, 0x80> cp437_to_unicode_table{
/* 0x00 through 0x7F need no translation */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
@@ -20,7 +21,6 @@ constexpr std::array<uint16_t, 0x80> cp437_to_unicode_table {
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x03BC, 0x03C4,
0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0};
// clang-format on
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -21,21 +21,20 @@ SOFTWARE.
*/
#include "iso_fs.h"
#include "th.h"
#include <cstring>
#include <cstdarg>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <array>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <vector>
#include "th.h"
namespace {
enum iso_volume_descriptor_type : uint8_t
{
enum iso_volume_descriptor_type : uint8_t {
vdt_primary_volume = 0x01,
// Other type numbers are either reserved for future use, or are not
// interesting to us.
@@ -43,8 +42,7 @@ enum iso_volume_descriptor_type : uint8_t
};
/// Flag values for directory table entries. The flag itself is a bitmask.
enum iso_dir_ent_flag : uint8_t
{
enum iso_dir_ent_flag : uint8_t {
def_hidden = 0x01,
def_directory = 0x02,
def_multi_extent = 0x80,
@@ -100,12 +98,9 @@ constexpr uint32_t first_filesystem_sector = 16;
/// Finds the length of the file name within a file identifier.
/// The file identifier is `filename;file id`.
void trim_file_id(const uint8_t* sIdent, uint8_t& iLength)
{
for (uint8_t i = 0; i < iLength; ++i)
{
if (sIdent[i] == ';')
{
void trim_file_id(const uint8_t* sIdent, uint8_t& iLength) {
for (uint8_t i = 0; i < iLength; ++i) {
if (sIdent[i] == ';') {
iLength = i;
return;
}
@@ -308,7 +303,8 @@ public:
*/
iso_directory_iterator& operator++() {
if (directory_ptr >= end_ptr) {
throw std::out_of_range("Cannot advance iso directory iterator past end of input");
throw std::out_of_range(
"Cannot advance iso directory iterator past end of input");
}
const uint8_t* new_dir_ptr = directory_ptr + *directory_ptr;
@@ -319,7 +315,9 @@ public:
// Catch a malformed directory entry where the size would extend past
// the end of the table.
if (new_dir_ptr < end_ptr && new_dir_ptr + *new_dir_ptr > end_ptr) {
throw std::runtime_error("The last directory entry was larger than the defined table region.");
throw std::runtime_error(
"The last directory entry was larger than the defined "
"table region.");
}
if (new_dir_ptr < end_ptr) {
@@ -354,32 +352,22 @@ private:
} // namespace
iso_filesystem::iso_filesystem() :
raw_file(nullptr),
error(nullptr),
files(),
path_seperator('\\')
{ }
iso_filesystem::iso_filesystem()
: raw_file(nullptr), error(nullptr), files(), path_seperator('\\') {}
iso_filesystem::~iso_filesystem()
{
clear();
}
iso_filesystem::~iso_filesystem() { clear(); }
void iso_filesystem::clear()
{
void iso_filesystem::clear() {
delete[] error;
error = nullptr;
files.clear();
}
void iso_filesystem::set_path_separator(char cSeparator)
{
void iso_filesystem::set_path_separator(char cSeparator) {
path_seperator = cSeparator;
}
bool iso_filesystem::initialise(std::FILE* fRawFile)
{
bool iso_filesystem::initialise(std::FILE* fRawFile) {
raw_file = fRawFile;
clear();
@@ -388,7 +376,8 @@ bool iso_filesystem::initialise(std::FILE* fRawFile)
// The first 16 sectors are reserved for bootable media.
// Volume descriptor records follow this, with one record per sector.
for(uint32_t iSector = first_filesystem_sector; seek_to_sector(iSector); ++iSector) {
for (uint32_t iSector = first_filesystem_sector; seek_to_sector(iSector);
++iSector) {
uint8_t aBuffer[root_directory_offset + root_directory_entry_size];
if (!read_data(sizeof(aBuffer), aBuffer)) {
break;
@@ -398,9 +387,12 @@ bool iso_filesystem::initialise(std::FILE* fRawFile)
if (aBuffer[0] == vdt_primary_volume) {
sector_size = bytes_to_uint16_le(aBuffer + sector_size_offset);
try {
find_hosp_directory(aBuffer + root_directory_offset, root_directory_entry_size, 0);
find_hosp_directory(aBuffer + root_directory_offset,
root_directory_entry_size, 0);
if (files.empty()) {
set_error("Could not find Theme Hospital data directory.");
set_error(
"Could not find Theme Hospital data "
"directory.");
return false;
} else {
return true;
@@ -418,24 +410,26 @@ bool iso_filesystem::initialise(std::FILE* fRawFile)
return false;
}
bool iso_filesystem::file_metadata_less(const file_metadata& lhs, const file_metadata& rhs)
{
bool iso_filesystem::file_metadata_less(const file_metadata& lhs,
const file_metadata& rhs) {
return lhs.path < rhs.path;
}
int iso_filesystem::find_hosp_directory(const uint8_t *pDirEnt, int iDirEntsSize, int iLevel)
{
int iso_filesystem::find_hosp_directory(const uint8_t* pDirEnt,
int iDirEntsSize, int iLevel) {
// Sanity check
// Apart from at the root level, directory record arrays must take up whole
// sectors, whose sizes are powers of two and at least 2048.
// The formal limit on directory depth is 8, so hitting 16 is insane.
if((iLevel != 0 && (iDirEntsSize & (min_sector_size - 1)) != 0) || iLevel > max_directory_depth)
if ((iLevel != 0 && (iDirEntsSize & (min_sector_size - 1)) != 0) ||
iLevel > max_directory_depth)
return 0;
uint8_t* pBuffer = nullptr;
uint32_t iBufferSize = 0;
iso_directory_iterator dir_iter(pDirEnt, pDirEnt + iDirEntsSize);
iso_directory_iterator end_iter(pDirEnt + iDirEntsSize, pDirEnt + iDirEntsSize);
iso_directory_iterator end_iter(pDirEnt + iDirEntsSize,
pDirEnt + iDirEntsSize);
for (; dir_iter != end_iter; ++dir_iter) {
const iso_file_entry& ent = *dir_iter;
if (ent.flags & def_directory) {
@@ -448,11 +442,14 @@ int iso_filesystem::find_hosp_directory(const uint8_t *pDirEnt, int iDirEntsSize
iBufferSize = ent.data_length;
pBuffer = new uint8_t[iBufferSize];
}
if (seek_to_sector(ent.data_sector) && read_data(ent.data_length, pBuffer)) {
int iFoundLevel = find_hosp_directory(pBuffer, ent.data_length, iLevel + 1);
if (seek_to_sector(ent.data_sector) &&
read_data(ent.data_length, pBuffer)) {
int iFoundLevel =
find_hosp_directory(pBuffer, ent.data_length, iLevel + 1);
if (iFoundLevel != 0) {
if (iFoundLevel == 2) {
build_file_lookup_table(ent.data_sector, ent.data_length, std::string(""));
build_file_lookup_table(ent.data_sector, ent.data_length,
std::string(""));
}
delete[] pBuffer;
return iFoundLevel + 1;
@@ -472,8 +469,8 @@ int iso_filesystem::find_hosp_directory(const uint8_t *pDirEnt, int iDirEntsSize
return 0;
}
void iso_filesystem::build_file_lookup_table(uint32_t iSector, int iDirEntsSize, const std::string& prefix)
{
void iso_filesystem::build_file_lookup_table(uint32_t iSector, int iDirEntsSize,
const std::string& prefix) {
// Sanity check
// Apart from at the root level, directory record arrays must take up whole
// sectors, whose sizes are powers of two and at least 2048.
@@ -483,15 +480,15 @@ void iso_filesystem::build_file_lookup_table(uint32_t iSector, int iDirEntsSize,
return;
uint8_t* pBuffer = new uint8_t[iDirEntsSize];
if(!seek_to_sector(iSector) || !read_data(iDirEntsSize, pBuffer))
{
if (!seek_to_sector(iSector) || !read_data(iDirEntsSize, pBuffer)) {
delete[] pBuffer;
return;
}
uint8_t* pDirEnt = pBuffer;
iso_directory_iterator dir_iter(pDirEnt, pDirEnt + iDirEntsSize);
iso_directory_iterator end_iter(pDirEnt + iDirEntsSize, pDirEnt + iDirEntsSize);
iso_directory_iterator end_iter(pDirEnt + iDirEntsSize,
pDirEnt + iDirEntsSize);
for (; dir_iter != end_iter; ++dir_iter) {
const iso_file_entry& ent = *dir_iter;
std::string path;
@@ -517,24 +514,24 @@ void iso_filesystem::build_file_lookup_table(uint32_t iSector, int iDirEntsSize,
}
delete[] pBuffer;
if(prefix.size() == 0)
{
if (prefix.size() == 0) {
// The lookup table will be ordered by the underlying ordering of the
// disk. we want it sorted by the path for ease of lookup.
std::sort(files.begin(), files.end(), file_metadata_less);
}
}
void iso_filesystem::visit_directory_files(const char* sPath,
void (*fnCallback)(void*, const char*, const char*),
void* pCallbackData) const
{
void iso_filesystem::visit_directory_files(
const char* sPath, void (*fnCallback)(void*, const char*, const char*),
void* pCallbackData) const {
std::string normalised_path = normalise(sPath);
// Inefficient (better would be to binary search for first and last files
// which begin with sPath), but who cares - this isn't called often
for (const file_metadata& file : files) {
if (normalised_path.size() < file.path.size() && std::equal(normalised_path.begin(), normalised_path.end(), file.path.begin())) {
if (normalised_path.size() < file.path.size() &&
std::equal(normalised_path.begin(), normalised_path.end(),
file.path.begin())) {
size_t filename_pos = normalised_path.size();
if (file.path.at(normalised_path.size()) == path_seperator) {
++filename_pos;
@@ -548,15 +545,13 @@ void iso_filesystem::visit_directory_files(const char* sPath,
}
}
iso_filesystem::file_handle iso_filesystem::find_file(const char* sPath) const
{
iso_filesystem::file_handle iso_filesystem::find_file(const char* sPath) const {
std::string normalised_path = normalise(sPath);
// Standard binary search over sorted list of files
int iLower = 0;
int iUpper = static_cast<int>(files.size());
while(iLower != iUpper)
{
while (iLower != iUpper) {
int iMid = (iLower + iUpper) / 2;
int iComp = normalised_path.compare(files[iMid].path);
if (iComp == 0) {
@@ -570,69 +565,55 @@ iso_filesystem::file_handle iso_filesystem::find_file(const char* sPath) const
return 0;
}
uint32_t iso_filesystem::get_file_size(file_handle iFile) const
{
uint32_t iso_filesystem::get_file_size(file_handle iFile) const {
if (iFile <= 0 || static_cast<size_t>(iFile) > files.size())
return 0;
else
return files[iFile - 1].size;
}
bool iso_filesystem::get_file_data(file_handle iFile, uint8_t *pBuffer)
{
if(iFile <= 0 || static_cast<size_t>(iFile) > files.size())
{
bool iso_filesystem::get_file_data(file_handle iFile, uint8_t* pBuffer) {
if (iFile <= 0 || static_cast<size_t>(iFile) > files.size()) {
set_error("Invalid file handle.");
return false;
}
else
{
} else {
return seek_to_sector(files[iFile - 1].sector) &&
read_data(files[iFile - 1].size, pBuffer);
}
}
const char* iso_filesystem::get_error() const
{
return error;
}
const char* iso_filesystem::get_error() const { return error; }
bool iso_filesystem::seek_to_sector(uint32_t iSector)
{
if(!raw_file)
{
bool iso_filesystem::seek_to_sector(uint32_t iSector) {
if (!raw_file) {
set_error("No raw file.");
return false;
}
if(std::fseek(raw_file, sector_size * static_cast<long>(iSector), SEEK_SET) == 0)
int res =
std::fseek(raw_file, sector_size * static_cast<long>(iSector), SEEK_SET);
if (res == 0) {
return true;
else
{
} else {
set_error("Unable to seek to sector %i.", static_cast<int>(iSector));
return false;
}
}
bool iso_filesystem::read_data(uint32_t iByteCount, uint8_t *pBuffer)
{
if(!raw_file)
{
bool iso_filesystem::read_data(uint32_t iByteCount, uint8_t* pBuffer) {
if (!raw_file) {
set_error("No raw file.");
return false;
}
if (std::fread(pBuffer, 1, iByteCount, raw_file) == iByteCount)
return true;
else
{
else {
set_error("Unable to read %i bytes.", static_cast<int>(iByteCount));
return false;
}
}
void iso_filesystem::set_error(const char* sFormat, ...)
{
if(error == nullptr)
{
void iso_filesystem::set_error(const char* sFormat, ...) {
if (error == nullptr) {
// None of the errors which we generate will be longer than 1024.
error = new char[1024];
}

View File

@@ -21,9 +21,9 @@ SOFTWARE.
*/
#include "config.h"
#include "th_lua.h"
#include <cstdio>
#include <string>
#include "th_lua.h"
//! Layer for reading Theme Hospital files out of an .iso disk image
/*!
@@ -34,8 +34,7 @@ SOFTWARE.
searches for the Theme Hospital data files, and can then be used to read
these data files.
*/
class iso_filesystem
{
class iso_filesystem {
public:
iso_filesystem();
~iso_filesystem();
@@ -76,7 +75,8 @@ public:
\param pCallbackData Opaque value to be called to fnCallback.
*/
void visit_directory_files(const char* sPath,
void (*fnCallback)(void*, const char*, const char*),
void (*fnCallback)(void*, const char*,
const char*),
void* pCallbackData) const;
//! Test if a file handle from findFile() is good or is invalid
@@ -97,8 +97,7 @@ public:
bool get_file_data(file_handle iFile, uint8_t* pBuffer);
private:
struct file_metadata
{
struct file_metadata {
std::string path;
uint32_t sector;
uint32_t size;
@@ -141,8 +140,10 @@ private:
\param iDirEntsSize The number of bytes in the directory entry array.
\param prefix The path name to prepend to filenames in the directory.
*/
void build_file_lookup_table(uint32_t iSector, int iDirEntsSize, const std::string& prefix);
void build_file_lookup_table(uint32_t iSector, int iDirEntsSize,
const std::string& prefix);
//! std:less like implementation for file_metadata. Based on the path.
static bool file_metadata_less(const file_metadata& lhs, const file_metadata& rhs);
static bool file_metadata_less(const file_metadata& lhs,
const file_metadata& rhs);
};

View File

@@ -24,8 +24,8 @@ SOFTWARE.
#define CORSIX_TH_LUA_HPP_
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
}
@@ -35,22 +35,17 @@ extern "C" {
// with LUA_COMPAT_ALL defined, but we have no control over this.
#ifndef lua_objlen
inline size_t lua_objlen(lua_State *L, int idx)
{
return lua_rawlen(L, idx);
}
inline size_t lua_objlen(lua_State* L, int idx) { return lua_rawlen(L, idx); }
#endif
#ifndef lua_equal
inline int lua_equal(lua_State *L, int idx1, int idx2)
{
inline int lua_equal(lua_State* L, int idx1, int idx2) {
return lua_compare(L, idx1, idx2, LUA_OPEQ);
}
#endif
#ifndef lua_lessthan
inline int lua_lessthan(lua_State *L, int idx1, int idx2)
{
inline int lua_lessthan(lua_State* L, int idx1, int idx2) {
return lua_compare(L, idx1, idx2, LUA_OPLT);
}
#endif
@@ -58,18 +53,12 @@ inline int lua_lessthan(lua_State *L, int idx1, int idx2)
// Use our own replacements for lua_[sg]etfenv
#ifndef lua_setfenv
int luaT_setfenv52(lua_State*, int);
inline int lua_setfenv(lua_State *L, int n)
{
return luaT_setfenv52(L, n);
}
inline int lua_setfenv(lua_State* L, int n) { return luaT_setfenv52(L, n); }
#endif
#ifndef lua_getfenv
void luaT_getfenv52(lua_State*, int);
inline void lua_getfenv(lua_State *L, int n)
{
luaT_getfenv52(L, n);
}
inline void lua_getfenv(lua_State* L, int n) { luaT_getfenv52(L, n); }
#endif
#endif // LUA_VERSION_NUM >= 502

View File

@@ -1,7 +1,7 @@
#include "lua_rnc.h"
#include <array>
#include "../../common/rnc.h"
#include "th_lua.h"
#include <array>
//! Provides lua function to decompress RNC data
/*!
@@ -12,15 +12,14 @@
namespace {
int l_decompress(lua_State *L)
{
int l_decompress(lua_State* L) {
size_t inlen;
const uint8_t* in = reinterpret_cast<const uint8_t*>(luaL_checklstring(L, 1, &inlen));
const uint8_t* in =
reinterpret_cast<const uint8_t*>(luaL_checklstring(L, 1, &inlen));
// Verify that the data contains an RNC signature, and that the input
// size matches the size specified in the data header.
if(inlen < rnc_header_size || inlen != rnc_input_size(in))
{
if (inlen < rnc_header_size || inlen != rnc_input_size(in)) {
lua_pushnil(L);
lua_pushliteral(L, "Input is not RNC compressed data");
return 2;
@@ -34,8 +33,7 @@ int l_decompress(lua_State *L)
void* outbuf = lua_newuserdata(L, outlen);
lua_pushnil(L);
switch(rnc_unpack(in, (uint8_t*)outbuf))
{
switch (rnc_unpack(in, (uint8_t*)outbuf)) {
case rnc_status::ok:
lua_pushlstring(L, (const char*)outbuf, outlen);
return 1;
@@ -67,15 +65,12 @@ int l_decompress(lua_State *L)
return 2;
}
constexpr std::array<luaL_Reg, 2> rnclib {{
{"decompress", l_decompress},
{nullptr, nullptr}
}};
constexpr std::array<luaL_Reg, 2> rnclib{
{{"decompress", l_decompress}, {nullptr, nullptr}}};
} // namespace
int luaopen_rnc(lua_State *L)
{
int luaopen_rnc(lua_State* L) {
luaT_register(L, "rnc", rnclib);
return 1;
}

View File

@@ -23,8 +23,8 @@ SOFTWARE.
#ifndef CORSIX_TH_LUA_SDL_H_
#define CORSIX_TH_LUA_SDL_H_
#include "lua.hpp"
#include <SDL.h>
#include "lua.hpp"
// SDL event codes used for delivering custom events to l_mainloop in
// sdl_core.cpp

View File

@@ -21,18 +21,15 @@ SOFTWARE.
*/
#include "config.h"
#include <cstdio>
#include <cstring>
#include <string>
#include "iso_fs.h"
#include "lua.hpp"
extern "C" {
int luaopen_random(lua_State *L);
}
#include "th_lua.h"
#include "lua_rnc.h"
#include "lua_sdl.h"
#include "persist_lua.h"
#include "iso_fs.h"
#include <cstring>
#include <cstdio>
#include <string>
#include "th_lua.h"
// Config file checking
#ifndef CORSIX_TH_USE_PACK_PRAGMAS
@@ -40,26 +37,33 @@ int luaopen_random(lua_State *L);
#endif
// End of config file checking
extern "C" {
int luaopen_random(lua_State* L);
}
namespace {
inline void preload_lua_package(lua_State *L, const char* name, lua_CFunction fn)
{
luaT_execute(L, std::string("package.preload.").append(name).append(" = ...").c_str(), fn);
inline void preload_lua_package(lua_State* L, const char* name,
lua_CFunction fn) {
luaT_execute(
L, std::string("package.preload.").append(name).append(" = ...").c_str(),
fn);
}
} // namespace
int lua_main_no_eval(lua_State *L)
{
int lua_main_no_eval(lua_State* L) {
// assert(_VERSION == LUA_VERSION)
size_t iLength;
lua_getglobal(L, "_VERSION");
const char* sVersion = lua_tolstring(L, -1, &iLength);
if(iLength != std::strlen(LUA_VERSION) || std::strcmp(sVersion, LUA_VERSION) != 0)
{
lua_pushliteral(L, "Linked against a version of Lua different to the "
"one used when compiling.\nPlease recompile CorsixTH against the "
"same Lua version it is linked against.");
if (iLength != std::strlen(LUA_VERSION) ||
std::strcmp(sVersion, LUA_VERSION) != 0) {
lua_pushliteral(
L,
"Linked against a version of Lua different to the one used "
"when compiling.\nPlease recompile CorsixTH against the same "
"Lua version it is linked against.");
return lua_error(L);
}
lua_pop(L, 1);
@@ -80,14 +84,11 @@ int lua_main_no_eval(lua_State *L)
// Check for --interpreter and run that instead of CorsixTH.lua
bool bGotScriptFile = false;
int iNArgs = lua_gettop(L);
for(int i = 1; i <= iNArgs; ++i)
{
if(lua_type(L, i) == LUA_TSTRING)
{
for (int i = 1; i <= iNArgs; ++i) {
if (lua_type(L, i) == LUA_TSTRING) {
size_t iLen;
const char* sCmd = lua_tolstring(L, i, &iLen);
if(iLen > 14 && std::memcmp(sCmd, "--interpreter=", 14) == 0)
{
if (iLen > 14 && std::memcmp(sCmd, "--interpreter=", 14) == 0) {
lua_getglobal(L, "assert");
lua_getglobal(L, "loadfile");
lua_pushlstring(L, sCmd + 14, iLen - 14);
@@ -97,8 +98,7 @@ int lua_main_no_eval(lua_State *L)
}
}
if(!bGotScriptFile)
{
if (!bGotScriptFile) {
lua_getglobal(L, "assert");
lua_getglobal(L, "loadfile");
lua_pushstring(L, CORSIX_TH_INTERPRETER_PATH);
@@ -111,14 +111,12 @@ int lua_main_no_eval(lua_State *L)
return lua_gettop(L);
}
int lua_main(lua_State *L)
{
int lua_main(lua_State* L) {
lua_call(L, lua_main_no_eval(L) - 1, LUA_MULTRET);
return lua_gettop(L);
}
int lua_stacktrace(lua_State *L)
{
int lua_stacktrace(lua_State* L) {
// err = tostring(err)
lua_settop(L, 1);
lua_getglobal(L, "tostring");
@@ -140,10 +138,10 @@ int lua_stacktrace(lua_State *L)
return 1;
}
int lua_panic(lua_State *L)
{
std::fprintf(stderr, "A Lua error has occurred in CorsixTH outside of protected "
"mode!!\n");
int lua_panic(lua_State* L) {
std::fprintf(stderr,
"A Lua error has occurred in CorsixTH outside of protected "
"mode!\n");
std::fflush(stderr);
if (lua_type(L, -1) == LUA_TSTRING)

File diff suppressed because it is too large Load Diff

View File

@@ -23,20 +23,23 @@ SOFTWARE.
#ifndef CORSIX_TH_PERSIST_LUA_H_
#define CORSIX_TH_PERSIST_LUA_H_
#include "config.h"
#include "th_lua.h"
#include <vector>
#include <cstdlib>
#include <vector>
#include "th_lua.h"
template <class T> struct lua_persist_int {};
template <> struct lua_persist_int<int> {typedef unsigned int T;};
template <class T>
struct lua_persist_int {};
template <>
struct lua_persist_int<int> {
typedef unsigned int T;
};
//! Interface used for persisting Lua objects
/*!
When userdata are persisted, they get an instance of this interface for
writing binary data and other Lua objects.
*/
class lua_persist_writer
{
class lua_persist_writer {
public:
virtual ~lua_persist_writer() = default;
@@ -54,23 +57,17 @@ public:
// Writes an unsigned integer as a variable number of bytes
// Endian independant and underlying type size independant
template <class T>
void write_uint(T tValue)
{
void write_uint(T tValue) {
T tTemp(tValue);
int iNumBytes;
for(iNumBytes = 1; tTemp >= (T)0x80; tTemp /= (T)0x80)
++iNumBytes;
if(iNumBytes == 1)
{
for (iNumBytes = 1; tTemp >= (T)0x80; tTemp /= (T)0x80) ++iNumBytes;
if (iNumBytes == 1) {
uint8_t iByte = (uint8_t)tValue;
write_byte_stream(&iByte, 1);
}
else
{
} else {
std::vector<uint8_t> bytes(iNumBytes);
bytes[iNumBytes - 1] = 0x7F & (uint8_t)(tValue);
for(int i = 1; i < iNumBytes; ++i)
{
for (int i = 1; i < iNumBytes; ++i) {
tValue /= (T)0x80;
bytes[iNumBytes - 1 - i] = 0x80 | (0x7F & (uint8_t)tValue);
}
@@ -79,16 +76,12 @@ public:
}
template <class T>
void write_int(T tValue)
{
void write_int(T tValue) {
typename lua_persist_int<T>::T tValueToWrite;
if(tValue >= 0)
{
if (tValue >= 0) {
tValueToWrite = (typename lua_persist_int<T>::T)tValue;
tValueToWrite <<= 1;
}
else
{
} else {
tValueToWrite = (typename lua_persist_int<T>::T)(-(tValue + 1));
tValueToWrite <<= 1;
tValueToWrite |= 1;
@@ -97,8 +90,7 @@ public:
}
template <class T>
void write_float(T fValue)
{
void write_float(T fValue) {
write_byte_stream(reinterpret_cast<uint8_t*>(&fValue), sizeof(T));
}
};
@@ -108,8 +100,7 @@ public:
When userdata are depersisted, they get an instance of this interface for
reading binary data and other Lua objects.
*/
class lua_persist_reader
{
class lua_persist_reader {
public:
virtual ~lua_persist_reader() = default;
@@ -120,22 +111,16 @@ public:
// Reads an integer previously written by lua_persist_writer::write_uint()
template <class T>
bool read_uint(T& tValue)
{
bool read_uint(T& tValue) {
T tTemp(0);
uint8_t iByte;
while(true)
{
if(!read_byte_stream(&iByte, 1))
return false;
if(iByte & 0x80)
{
while (true) {
if (!read_byte_stream(&iByte, 1)) return false;
if (iByte & 0x80) {
tTemp = static_cast<T>(tTemp | (iByte & 0x7F));
tTemp = static_cast<T>(tTemp << 7);
}
else
{
} else {
tTemp = static_cast<T>(tTemp | iByte);
break;
}
@@ -146,11 +131,9 @@ public:
}
template <class T>
bool read_int(T& tValue)
{
bool read_int(T& tValue) {
typename lua_persist_int<T>::T tWrittenValue;
if(!read_uint(tWrittenValue))
return false;
if (!read_uint(tWrittenValue)) return false;
if (tWrittenValue & 1)
tValue = (-(T)(tWrittenValue >> 1)) - 1;
else
@@ -159,8 +142,7 @@ public:
}
template <class T>
bool read_float(T& fValue)
{
bool read_float(T& fValue) {
if (!read_byte_stream(reinterpret_cast<uint8_t*>(&fValue), sizeof(T)))
return false;
return true;

View File

@@ -41,8 +41,8 @@
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
#include <lua.h>
#include <lauxlib.h>
#include <lua.h>
#ifdef _MSC_VER
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
@@ -61,12 +61,10 @@ uint32_t mt[N]; /* the array for the state vector */
uint16_t mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
/* initializes mt[N] with a seed */
static void init_genrand(uint32_t s)
{
static void init_genrand(uint32_t s) {
mt[0] = s;
for (mti = 1; mti < N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
@@ -74,8 +72,7 @@ static void init_genrand(uint32_t s)
}
/* generates a random number on [0,0xffffffff]-interval */
static uint32_t genrand_int32(void)
{
static uint32_t genrand_int32(void) {
uint32_t y;
static uint32_t mag01[2] = {0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
@@ -112,8 +109,7 @@ static uint32_t genrand_int32(void)
}
/* generates a random number on [0,1) with 53-bit resolution*/
static double genrand_res53(void)
{
static double genrand_res53(void) {
uint32_t a = genrand_int32() >> 5, b = genrand_int32() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
@@ -129,12 +125,10 @@ static double genrand_res53(void)
[1, range_end]. If called with two or more arguments, returns a random
integer in the range [range_start, range_end].
*/
static int l_random(lua_State *L)
{
static int l_random(lua_State* L) {
lua_Integer min;
uint32_t max;
switch(lua_gettop(L))
{
switch (lua_gettop(L)) {
default:
case 2:
min = luaL_checkinteger(L, 1);
@@ -162,8 +156,7 @@ static int l_random(lua_State *L)
Returns a string which can later be passed to math.randomseed() to restore
the random number generator to its current state.
*/
static int l_randomdump(lua_State *L)
{
static int l_randomdump(lua_State* L) {
lua_pushlstring(L, (const char*)mt, N * 4);
lua_pushlstring(L, (const char*)&mti, 2);
lua_concat(L, 2);
@@ -180,28 +173,21 @@ static int l_randomdump(lua_State *L)
the random number generator state from a string previously generated from
math.randomdump().
*/
static int l_randomseed(lua_State *L)
{
if(lua_type(L, 1) == LUA_TSTRING)
{
static int l_randomseed(lua_State* L) {
if (lua_type(L, 1) == LUA_TSTRING) {
int i;
size_t len;
const char* data = lua_tolstring(L, 1, &len);
if(len != N * 4 + 2)
luaL_argerror(L, 1, "Seed string wrong length");
for(i = 0; i < N; ++i)
mt[i] = ((uint32_t*)data)[i];
if (len != N * 4 + 2) luaL_argerror(L, 1, "Seed string wrong length");
for (i = 0; i < N; ++i) mt[i] = ((uint32_t*)data)[i];
mti = *(uint16_t*)(data + len - 2);
}
else
{
} else {
init_genrand((uint32_t)luaL_checkinteger(L, 1));
}
return 0;
}
int luaopen_random(lua_State *L)
{
int luaopen_random(lua_State* L) {
lua_getglobal(L, "math");
lua_pushliteral(L, "random");
lua_pushcfunction(L, l_random);

View File

@@ -21,24 +21,19 @@ SOFTWARE.
*/
#include "run_length_encoder.h"
#include "persist_lua.h"
#include <new>
#include <algorithm>
#include <new>
#include "persist_lua.h"
integer_run_length_encoder::integer_run_length_encoder()
{
integer_run_length_encoder::integer_run_length_encoder() {
buffer = nullptr;
output = nullptr;
clean();
}
integer_run_length_encoder::~integer_run_length_encoder()
{
clean();
}
integer_run_length_encoder::~integer_run_length_encoder() { clean(); }
void integer_run_length_encoder::clean()
{
void integer_run_length_encoder::clean() {
delete[] buffer;
delete[] output;
buffer = nullptr;
@@ -53,8 +48,7 @@ void integer_run_length_encoder::clean()
object_copies = 0;
}
bool integer_run_length_encoder::initialise(size_t iRecordSize)
{
bool integer_run_length_encoder::initialise(size_t iRecordSize) {
clean();
record_size = iRecordSize;
@@ -65,14 +59,12 @@ bool integer_run_length_encoder::initialise(size_t iRecordSize)
buffer_size = 0;
buffer_offset = 0;
buffer = new (std::nothrow) uint32_t[buffer_capacity];
if(!buffer)
return false;
if (!buffer) return false;
output_capacity = iRecordSize * 32;
output_size = 0;
output = new (std::nothrow) uint32_t[output_capacity];
if(!output)
return false;
if (!output) return false;
object_size = 0;
object_copies = 0;
@@ -80,59 +72,45 @@ bool integer_run_length_encoder::initialise(size_t iRecordSize)
return true;
}
void integer_run_length_encoder::write(uint32_t iValue)
{
void integer_run_length_encoder::write(uint32_t iValue) {
buffer[(buffer_offset + buffer_size) % buffer_capacity] = iValue;
if(++buffer_size == buffer_capacity)
flush(false);
if (++buffer_size == buffer_capacity) flush(false);
}
void integer_run_length_encoder::finish()
{
if(buffer_size != 0)
flush(true);
void integer_run_length_encoder::finish() {
if (buffer_size != 0) flush(true);
}
void integer_run_length_encoder::flush(bool bAll)
{
do
{
if(object_size == 0)
{
void integer_run_length_encoder::flush(bool bAll) {
do {
if (object_size == 0) {
// Decide on the size of the next object
// Want the object size which gives most object repeats, then for
// two sizes with the same repeat count, the smaller size.
size_t iBestRepeats = 0;
size_t iBestSize = 0;
size_t iBestOffset = 0;
for(size_t iNumRecords = 1; iNumRecords <= 8; ++iNumRecords)
{
for(size_t iOffset = 0; iOffset < iNumRecords; ++iOffset)
{
for (size_t iNumRecords = 1; iNumRecords <= 8; ++iNumRecords) {
for (size_t iOffset = 0; iOffset < iNumRecords; ++iOffset) {
size_t iNumRepeats = 0;
size_t iObjSize = iNumRecords * record_size;
while(iObjSize * (iOffset + iNumRepeats + 1) <= buffer_size
&& are_ranges_equal(0, iNumRepeats, iOffset, iObjSize))
{
while (iObjSize * (iOffset + iNumRepeats + 1) <= buffer_size &&
are_ranges_equal(0, iNumRepeats, iOffset, iObjSize)) {
++iNumRepeats;
}
if(iNumRepeats > iBestRepeats
||(iNumRepeats == iBestRepeats && iObjSize < iBestSize))
{
if (iNumRepeats > iBestRepeats ||
(iNumRepeats == iBestRepeats && iObjSize < iBestSize)) {
iBestRepeats = iNumRepeats;
iBestSize = iObjSize;
iBestOffset = iOffset;
}
}
}
if(iBestRepeats == 1)
{
if (iBestRepeats == 1) {
// No repeats were found, so the best we can do is output
// a large non-repeating blob.
move_object_to_output(std::min(buffer_size, 8 * record_size), 1);
}
else
{
} else {
if (iBestOffset != 0)
move_object_to_output(iBestOffset * record_size, 1);
// Mark the object as the current one, and remove all but the
@@ -141,23 +119,20 @@ void integer_run_length_encoder::flush(bool bAll)
// object isn't output just yet.
object_size = iBestSize;
object_copies = iBestRepeats - 1;
buffer_offset = (buffer_offset + object_size * object_copies) % buffer_capacity;
buffer_offset =
(buffer_offset + object_size * object_copies) % buffer_capacity;
buffer_size -= object_size * object_copies;
}
}
else
{
} else {
// Try to match more of the current object
while (object_size * 2 <= buffer_size &&
are_ranges_equal(0, 1, 0, object_size))
{
are_ranges_equal(0, 1, 0, object_size)) {
++object_copies;
buffer_offset = (buffer_offset + object_size) % buffer_capacity;
buffer_size -= object_size;
}
// Write data
if(object_size * 2 <= buffer_size || bAll)
{
if (object_size * 2 <= buffer_size || bAll) {
move_object_to_output(object_size, object_copies + 1);
object_size = 0;
object_copies = 0;
@@ -166,31 +141,28 @@ void integer_run_length_encoder::flush(bool bAll)
} while (bAll && buffer_size != 0);
}
bool integer_run_length_encoder::are_ranges_equal(size_t iObjIdx1, size_t iObjIdx2,
size_t iOffset, size_t iObjSize) const
{
bool integer_run_length_encoder::are_ranges_equal(size_t iObjIdx1,
size_t iObjIdx2,
size_t iOffset,
size_t iObjSize) const {
iObjIdx1 = buffer_offset + iOffset * record_size + iObjIdx1 * iObjSize;
iObjIdx2 = buffer_offset + iOffset * record_size + iObjIdx2 * iObjSize;
for(size_t i = 0; i < iObjSize; ++i)
{
if(buffer[(iObjIdx1 + i) % buffer_capacity]
!= buffer[(iObjIdx2 + i) % buffer_capacity])
{
for (size_t i = 0; i < iObjSize; ++i) {
if (buffer[(iObjIdx1 + i) % buffer_capacity] !=
buffer[(iObjIdx2 + i) % buffer_capacity]) {
return false;
}
}
return true;
}
bool integer_run_length_encoder::move_object_to_output(size_t iObjSize, size_t iObjCount)
{
bool integer_run_length_encoder::move_object_to_output(size_t iObjSize,
size_t iObjCount) {
// Grow the output array if needed
if(output_capacity - output_size <= iObjSize)
{
if (output_capacity - output_size <= iObjSize) {
size_t iNewSize = (output_capacity + iObjSize) * 2;
uint32_t* pNewOutput = new (std::nothrow) uint32_t[iNewSize];
if(!pNewOutput)
return false;
if (!pNewOutput) return false;
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#endif
@@ -205,8 +177,7 @@ bool integer_run_length_encoder::move_object_to_output(size_t iObjSize, size_t i
size_t iHeader = (iObjSize / record_size - 1) + 8 * (iObjCount - 1);
output[output_size++] = static_cast<uint32_t>(iHeader);
// Move the object from the buffer to the output
for(size_t i = 0; i < iObjSize; ++i)
{
for (size_t i = 0; i < iObjSize; ++i) {
output[output_size++] = buffer[buffer_offset];
buffer_offset = (buffer_offset + 1) % buffer_capacity;
}
@@ -214,35 +185,27 @@ bool integer_run_length_encoder::move_object_to_output(size_t iObjSize, size_t i
return true;
}
uint32_t* integer_run_length_encoder::get_output(size_t *pCount) const
{
if(pCount)
*pCount = output_size;
uint32_t* integer_run_length_encoder::get_output(size_t* pCount) const {
if (pCount) *pCount = output_size;
return output;
}
void integer_run_length_encoder::pump_output(lua_persist_writer *pWriter) const
{
void integer_run_length_encoder::pump_output(
lua_persist_writer* pWriter) const {
pWriter->write_uint(output_size);
for(size_t i = 0; i < output_size; ++i)
{
for (size_t i = 0; i < output_size; ++i) {
pWriter->write_uint(output[i]);
}
}
integer_run_length_decoder::integer_run_length_decoder()
{
integer_run_length_decoder::integer_run_length_decoder() {
buffer = nullptr;
clean();
}
integer_run_length_decoder::~integer_run_length_decoder()
{
clean();
}
integer_run_length_decoder::~integer_run_length_decoder() { clean(); }
void integer_run_length_decoder::clean()
{
void integer_run_length_decoder::clean() {
delete[] buffer;
buffer = nullptr;
reader = nullptr;
@@ -255,71 +218,59 @@ void integer_run_length_decoder::clean()
object_size = 0;
}
bool integer_run_length_decoder::initialise(size_t iRecordSize, lua_persist_reader *pReader)
{
bool integer_run_length_decoder::initialise(size_t iRecordSize,
lua_persist_reader* pReader) {
clean();
buffer = new (std::nothrow) uint32_t[9 * iRecordSize];
if(!buffer)
return false;
if (!buffer) return false;
reader = pReader;
record_size = iRecordSize;
return pReader->read_uint(reads_remaining);
}
bool integer_run_length_decoder::initialise(size_t iRecordSize, const uint32_t *pInput, size_t iCount)
{
bool integer_run_length_decoder::initialise(size_t iRecordSize,
const uint32_t* pInput,
size_t iCount) {
clean();
buffer = new (std::nothrow) uint32_t[9 * iRecordSize];
if(!buffer)
return false;
if (!buffer) return false;
input = pInput;
input_end = pInput + iCount;
record_size = iRecordSize;
return true;
}
uint32_t integer_run_length_decoder::read()
{
if(object_copies == 0)
{
uint32_t integer_run_length_decoder::read() {
if (object_copies == 0) {
uint32_t iHeader = 0;
if(reader)
{
if (reader) {
reader->read_uint(iHeader);
--reads_remaining;
}
else
} else
iHeader = *(input++);
object_size = record_size * (1 + (iHeader & 7));
object_copies = (iHeader / 8) + 1;
if(reader)
{
for(size_t i = 0; i < object_size; ++i)
{
if (reader) {
for (size_t i = 0; i < object_size; ++i) {
reader->read_uint(buffer[i]);
--reads_remaining;
}
}
else
{
for(size_t i = 0; i < object_size; ++i)
buffer[i] = *(input++);
} else {
for (size_t i = 0; i < object_size; ++i) buffer[i] = *(input++);
}
}
uint32_t iValue = buffer[object_index];
if(++object_index == object_size)
{
if (++object_index == object_size) {
object_index = 0;
--object_copies;
}
return iValue;
}
bool integer_run_length_decoder::is_finished() const
{
bool integer_run_length_decoder::is_finished() const {
if (reader)
return reads_remaining == 0 && object_copies == 0;
else

View File

@@ -39,8 +39,7 @@ class lua_persist_writer;
* Object - One or more records. Each object has an associated repeat
count.
*/
class integer_run_length_encoder
{
class integer_run_length_encoder {
public:
integer_run_length_encoder();
~integer_run_length_encoder();
@@ -76,7 +75,8 @@ private:
*/
void flush(bool bAll);
bool are_ranges_equal(size_t iObjIdx1, size_t iObjIdx2, size_t iOffset, size_t iObjSize) const;
bool are_ranges_equal(size_t iObjIdx1, size_t iObjIdx2, size_t iOffset,
size_t iObjSize) const;
bool move_object_to_output(size_t iObjSize, size_t iObjCount);
//! A circular fixed-size buffer holding the most recent input
@@ -103,8 +103,7 @@ private:
size_t object_copies;
};
class integer_run_length_decoder
{
class integer_run_length_decoder {
public:
integer_run_length_decoder();
~integer_run_length_decoder();
@@ -120,8 +119,7 @@ private:
uint32_t* buffer;
lua_persist_reader* reader;
const uint32_t* input;
union
{
union {
const uint32_t* input_end;
size_t reads_remaining;
};

View File

@@ -21,31 +21,25 @@ SOFTWARE.
*/
#include "config.h"
#include "lua_sdl.h"
#ifdef CORSIX_TH_USE_SDL_MIXER
#include <SDL_mixer.h>
#include <array>
#include <cstring>
#include "lua_sdl.h"
#include "th_lua.h"
#include "xmi2mid.h"
#include <SDL_mixer.h>
#ifdef _MSC_VER
#pragma comment(lib, "SDL2_mixer")
#endif
#include <cstring>
#include <array>
class music
{
class music {
public:
Mix_Music* pMusic;
music()
{
pMusic = nullptr;
}
music() { pMusic = nullptr; }
~music()
{
if(pMusic)
{
~music() {
if (pMusic) {
Mix_FreeMusic(pMusic);
pMusic = nullptr;
}
@@ -54,34 +48,32 @@ public:
namespace {
void audio_music_over_callback()
{
void audio_music_over_callback() {
SDL_Event e;
e.type = SDL_USEREVENT_MUSIC_OVER;
SDL_PushEvent(&e);
}
int l_init(lua_State *L)
{
if(Mix_OpenAudio(static_cast<int>(luaL_optinteger(L, 1, MIX_DEFAULT_FREQUENCY)),
int l_init(lua_State* L) {
constexpr int chunk_size = 2048;
int err = Mix_OpenAudio(
static_cast<int>(luaL_optinteger(L, 1, MIX_DEFAULT_FREQUENCY)),
MIX_DEFAULT_FORMAT,
static_cast<int>(luaL_optinteger(L, 2, MIX_DEFAULT_CHANNELS)),
static_cast<int>(luaL_optinteger(L, 3, 2048)) /* chunk size */) != 0)
{
static_cast<int>(luaL_optinteger(L, 3, chunk_size)));
if (err != 0) {
lua_pushboolean(L, 0);
lua_pushstring(L, Mix_GetError());
return 2;
}
else
{
} else {
lua_pushboolean(L, 1);
Mix_HookMusicFinished(audio_music_over_callback);
return 1;
}
}
struct load_music_async_data
{
struct load_music_async_data {
lua_State* L;
Mix_Music* music;
SDL_RWops* rwop;
@@ -89,14 +81,12 @@ struct load_music_async_data
SDL_Thread* thread;
};
int load_music_async_thread(void* arg)
{
int load_music_async_thread(void* arg) {
load_music_async_data* async = (load_music_async_data*)arg;
async->music = Mix_LoadMUS_RW(async->rwop, 1);
async->rwop = nullptr;
if(async->music == nullptr)
{
if (async->music == nullptr) {
size_t iLen = std::strlen(Mix_GetError()) + 1;
async->err = (char*)malloc(iLen);
std::memcpy(async->err, Mix_GetError(), iLen);
@@ -108,8 +98,7 @@ int load_music_async_thread(void* arg)
return 0;
}
int l_load_music_async(lua_State *L)
{
int l_load_music_async(lua_State* L) {
size_t iLength;
const uint8_t* pData = luaT_checkfile(L, 1, &iLength);
luaL_checktype(L, 2, LUA_TFUNCTION);
@@ -145,19 +134,18 @@ int l_load_music_async(lua_State *L)
call the callback and remove the new entries from the registry.
*/
async->thread = SDL_CreateThread(load_music_async_thread, "music_thread", async);
async->thread =
SDL_CreateThread(load_music_async_thread, "music_thread", async);
return 0;
}
int l_load_music(lua_State *L)
{
int l_load_music(lua_State* L) {
size_t iLength;
const uint8_t* pData = luaT_checkfile(L, 1, &iLength);
SDL_RWops* rwop = SDL_RWFromConstMem(pData, (int)iLength);
Mix_Music* pMusic = Mix_LoadMUS_RW(rwop, 1);
if(pMusic == nullptr)
{
if (pMusic == nullptr) {
lua_pushnil(L);
lua_pushstring(L, Mix_GetError());
return 2;
@@ -169,24 +157,24 @@ int l_load_music(lua_State *L)
return 1;
}
int l_music_volume(lua_State *L)
{
int l_music_volume(lua_State* L) {
lua_Number fValue = luaL_checknumber(L, 1);
fValue = fValue * (lua_Number)MIX_MAX_VOLUME;
int iVolume = (int)(fValue + 0.5);
if(iVolume < 0)
if (iVolume < 0) {
iVolume = 0;
else if(iVolume > MIX_MAX_VOLUME)
} else if (iVolume > MIX_MAX_VOLUME) {
iVolume = MIX_MAX_VOLUME;
}
Mix_VolumeMusic(iVolume);
return 0;
}
int l_play_music(lua_State *L)
{
int l_play_music(lua_State* L) {
music* pLMusic = luaT_testuserdata<music>(L, -1);
if(Mix_PlayMusic(pLMusic->pMusic, static_cast<int>(luaL_optinteger(L, 2, 1))) != 0)
{
int err = Mix_PlayMusic(pLMusic->pMusic,
static_cast<int>(luaL_optinteger(L, 2, 1)));
if (err != 0) {
lua_pushnil(L);
lua_pushstring(L, Mix_GetError());
return 2;
@@ -195,34 +183,29 @@ int l_play_music(lua_State *L)
return 1;
}
int l_pause_music(lua_State *L)
{
int l_pause_music(lua_State* L) {
Mix_PauseMusic();
lua_pushboolean(L, Mix_PausedMusic() != 0 ? 1 : 0);
return 1;
}
int l_resume_music(lua_State *L)
{
int l_resume_music(lua_State* L) {
Mix_ResumeMusic();
lua_pushboolean(L, Mix_PausedMusic() == 0 ? 1 : 0);
return 1;
}
int l_stop_music(lua_State *L)
{
int l_stop_music(lua_State* L) {
Mix_HaltMusic();
return 0;
}
int l_transcode_xmi(lua_State *L)
{
int l_transcode_xmi(lua_State* L) {
size_t iLength, iMidLength;
const uint8_t* pData = luaT_checkfile(L, 1, &iLength);
uint8_t* pMidData = transcode_xmi_to_midi(pData, iLength, &iMidLength);
if(pMidData == nullptr)
{
if (pMidData == nullptr) {
lua_pushnil(L);
lua_pushliteral(L, "Unable to transcode XMI to MIDI");
return 2;
@@ -233,27 +216,24 @@ int l_transcode_xmi(lua_State *L)
return 1;
}
constexpr std::array<struct luaL_Reg, 3> sdl_audiolib {{
{"init", l_init},
constexpr std::array<struct luaL_Reg, 3> sdl_audiolib{
{{"init", l_init},
{"transcodeXmiToMid", l_transcode_xmi},
{nullptr, nullptr}
}};
{nullptr, nullptr}}};
constexpr std::array<struct luaL_Reg, 8> sdl_musiclib {{
{"loadMusic", l_load_music},
constexpr std::array<struct luaL_Reg, 8> sdl_musiclib{
{{"loadMusic", l_load_music},
{"loadMusicAsync", l_load_music_async},
{"playMusic", l_play_music},
{"stopMusic", l_stop_music},
{"pauseMusic", l_pause_music},
{"resumeMusic", l_resume_music},
{"setMusicVolume", l_music_volume},
{nullptr, nullptr}
}};
{nullptr, nullptr}}};
} // namespace
int l_load_music_async_callback(lua_State *L)
{
int l_load_music_async_callback(lua_State* L) {
load_music_async_data* async = (load_music_async_data*)lua_touserdata(L, 1);
// Frees resources allocated to the thread
@@ -273,21 +253,16 @@ int l_load_music_async_callback(lua_State *L)
// Push CB arguments
int nargs = 1;
if(async->music == nullptr)
{
if (async->music == nullptr) {
lua_pushnil(L);
if(async->err)
{
if(*async->err)
{
if (async->err) {
if (*async->err) {
lua_pushstring(L, async->err);
nargs = 2;
}
free(async->err);
}
}
else
{
} else {
lua_rawgeti(L, 2, 2);
music* pLMusic = (music*)lua_touserdata(L, -1);
pLMusic->pMusic = async->music;
@@ -305,8 +280,7 @@ int l_load_music_async_callback(lua_State *L)
return 0;
}
int luaopen_sdl_audio(lua_State *L)
{
int luaopen_sdl_audio(lua_State* L) {
lua_newtable(L);
luaT_setfuncs(L, sdl_audiolib.data());
lua_pushboolean(L, 1);
@@ -328,8 +302,7 @@ int luaopen_sdl_audio(lua_State *L)
#else // CORSIX_TH_USE_SDL_MIXER
int luaopen_sdl_audio(lua_State *L)
{
int luaopen_sdl_audio(lua_State* L) {
lua_newtable(L);
lua_pushboolean(L, 0);
lua_setfield(L, -2, "loaded");
@@ -337,9 +310,6 @@ int luaopen_sdl_audio(lua_State *L)
return 1;
}
int l_load_music_async_callback(lua_State *L)
{
return 0;
}
int l_load_music_async_callback(lua_State* L) { return 0; }
#endif // CORSIX_TH_USE_SDL_MIXER

View File

@@ -21,21 +21,19 @@ SOFTWARE.
*/
#include "config.h"
#include <array>
#include <cstdio>
#include <cstring>
#include "lua_sdl.h"
#include "th_lua.h"
#include <cstring>
#include <cstdio>
#include <array>
namespace {
int l_init(lua_State *L)
{
int l_init(lua_State* L) {
Uint32 flags = 0;
int i;
int argc = lua_gettop(L);
for(i = 1; i <= argc; ++i)
{
for (i = 1; i <= argc; ++i) {
const char* s = luaL_checkstring(L, i);
if (std::strcmp(s, "video") == 0)
flags |= SDL_INIT_VIDEO;
@@ -48,8 +46,7 @@ int l_init(lua_State *L)
else
luaL_argerror(L, i, "Expected SDL part name");
}
if(SDL_Init(flags) != 0)
{
if (SDL_Init(flags) != 0) {
std::fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
lua_pushboolean(L, 0);
return 1;
@@ -59,16 +56,14 @@ int l_init(lua_State *L)
return 1;
}
Uint32 timer_frame_callback(Uint32 interval, void *param)
{
Uint32 timer_frame_callback(Uint32 interval, void* param) {
SDL_Event e;
e.type = SDL_USEREVENT_TICK;
SDL_PushEvent(&e);
return interval;
}
class fps_ctrl
{
class fps_ctrl {
public:
bool limit_fps;
bool track_fps;
@@ -76,10 +71,9 @@ public:
int q_front;
int q_back;
int frame_count;
Uint32 frame_time[4096];
std::array<Uint32, 4096> frame_time;
void init()
{
void init() {
limit_fps = true;
track_fps = true;
q_front = 0;
@@ -87,60 +81,54 @@ public:
frame_count = 0;
}
void count_frame()
{
void count_frame() {
Uint32 now = SDL_GetTicks();
frame_time[q_front] = now;
q_front = (q_front + 1) % static_cast<int>((sizeof(frame_time) / sizeof(*frame_time)));
if(q_front == q_back)
q_back = (q_back + 1) % static_cast<int>((sizeof(frame_time) / sizeof(*frame_time)));
else
q_front = (q_front + 1) % frame_time.size();
if (q_front == q_back) {
q_back = (q_back + 1) % frame_time.size();
} else {
++frame_count;
if(now < 1000)
}
if (now < 1000) {
now = 0;
else
} else {
now -= 1000;
while(frame_time[q_back] < now)
{
}
while (frame_time[q_back] < now) {
--frame_count;
q_back = (q_back + 1) % static_cast<int>((sizeof(frame_time) / sizeof(*frame_time)));
q_back = (q_back + 1) % frame_time.size();
}
}
};
void l_push_modifiers_table(lua_State *L, Uint16 mod)
{
void l_push_modifiers_table(lua_State* L, Uint16 mod) {
lua_newtable(L);
if ((mod & KMOD_SHIFT) != 0)
{
if ((mod & KMOD_SHIFT) != 0) {
luaT_pushtablebool(L, "shift", true);
}
if ((mod & KMOD_ALT) != 0)
{
if ((mod & KMOD_ALT) != 0) {
luaT_pushtablebool(L, "alt", true);
}
if ((mod & KMOD_CTRL) != 0)
{
if ((mod & KMOD_CTRL) != 0) {
luaT_pushtablebool(L, "ctrl", true);
}
if ((mod & KMOD_GUI) != 0)
{
if ((mod & KMOD_GUI) != 0) {
luaT_pushtablebool(L, "gui", true);
}
if ((mod & KMOD_NUM) != 0)
{
if ((mod & KMOD_NUM) != 0) {
luaT_pushtablebool(L, "numlockactive", true);
}
}
int l_get_key_modifiers(lua_State *L)
{
int l_get_key_modifiers(lua_State* L) {
l_push_modifiers_table(L, SDL_GetModState());
return 1;
}
int l_mainloop(lua_State *L)
{
int l_mainloop(lua_State* L) {
luaL_checktype(L, 1, LUA_TTHREAD);
lua_State* dispatcher = lua_tothread(L, 1);
@@ -148,15 +136,12 @@ int l_mainloop(lua_State *L)
SDL_TimerID timer = SDL_AddTimer(30, timer_frame_callback, nullptr);
SDL_Event e;
while(SDL_WaitEvent(&e) != 0)
{
while (SDL_WaitEvent(&e) != 0) {
bool do_frame = false;
bool do_timer = false;
do
{
do {
int nargs;
switch(e.type)
{
switch (e.type) {
case SDL_QUIT:
goto leave_loop;
case SDL_KEYDOWN:
@@ -248,8 +233,8 @@ int l_mainloop(lua_State *L)
nargs = 1;
break;
case SDL_USEREVENT_MUSIC_LOADED:
if(luaT_cpcall(L, (lua_CFunction)l_load_music_async_callback, e.user.data1))
{
if (luaT_cpcall(L, (lua_CFunction)l_load_music_async_callback,
e.user.data1)) {
SDL_RemoveTimer(timer);
lua_pushliteral(L, "callback");
return 2;
@@ -273,37 +258,29 @@ int l_mainloop(lua_State *L)
nargs = 0;
break;
}
if(nargs != 0)
{
if(luaT_resume(dispatcher, dispatcher, nargs) != LUA_YIELD)
{
if (nargs != 0) {
if (luaT_resume(dispatcher, dispatcher, nargs) != LUA_YIELD) {
goto leave_loop;
}
do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0);
lua_settop(dispatcher, 0);
}
} while (SDL_PollEvent(&e) != 0);
if(do_timer)
{
if (do_timer) {
lua_pushliteral(dispatcher, "timer");
if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD)
{
if (luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) {
break;
}
do_frame = do_frame || (lua_toboolean(dispatcher, 1) != 0);
lua_settop(dispatcher, 0);
}
if(do_frame || !fps_control->limit_fps)
{
do
{
if(fps_control->track_fps)
{
if (do_frame || !fps_control->limit_fps) {
do {
if (fps_control->track_fps) {
fps_control->count_frame();
}
lua_pushliteral(dispatcher, "frame");
if(luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD)
{
if (luaT_resume(dispatcher, dispatcher, 1) != LUA_YIELD) {
goto leave_loop;
}
lua_settop(dispatcher, 0);
@@ -317,8 +294,7 @@ int l_mainloop(lua_State *L)
leave_loop:
SDL_RemoveTimer(timer);
int n = lua_gettop(dispatcher);
if(lua_status(dispatcher) >= LUA_ERRRUN)
{
if (lua_status(dispatcher) >= LUA_ERRRUN) {
n = 1;
}
lua_checkstack(L, n);
@@ -326,57 +302,47 @@ leave_loop:
return n;
}
int l_track_fps(lua_State *L)
{
int l_track_fps(lua_State* L) {
fps_ctrl* ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1));
ctrl->track_fps = lua_isnone(L, 1) ? true : (lua_toboolean(L, 1) != 0);
return 0;
}
int l_limit_fps(lua_State *L)
{
int l_limit_fps(lua_State* L) {
fps_ctrl* ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1));
ctrl->limit_fps = lua_isnone(L, 1) ? true : (lua_toboolean(L, 1) != 0);
return 0;
}
int l_get_fps(lua_State *L)
{
int l_get_fps(lua_State* L) {
fps_ctrl* ctrl = (fps_ctrl*)lua_touserdata(L, luaT_upvalueindex(1));
if(ctrl->track_fps)
{
if (ctrl->track_fps) {
lua_pushinteger(L, ctrl->frame_count);
}
else
{
} else {
lua_pushnil(L);
}
return 1;
}
int l_get_ticks(lua_State *L)
{
int l_get_ticks(lua_State* L) {
lua_pushinteger(L, (lua_Integer)SDL_GetTicks());
return 1;
}
constexpr std::array<luaL_Reg, 4> sdllib {{
{"init", l_init},
constexpr std::array<luaL_Reg, 4> sdllib{
{{"init", l_init},
{"getTicks", l_get_ticks},
{"getKeyModifiers", l_get_key_modifiers},
{nullptr, nullptr}
}};
{nullptr, nullptr}}};
constexpr std::array<luaL_Reg, 5> sdllib_with_upvalue {{
{"mainloop", l_mainloop},
constexpr std::array<luaL_Reg, 5> sdllib_with_upvalue{
{{"mainloop", l_mainloop},
{"getFPS", l_get_fps},
{"trackFPS", l_track_fps},
{"limitFPS", l_limit_fps},
{nullptr, nullptr}
}};
{nullptr, nullptr}}};
inline void load_extra(lua_State *L, const char *name, lua_CFunction fn)
{
inline void load_extra(lua_State* L, const char* name, lua_CFunction fn) {
luaT_pushcfunction(L, fn);
lua_call(L, 0, 1);
lua_setfield(L, -2, name);
@@ -387,13 +353,11 @@ inline void load_extra(lua_State *L, const char *name, lua_CFunction fn)
int luaopen_sdl_audio(lua_State* L);
int luaopen_sdl_wm(lua_State* L);
int luaopen_sdl(lua_State *L)
{
int luaopen_sdl(lua_State* L) {
fps_ctrl* ctrl = (fps_ctrl*)lua_newuserdata(L, sizeof(fps_ctrl));
ctrl->init();
luaT_register(L, "sdl", sdllib);
for (auto reg = sdllib_with_upvalue.begin(); reg->name; ++reg)
{
for (auto reg = sdllib_with_upvalue.begin(); reg->name; ++reg) {
lua_pushvalue(L, -2);
luaT_pushcclosure(L, reg->func, 1);
lua_setfield(L, -2, reg->name);

View File

@@ -21,19 +21,18 @@ SOFTWARE.
*/
#include "config.h"
#include "th_lua.h"
#include "lua_sdl.h"
#include "th_lua.h"
#ifdef CORSIX_TH_USE_WIN32_SDK
#include <windows.h>
#include <SDL_syswm.h>
#include <windows.h>
#include "../resource.h"
#endif
#include <array>
namespace {
int l_set_icon_win32(lua_State *L)
{
int l_set_icon_win32(lua_State* L) {
// Hack to set the window icon from the EXE resource under Windows.
// Does nothing (and returns false) on other platforms.
@@ -56,22 +55,19 @@ int l_set_icon_win32(lua_State *L)
return 1;
}
int l_show_cursor(lua_State *L)
{
int l_show_cursor(lua_State* L) {
SDL_ShowCursor(lua_toboolean(L, 1));
return 0;
}
constexpr std::array<struct luaL_Reg, 3> sdl_wmlib {{
{"setIconWin32", l_set_icon_win32},
constexpr std::array<struct luaL_Reg, 3> sdl_wmlib{
{{"setIconWin32", l_set_icon_win32},
{"showCursor", l_show_cursor},
{nullptr, nullptr}
}};
{nullptr, nullptr}}};
} // namespace
int luaopen_sdl_wm(lua_State *L)
{
int luaopen_sdl_wm(lua_State* L) {
lua_newtable(L);
luaT_setfuncs(L, sdl_wmlib.data());

View File

@@ -20,31 +20,24 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "th.h"
#include "config.h"
#include <cstring>
#include <stdexcept>
link_list::link_list()
{
link_list::link_list() {
drawing_layer = 0;
prev = nullptr;
next = nullptr;
}
link_list::~link_list()
{
remove_from_list();
}
link_list::~link_list() { remove_from_list(); }
void link_list::remove_from_list()
{
if(prev != nullptr)
{
void link_list::remove_from_list() {
if (prev != nullptr) {
prev->next = next;
}
if(next != nullptr)
{
if (next != nullptr) {
next->prev = prev;
next = nullptr;
}
@@ -56,23 +49,17 @@ void link_list::remove_from_list()
namespace {
void utf8encode(uint8_t*& sOut, uint32_t iCodepoint)
{
if(iCodepoint <= 0x7F)
{
void utf8encode(uint8_t*& sOut, uint32_t iCodepoint) {
if (iCodepoint <= 0x7F) {
*sOut = static_cast<char>(iCodepoint);
++sOut;
}
else if(iCodepoint <= 0x7FF)
{
} else if (iCodepoint <= 0x7FF) {
uint8_t cSextet = iCodepoint & 0x3F;
iCodepoint >>= 6;
sOut[0] = static_cast<uint8_t>(0xC0 + iCodepoint);
sOut[1] = static_cast<uint8_t>(0x80 + cSextet);
sOut += 2;
}
else if(iCodepoint <= 0xFFFF)
{
} else if (iCodepoint <= 0xFFFF) {
uint8_t cSextet2 = iCodepoint & 0x3F;
iCodepoint >>= 6;
uint8_t cSextet1 = iCodepoint & 0x3F;
@@ -81,9 +68,7 @@ void utf8encode(uint8_t*& sOut, uint32_t iCodepoint)
sOut[1] = static_cast<uint8_t>(0x80 + cSextet1);
sOut[2] = static_cast<uint8_t>(0x80 + cSextet2);
sOut += 3;
}
else
{
} else {
uint8_t cSextet3 = iCodepoint & 0x3F;
iCodepoint >>= 6;
uint8_t cSextet2 = iCodepoint & 0x3F;
@@ -98,52 +83,38 @@ void utf8encode(uint8_t*& sOut, uint32_t iCodepoint)
}
}
void CopyStringCP437(const uint8_t*& sIn, uint8_t*& sOut)
{
void CopyStringCP437(const uint8_t*& sIn, uint8_t*& sOut) {
uint8_t cChar;
do
{
do {
cChar = *sIn;
++sIn;
if(cChar < 0x80)
{
if (cChar < 0x80) {
*sOut = cChar;
++sOut;
}
else
{
} else {
utf8encode(sOut, cp437_to_unicode_table[cChar - 0x80]);
}
} while (cChar != 0);
}
void CopyStringCP936(const uint8_t*& sIn, uint8_t*& sOut)
{
void CopyStringCP936(const uint8_t*& sIn, uint8_t*& sOut) {
uint8_t cChar1, cChar2;
do
{
do {
cChar1 = *sIn;
++sIn;
if(cChar1 < 0x81 || cChar1 == 0xFF)
{
if (cChar1 < 0x81 || cChar1 == 0xFF) {
*sOut = cChar1;
++sOut;
}
else
{
} else {
cChar2 = *sIn;
++sIn;
if(0x40 <= cChar2 && cChar2 <= 0xFE)
{
if (0x40 <= cChar2 && cChar2 <= 0xFE) {
utf8encode(sOut, cp936_to_unicode_table[cChar1 - 0x81][cChar2 - 0x40]);
// The Theme Hospital string tables seem to like following a
// multibyte character with a superfluous space.
cChar2 = *sIn;
if(cChar2 == ' ')
++sIn;
}
else
{
if (cChar2 == ' ') ++sIn;
} else {
*sOut = cChar1;
++sOut;
*sOut = cChar2;
@@ -155,10 +126,8 @@ void CopyStringCP936(const uint8_t*& sIn, uint8_t*& sOut)
} // namespace
th_string_list::th_string_list(const uint8_t* data, size_t length)
{
if(length < 2)
throw std::invalid_argument("length must be 2 or larger");
th_string_list::th_string_list(const uint8_t* data, size_t length) {
if (length < 2) throw std::invalid_argument("length must be 2 or larger");
size_t iSectionCount = *reinterpret_cast<const uint16_t*>(data);
size_t iHeaderLength = (iSectionCount + 1) * 2;
@@ -175,10 +144,8 @@ th_string_list::th_string_list(const uint8_t* data, size_t length)
// which shouldn't occur much (if ever) in TH strings, whereas they are
// commonly used in GB2312 encoding. We use 10% as a threshold.
size_t iBCDCount = 0;
for(size_t i = 0; i < iStringDataLength; ++i)
{
if(0xB0 <= sStringData[i] && sStringData[i] <= 0xDF)
++iBCDCount;
for (size_t i = 0; i < iStringDataLength; ++i) {
if (0xB0 <= sStringData[i] && sStringData[i] <= 0xDF) ++iBCDCount;
}
void (*fnCopyString)(const uint8_t*&, uint8_t*&);
if (iBCDCount * 10 >= iStringDataLength)
@@ -192,15 +159,12 @@ th_string_list::th_string_list(const uint8_t* data, size_t length)
uint8_t* sDataOut = string_buffer.data();
sections.resize(iSectionCount);
for(size_t i = 0; i < iSectionCount; ++i)
{
for (size_t i = 0; i < iSectionCount; ++i) {
size_t section_size = reinterpret_cast<const uint16_t*>(data)[i + 1];
sections[i].reserve(section_size);
for(size_t j = 0; j < section_size; ++j)
{
for (size_t j = 0; j < section_size; ++j) {
sections[i].push_back(reinterpret_cast<char*>(sDataOut));
if(sStringData != sDataEnd)
{
if (sStringData != sDataEnd) {
fnCopyString(sStringData, sDataOut);
}
}
@@ -209,23 +173,16 @@ th_string_list::th_string_list(const uint8_t* data, size_t length)
*sDataOut = 0;
}
th_string_list::~th_string_list()
{}
th_string_list::~th_string_list() {}
size_t th_string_list::get_section_count()
{
return sections.size();
}
size_t th_string_list::get_section_count() { return sections.size(); }
size_t th_string_list::get_section_size(size_t section)
{
size_t th_string_list::get_section_size(size_t section) {
return section < sections.size() ? sections[section].size() : 0;
}
const char* th_string_list::get_string(size_t section, size_t index)
{
if(index < get_section_size(section))
{
const char* th_string_list::get_string(size_t section, size_t index) {
if (index < get_section_size(section)) {
return sections[section][index];
}
return nullptr;

View File

@@ -26,8 +26,7 @@ SOFTWARE.
#include <vector>
//! Generic linked list class (for inheriting from)
class link_list
{
class link_list {
public:
link_list();
~link_list();
@@ -48,8 +47,7 @@ private:
//! \brief Theme Hospital localised string list
//!
//! Presents Theme Hospital strings by section and index.
class th_string_list
{
class th_string_list {
public:
//! Construct an instance of string_list from the given data
//! from a Theme Hosptial string file. The format of the data is
@@ -80,7 +78,8 @@ public:
/*!
@param section Section index in range [0, getSectionCount() - 1]
@param index String index in range [0, getSectionSize(iSection) - 1]
@return nullptr if the index is invalid, otherwise a UTF-8 encoded string.
@return nullptr if the index is invalid, otherwise a UTF-8 encoded
string.
*/
const char* get_string(size_t section, size_t index);
@@ -99,8 +98,7 @@ private:
* @param bytes A pointer to the first of 4 sequential bytes in memory making
* up the uint32.
*/
inline uint32_t bytes_to_uint32_le(const uint8_t* bytes)
{
inline uint32_t bytes_to_uint32_le(const uint8_t* bytes) {
uint32_t res = bytes[3];
res <<= 8;
res |= bytes[2];
@@ -119,8 +117,7 @@ inline uint32_t bytes_to_uint32_le(const uint8_t* bytes)
* @param bytes A pointer to the first of 2 sequential bytes in memory making
* up the uint16.
*/
inline uint16_t bytes_to_uint16_le(const uint8_t* bytes)
{
inline uint16_t bytes_to_uint16_le(const uint8_t* bytes) {
uint16_t res = bytes[1];
res <<= 8;
res |= bytes[0];

File diff suppressed because it is too large Load Diff

View File

@@ -22,29 +22,21 @@ SOFTWARE.
#ifndef CORSIX_TH_TH_GFX_H_
#define CORSIX_TH_TH_GFX_H_
#include <map>
#include <string>
#include <vector>
#include "th.h"
#include "th_gfx_sdl.h"
class lua_persist_reader;
class lua_persist_writer;
enum class scaled_items {
none,
sprite_sheets,
bitmaps,
all
};
#include "th_gfx_sdl.h"
#include "th_gfx_font.h"
#include <vector>
#include <map>
#include <string>
enum class scaled_items { none, sprite_sheets, bitmaps, all };
void clip_rect_intersection(clip_rect& rcClip, const clip_rect& rcIntersect);
//! Bitflags for drawing operations
enum draw_flags : uint32_t
{
enum draw_flags : uint32_t {
/** Sprite drawing flags **/
/* Where possible, designed to be the same values used by TH data files */
@@ -88,13 +80,13 @@ enum draw_flags : uint32_t
};
/** Helper structure with parameters to create a #render_target. */
struct render_target_creation_params
{
struct render_target_creation_params {
int width; ///< Expected width of the render target.
int height; ///< Expected height of the render target.
int bpp; ///< Expected colour depth of the render target.
bool fullscreen; ///< Run full-screen.
bool present_immediate; ///< Whether to present immediately to the user (else wait for Vsync).
bool present_immediate; ///< Whether to present immediately to the user
///< (else wait for Vsync).
};
/*!
@@ -103,20 +95,21 @@ struct render_target_creation_params
game objects (though they are the most common thing in drawing lists).
*/
// TODO: Replace this struct with something cleaner
struct drawable : public link_list
{
struct drawable : public link_list {
//! Draw the object at a specific point on a render target
/*!
Can also "draw" the object to the speakers, i.e. play sounds.
*/
void (*draw_fn)(drawable* pSelf, render_target* pCanvas, int iDestX, int iDestY);
void (*draw_fn)(drawable* pSelf, render_target* pCanvas, int iDestX,
int iDestY);
//! Perform a hit test against the object
/*!
Should return true if when the object is drawn at (iDestX, iDestY) on a canvas,
the point (iTestX, iTestY) is within / on the object.
Should return true if when the object is drawn at (iDestX, iDestY) on a
canvas, the point (iTestX, iTestY) is within / on the object.
*/
bool (*hit_test_fn)(drawable* pSelf, int iDestX, int iDestY, int iTestX, int iTestY);
bool (*hit_test_fn)(drawable* pSelf, int iDestX, int iDestY, int iTestX,
int iTestY);
//! Drawing flags (zero or more list flags from #draw_flags).
uint32_t flags;
@@ -131,15 +124,14 @@ struct drawable : public link_list
Utility class for decoding Theme Hospital "chunked" graphics files.
Generally used internally by sprite_sheet.
*/
class chunk_renderer
{
class chunk_renderer {
public:
//! Initialise a renderer for a specific size result
/*!
@param width Pixel width of the resulting image
@param height Pixel height of the resulting image
@param buffer If nullptr, then a new buffer is created to render the image
onto. Otherwise, should be an array at least width*height in size.
@param buffer If nullptr, then a new buffer is created to render the
image onto. Otherwise, should be an array at least width*height in size.
Ownership of this pointer is assumed by the class - call takeData()
to take ownership back again.
*/
@@ -194,16 +186,14 @@ private:
};
//! Layer information (see animation_manager::draw_frame)
struct layers
{
struct layers {
uint8_t layer_contents[13];
};
class memory_reader;
/** Key value for finding an animation. */
struct animation_key
{
struct animation_key {
std::string name; ///< Name of the animations.
int tile_size; ///< Size of a tile.
};
@@ -214,8 +204,7 @@ struct animation_key
@param oL Second key value.
@return Whether \a oK should be before \a oL.
*/
inline bool operator<(const animation_key &oK, const animation_key &oL)
{
inline bool operator<(const animation_key& oK, const animation_key& oL) {
if (oK.tile_size != oL.tile_size) return oK.tile_size < oL.tile_size;
return oK.name < oL.name;
}
@@ -224,8 +213,7 @@ inline bool operator<(const animation_key &oK, const animation_key &oL)
* Start frames of an animation, in each view direction.
* A negative number indicates there is no animation in that direction.
*/
struct animation_start_frames
{
struct animation_start_frames {
long north; ///< Animation start frame for the 'north' view.
long east; ///< Animation start frame for the 'east' view.
long south; ///< Animation start frame for the 'south' view.
@@ -244,8 +232,7 @@ typedef std::pair<animation_key, animation_start_frames> named_animation_pair;
files, and uses them to draw animation frames and provide information about
the animations.
*/
class animation_manager
{
class animation_manager {
public:
animation_manager();
~animation_manager();
@@ -268,7 +255,8 @@ public:
bool load_from_th_file(const uint8_t* pStartData, size_t iStartDataLength,
const uint8_t* pFrameData, size_t iFrameDataLength,
const uint8_t* pListData, size_t iListDataLength,
const uint8_t* pElementData, size_t iElementDataLength);
const uint8_t* pElementData,
size_t iElementDataLength);
//! Set the video target.
/*!
@@ -296,8 +284,9 @@ public:
//! Get the index of the frame after a given frame
/*!
To draw an animation frame by frame, call get_first_frame() to get the
index of the first frame, and then keep on calling get_next_frame() using
the most recent return value from get_next_frame() or get_first_frame().
index of the first frame, and then keep on calling get_next_frame()
using the most recent return value from get_next_frame() or
get_first_frame().
*/
size_t get_next_frame(size_t iFrame) const;
@@ -309,12 +298,14 @@ public:
new palette indices by the 256 byte array pMap. This is typically used
to draw things in different colours or in greyscale.
*/
void set_animation_alt_palette_map(size_t iAnimation, const uint8_t* pMap, uint32_t iAlt32);
void set_animation_alt_palette_map(size_t iAnimation, const uint8_t* pMap,
uint32_t iAlt32);
//! Draw an animation frame
/*!
@param pCanvas The render target to draw onto.
@param iFrame The frame index to draw (should be in range [0, getFrameCount() - 1])
@param iFrame The frame index to draw (should be in range [0,
getFrameCount() - 1])
@param oLayers Information to decide what to draw on each layer.
An animation is comprised of up to thirteen layers, numbered 0
through 12. Some animations will have different options for what to
@@ -330,16 +321,16 @@ public:
@param iFlags Zero or more THDrawFlags flags.
*/
void draw_frame(render_target* pCanvas, size_t iFrame,
const ::layers& oLayers,
int iX, int iY, uint32_t iFlags) const;
const ::layers& oLayers, int iX, int iY,
uint32_t iFlags) const;
void get_frame_extent(size_t iFrame, const ::layers& oLayers,
int* pMinX, int* pMaxX, int* pMinY, int* pMaxY,
void get_frame_extent(size_t iFrame, const ::layers& oLayers, int* pMinX,
int* pMaxX, int* pMinY, int* pMaxY,
uint32_t iFlags) const;
size_t get_frame_sound(size_t iFrame);
bool hit_test(size_t iFrame, const ::layers& oLayers,
int iX, int iY, uint32_t iFlags, int iTestX, int iTestY) const;
bool hit_test(size_t iFrame, const ::layers& oLayers, int iX, int iY,
uint32_t iFlags, int iTestX, int iTestY) const;
bool set_frame_marker(size_t iFrame, int iX, int iY);
bool set_frame_secondary_marker(size_t iFrame, int iX, int iY);
@@ -352,7 +343,8 @@ public:
@param iTilesize Tile size of the animation.
@return A set starting frames for the queried animation.
*/
const animation_start_frames &get_named_animations(const std::string &sName, int iTilesize) const;
const animation_start_frames& get_named_animations(const std::string& sName,
int iTilesize) const;
private:
#if CORSIX_TH_USE_PACK_PRAGMAS
@@ -360,8 +352,7 @@ private:
#pragma pack(1)
#endif
// Animation information structure reinterpreted from Theme Hospital data.
struct th_animation_properties
{
struct th_animation_properties {
uint16_t first_frame;
// It could be that frame is a uint32_t rather than a uint16_t, which
// would resolve the following unknown (which seems to always be zero).
@@ -369,8 +360,7 @@ private:
} CORSIX_TH_PACKED_FLAGS;
// Frame information structure reinterpreted from Theme Hospital data.
struct th_frame_properties
{
struct th_frame_properties {
uint32_t list_index;
// These fields have something to do with width and height, but it's
// not clear quite exactly how.
@@ -384,8 +374,7 @@ private:
} CORSIX_TH_PACKED_FLAGS;
// Structure reinterpreted from Theme Hospital data.
struct th_element_properties
{
struct th_element_properties {
uint16_t table_position;
uint8_t offx;
uint8_t offy;
@@ -399,31 +388,36 @@ private:
#pragma pack(pop)
#endif
struct frame
{
size_t list_index; ///< First entry in #element_list (pointing to an element) for this frame.
struct frame {
size_t list_index; ///< First entry in #element_list (pointing to an
///< element) for this frame.
size_t next_frame; ///< Number of the next frame.
unsigned int sound; ///< Sound to play, if non-zero.
unsigned int flags; ///< Flags of the frame. Bit 0=start of animation.
// Bounding rectangle is with all layers / options enabled - used as a
// quick test prior to a full pixel perfect test.
int bounding_left; ///< Left edge of the bounding rectangle of this frame.
int bounding_right; ///< Right edge of the bounding rectangle of this frame.
int bounding_top; ///< Top edge of the bounding rectangle of this frame.
int bounding_bottom; ///< Bottom edge of the bounding rectangle of this frame.
int bounding_left; ///< Left edge of the bounding rectangle of this
///< frame.
int bounding_right; ///< Right edge of the bounding rectangle of this
///< frame.
int bounding_top; ///< Top edge of the bounding rectangle of this
///< frame.
int bounding_bottom; ///< Bottom edge of the bounding rectangle of this
///< frame.
// Markers are used to know where humanoids are on an frame. The
// positions are pixels offsets from the centre of the frame's base
// tile to the centre of the humanoid's feet.
int marker_x; ///< X position of the first center of a humanoids feet.
int marker_y; ///< Y position of the first center of a humanoids feet.
int secondary_marker_x; ///< X position of the second center of a humanoids feet.
int secondary_marker_y; ///< Y position of the second center of a humanoids feet.
int secondary_marker_x; ///< X position of the second center of a
///< humanoids feet.
int secondary_marker_y; ///< Y position of the second center of a
///< humanoids feet.
};
struct element
{
struct element {
size_t sprite; ///< Sprite number of the sprite sheet to display.
uint32_t flags; ///< Flags of the sprite.
///< bit 0=flip vertically, bit 1=flip horizontally,
@@ -433,14 +427,16 @@ private:
uint8_t layer; ///< Layer class (0..12).
uint8_t layer_id; ///< Value of the layer class to match.
sprite_sheet *element_sprite_sheet; ///< Sprite sheet to use for this element.
sprite_sheet* element_sprite_sheet; ///< Sprite sheet to use for this
///< element.
};
std::vector<size_t> first_frames; ///< First frame number of an animation.
std::vector<frame> frames; ///< The loaded frames.
std::vector<uint16_t> element_list; ///< List of elements for a frame.
std::vector<element> elements; ///< Sprite Elements.
std::vector<sprite_sheet *> custom_sheets; ///< Sprite sheets with custom graphics.
std::vector<sprite_sheet*>
custom_sheets; ///< Sprite sheets with custom graphics.
named_animations_map named_animations; ///< Collected named animations.
sprite_sheet* sheet; ///< Sprite sheet to use.
@@ -465,7 +461,8 @@ private:
@param [inout] iLoadedElements Number of loaded elements so far.
@param iElementStart Offset of the first element.
@param iElementCount Number of elements to load.
@return Index of the first loaded element in #elements. Negative value means failure.
@return Index of the first loaded element in #elements. Negative value
means failure.
*/
size_t load_elements(memory_reader& input, sprite_sheet* pSpriteSheet,
size_t iNumElements, size_t& iLoadedElements,
@@ -475,16 +472,19 @@ private:
/*!
@param iFirstElement Index of the first element in #elements.
@param iNumElements Number of elements to add.
@param [inout] iLoadedListElements Number of created list elements so far.
@param [inout] iLoadedListElements Number of created list elements so
far.
@param iListStart Offset of the first created list element.
@param iListCount Expected number of list elements to create.
@return Index of the list elements, or a negative value to indicate failure.
@return Index of the list elements, or a negative value to indicate
failure.
*/
size_t make_list_elements(size_t iFirstElement, size_t iNumElements,
size_t &iLoadedListElements,
size_t iListStart, size_t iListCount);
size_t& iLoadedListElements, size_t iListStart,
size_t iListCount);
//! Fix the flags of the first frame, and set the next frame of the last frame back to the first frame.
//! Fix the flags of the first frame, and set the next frame of the last
//! frame back to the first frame.
/*!
@param iFirst First frame of the animation, or 0xFFFFFFFFu.
@param iLength Number of frames in the animation.
@@ -493,8 +493,7 @@ private:
};
struct map_tile;
class animation_base : public drawable
{
class animation_base : public drawable {
public:
animation_base();
@@ -506,7 +505,9 @@ public:
int get_y() const { return y_relative_to_tile; }
void set_flags(uint32_t iFlags) { flags = iFlags; }
void set_position(int iX, int iY) {x_relative_to_tile = iX, y_relative_to_tile = iY;}
void set_position(int iX, int iY) {
x_relative_to_tile = iX, y_relative_to_tile = iY;
}
void set_layer(int iLayer, int iId);
void set_layers_from(const animation_base* pSrc) { layers = pSrc->layers; }
@@ -520,8 +521,14 @@ protected:
::layers layers;
};
class animation : public animation_base
{
struct xy_diff {
//! Amount to change x per tick
int dx;
//! Amount to change y per tick
int dy;
};
class animation : public animation_base {
public:
animation();
@@ -543,7 +550,8 @@ public:
int get_crop_column() const { return crop_column; }
void set_animation(animation_manager* pManager, size_t iAnimation);
void set_morph_target(animation *pMorphTarget, unsigned int iDurationFactor = 1);
void set_morph_target(animation* pMorphTarget,
unsigned int iDurationFactor = 1);
void set_frame(size_t iFrame);
void set_speed(int iX, int iY) { speed.dx = iX, speed.dy = iY; }
@@ -553,18 +561,14 @@ public:
void depersist(lua_persist_reader* pReader);
animation_manager* get_animation_manager() { return manager; }
private:
animation_manager* manager;
animation* morph_target;
size_t animation_index; ///< Animation number.
size_t frame_index; ///< Frame number.
union {
struct {
//! Amount to change x per tick
int dx;
//! Amount to change y per tick
int dy;
} speed;
xy_diff speed;
//! Some animations are tied to the marker of another animation and
//! hence have a parent rather than a speed.
animation* parent;
@@ -574,8 +578,7 @@ private:
int crop_column;
};
class sprite_render_list : public animation_base
{
class sprite_render_list : public animation_base {
public:
sprite_render_list();
~sprite_render_list();
@@ -594,8 +597,7 @@ public:
void depersist(lua_persist_reader* pReader);
private:
struct sprite
{
struct sprite {
size_t index;
int x;
int y;

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,10 @@ SOFTWARE.
#include FT_FREETYPE_H
#endif
class render_target;
class sprite_sheet;
enum class text_alignment {
left = 0,
center = 1,
@@ -35,8 +39,7 @@ enum class text_alignment {
};
/** Structure for the bounds of a text string that is rendered to the screen. */
struct text_layout
{
struct text_layout {
//! Number of rows the rendered text spans
int row_count;
@@ -56,8 +59,7 @@ struct text_layout
int width;
};
class font
{
class font {
public:
virtual ~font() = default;
@@ -72,7 +74,8 @@ public:
@param iMaxWidth The maximum length, in pixels, that the text may
occupy. Default is INT_MAX.
*/
virtual text_layout get_text_dimensions(const char* sMessage, size_t iMessageLength,
virtual text_layout get_text_dimensions(const char* sMessage,
size_t iMessageLength,
int iMaxWidth = INT_MAX) const = 0;
//! Draw a single line of text
@@ -93,11 +96,11 @@ public:
//! Draw a single line of text, splitting it at word boundaries
/*!
This function still only draws a single line of text (i.e. any line
breaks like `\r` and `\n` in sMessage are ignored), but inserts line breaks
between words so that no single line is wider than iWidth pixels.
breaks like `\r` and `\n` in sMessage are ignored), but inserts line
breaks between words so that no single line is wider than iWidth pixels.
If iMaxRows is specified it will simply cut after that many rows.
@param pCanvas The canvas on which to draw. Can be nullptr, in which case
nothing is drawn, but other calculations are still made.
@param pCanvas The canvas on which to draw. Can be nullptr, in which
case nothing is drawn, but other calculations are still made.
@param sMessage The line of text to draw, encoded in CP437.
@param iMessageLength The length (in bytes) of sMessage.
@param iX The X position to start drawing on the canvas.
@@ -108,14 +111,13 @@ public:
@param eAlign How to align each line of text if the width of the line
of text is smaller than iWidth.
*/
virtual text_layout draw_text_wrapped(render_target* pCanvas, const char* sMessage,
size_t iMessageLength, int iX, int iY,
int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0,
virtual text_layout draw_text_wrapped(
render_target* pCanvas, const char* sMessage, size_t iMessageLength,
int iX, int iY, int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0,
text_alignment eAlign = text_alignment::left) const = 0;
};
class bitmap_font final : public font
{
class bitmap_font final : public font {
public:
bitmap_font();
@@ -142,9 +144,9 @@ public:
void draw_text(render_target* pCanvas, const char* sMessage,
size_t iMessageLength, int iX, int iY) const override;
text_layout draw_text_wrapped(render_target* pCanvas, const char* sMessage,
size_t iMessageLength, int iX, int iY,
int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0,
text_layout draw_text_wrapped(
render_target* pCanvas, const char* sMessage, size_t iMessageLength,
int iX, int iY, int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0,
text_alignment eAlign = text_alignment::left) const override;
private:
@@ -167,8 +169,7 @@ private:
THRawBitmap class, but with an alpha channel, and a single colour rather
than a palette).
*/
class freetype_font final : public font
{
class freetype_font final : public font {
public:
freetype_font();
~freetype_font();
@@ -222,14 +223,13 @@ public:
void draw_text(render_target* pCanvas, const char* sMessage,
size_t iMessageLength, int iX, int iY) const override;
text_layout draw_text_wrapped(render_target* pCanvas, const char* sMessage,
size_t iMessageLength, int iX, int iY,
int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0,
text_layout draw_text_wrapped(
render_target* pCanvas, const char* sMessage, size_t iMessageLength,
int iX, int iY, int iWidth, int iMaxRows = INT_MAX, int iSkipRows = 0,
text_alignment eAlign = text_alignment::left) const override;
private:
struct cached_text
{
struct cached_text {
//! The text being converted to pixels
char* message;
@@ -268,10 +268,12 @@ private:
};
//! Render a FreeType2 monochrome bitmap to a cache canvas.
void render_mono(cached_text *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const;
void render_mono(cached_text* pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x,
FT_Pos y) const;
//! Render a FreeType2 grayscale bitmap to a cache canvas.
void render_gray(cached_text *pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x, FT_Pos y) const;
void render_gray(cached_text* pCacheEntry, FT_Bitmap* pBitmap, FT_Pos x,
FT_Pos y) const;
static FT_Library freetype_library;
static int freetype_init_count;
@@ -300,7 +302,8 @@ private:
an object which can be used by the rendering engine, and store the
result in the pTexture or iTexture field.
*/
void make_texture(render_target *pEventualCanvas, cached_text* pCacheEntry) const;
void make_texture(render_target* pEventualCanvas,
cached_text* pCacheEntry) const;
//! Free a previously-made texture of a cache entry.
/*!
@@ -320,8 +323,8 @@ private:
@param iX The X position at which to draw the texture on the canvas.
@param iY The Y position at which to draw the texture on the canvas.
*/
void draw_texture(render_target* pCanvas, cached_text* pCacheEntry,
int iX, int iY) const;
void draw_texture(render_target* pCanvas, cached_text* pCacheEntry, int iX,
int iY) const;
};
#endif // CORSIX_TH_USE_FREETYPE2

File diff suppressed because it is too large Load Diff

View File

@@ -25,22 +25,25 @@ SOFTWARE.
#include "config.h"
#include <SDL.h>
#include "persist_lua.h"
#include <stdexcept>
#include "persist_lua.h"
class cursor;
struct clip_rect : public SDL_Rect {
typedef Sint16 x_y_type;
typedef Uint16 w_h_type;
};
struct render_target_creation_params;
enum class scaled_items;
//! 32bpp ARGB colour. See #palette::pack_argb
typedef uint32_t argb_colour;
//! 8bpp palette class.
class palette
{
class palette {
public: // External API
palette();
@@ -65,7 +68,6 @@ public: // External API
bool set_entry(int iEntry, uint8_t iR, uint8_t iG, uint8_t iB);
public: // Internal (this rendering engine only) API
//! Convert A, R, G, B values to a 32bpp colour.
/*!
@param iA Amount of opacity (0-255).
@@ -74,8 +76,8 @@ public: // Internal (this rendering engine only) API
@param iB Amount of blue (0-255).
@return 32bpp value representing the provided colour values.
*/
static constexpr argb_colour pack_argb(uint8_t iA, uint8_t iR, uint8_t iG, uint8_t iB)
{
static constexpr argb_colour pack_argb(uint8_t iA, uint8_t iR, uint8_t iG,
uint8_t iB) {
return (static_cast<argb_colour>(iR) << 0) |
(static_cast<argb_colour>(iG) << 8) |
(static_cast<argb_colour>(iB) << 16) |
@@ -87,8 +89,7 @@ public: // Internal (this rendering engine only) API
@param iColour Colour to examine.
@return The red component intensity of the colour.
*/
static constexpr uint8_t get_red(argb_colour iColour)
{
static constexpr uint8_t get_red(argb_colour iColour) {
return static_cast<uint8_t>((iColour >> 0) & 0xFF);
}
@@ -97,8 +98,7 @@ public: // Internal (this rendering engine only) API
@param iColour Colour to examine.
@return The green component intensity of the colour.
*/
static constexpr uint8_t get_green(argb_colour iColour)
{
static constexpr uint8_t get_green(argb_colour iColour) {
return static_cast<uint8_t>((iColour >> 8) & 0xFF);
}
@@ -107,8 +107,7 @@ public: // Internal (this rendering engine only) API
@param iColour Colour to examine.
@return The blue component intensity of the colour.
*/
static constexpr uint8_t get_blue(argb_colour iColour)
{
static constexpr uint8_t get_blue(argb_colour iColour) {
return static_cast<uint8_t>((iColour >> 16) & 0xFF);
}
@@ -117,8 +116,7 @@ public: // Internal (this rendering engine only) API
@param iColour Colour to examine.
@return The opacity of the colour.
*/
static constexpr uint8_t get_alpha(argb_colour iColour)
{
static constexpr uint8_t get_alpha(argb_colour iColour) {
return static_cast<uint8_t>((iColour >> 24) & 0xFF);
}
@@ -139,8 +137,7 @@ public: // Internal (this rendering engine only) API
@param iEntry Entry to modify.
@param iVal Palette value to set.
*/
inline void set_argb(int iEntry, uint32_t iVal)
{
inline void set_argb(int iEntry, uint32_t iVal) {
colour_index_to_argb_map[iEntry] = iVal;
}
@@ -155,8 +152,7 @@ private:
/*!
Utility class for decoding 32bpp images.
*/
class full_colour_renderer
{
class full_colour_renderer {
public:
//! Initialize the renderer for a specific render.
/*!
@@ -173,7 +169,8 @@ public:
@param iSpriteFlags Flags how to render the sprite.
@return Decoding was successful.
*/
void decode_image(const uint8_t* pImg, const ::palette *pPalette, uint32_t iSpriteFlags);
void decode_image(const uint8_t* pImg, const ::palette* pPalette,
uint32_t iSpriteFlags);
private:
//! Store a decoded pixel. Use x and y if necessary.
@@ -191,27 +188,21 @@ private:
/*!
@param iValue Pixel value to store.
*/
inline void push_pixel(uint32_t iValue)
{
if (y < height)
{
inline void push_pixel(uint32_t iValue) {
if (y < height) {
store_argb(iValue);
x++;
if (x >= width)
{
if (x >= width) {
x = 0;
y++;
}
}
else
{
} else {
throw std::logic_error("Attempt to push_pixel past the end of the image");
}
}
};
class full_colour_storing : public full_colour_renderer
{
class full_colour_storing : public full_colour_renderer {
public:
full_colour_storing(uint32_t* pDest, int iWidth, int iHeight);
@@ -222,8 +213,7 @@ private:
uint32_t* destination;
};
class wx_storing : public full_colour_renderer
{
class wx_storing : public full_colour_renderer {
public:
wx_storing(uint8_t* pRGBData, uint8_t* pAData, int iWidth, int iHeight);
@@ -237,15 +227,13 @@ private:
uint8_t* alpha_data;
};
class render_target
{
class render_target {
public: // External API
render_target();
~render_target();
//! Encode an RGB triplet for fillRect()
static constexpr uint32_t map_colour(uint8_t iR, uint8_t iG, uint8_t iB)
{
static constexpr uint32_t map_colour(uint8_t iR, uint8_t iG, uint8_t iB) {
return palette::pack_argb(0xFF, iR, iG, iB);
}
@@ -336,10 +324,14 @@ public: // Internal (this rendering engine only) API
*/
bool should_scale_bitmaps(double* pFactor);
SDL_Texture* create_palettized_texture(int iWidth, int iHeight, const uint8_t* pPixels,
const ::palette* pPalette, uint32_t iSpriteFlags) const;
SDL_Texture* create_texture(int iWidth, int iHeight, const uint32_t* pPixels) const;
void draw(SDL_Texture *pTexture, const SDL_Rect *prcSrcRect, const SDL_Rect *prcDstRect, int iFlags);
SDL_Texture* create_palettized_texture(int iWidth, int iHeight,
const uint8_t* pPixels,
const ::palette* pPalette,
uint32_t iSpriteFlags) const;
SDL_Texture* create_texture(int iWidth, int iHeight,
const uint32_t* pPixels) const;
void draw(SDL_Texture* pTexture, const SDL_Rect* prcSrcRect,
const SDL_Rect* prcDstRect, int iFlags);
void draw_line(line* pLine, int iX, int iY);
private:
@@ -366,8 +358,7 @@ private:
};
//! Stored image.
class raw_bitmap
{
class raw_bitmap {
public:
raw_bitmap();
~raw_bitmap();
@@ -429,8 +420,7 @@ private:
};
//! Sheet of sprites.
class sprite_sheet
{
class sprite_sheet {
public: // External API
sprite_sheet();
~sprite_sheet();
@@ -441,9 +431,11 @@ public: // External API
*/
void set_palette(const ::palette* pPalette);
//! Load the sprites from the supplied data (using the palette supplied earlier).
//! Load the sprites from the supplied data (using the palette supplied
//! earlier).
/*!
@param pTableData Start of table data with TH sprite information (see th_sprite_properties).
@param pTableData Start of table data with TH sprite information (see
th_sprite_properties).
@param iTableDataLength Length of the table data.
@param pChunkData Start of image data (chunks).
@param iChunkDataLength Length of the chunk data.
@@ -459,7 +451,8 @@ public: // External API
/*!
@param iSprite Number of the sprite to set.
@param pData Data of the sprite.
@param bTakeData Whether the data block may be taken (must be new[] then).
@param bTakeData Whether the data block may be taken (must be new[]
then).
@param iDataLength Length of the data.
@param iWidth Width of the sprite.
@param iHeight Height of the sprite.
@@ -474,7 +467,8 @@ public: // External API
@param pMap The palette map to apply.
@param iAlt32 What to do for a 32bpp sprite (#thdf_alt32_mask bits).
*/
void set_sprite_alt_palette_map(size_t iSprite, const uint8_t* pMap, uint32_t iAlt32);
void set_sprite_alt_palette_map(size_t iSprite, const uint8_t* pMap,
uint32_t iAlt32);
//! Get the number of sprites at the sheet.
/*!
@@ -493,11 +487,14 @@ public: // External API
//! Get size of a sprite.
/*!
@param iSprite Sprite to get info from.
@param pWidth [out] If not nullptr, the sprite width is stored in the destination.
@param pHeight [out] If not nullptr, the sprite height is stored in the destination.
@param pWidth [out] If not nullptr, the sprite width is stored in the
destination.
@param pHeight [out] If not nullptr, the sprite height is stored in the
destination.
@return Size could be provided for the sprite.
*/
bool get_sprite_size(size_t iSprite, unsigned int* pWidth, unsigned int* pHeight) const;
bool get_sprite_size(size_t iSprite, unsigned int* pWidth,
unsigned int* pHeight) const;
//! Get size of a sprite, assuming all input is correctly supplied.
/*!
@@ -505,7 +502,8 @@ public: // External API
@param pWidth [out] The sprite width is stored in the destination.
@param pHeight [out] The sprite height is stored in the destination.
*/
void get_sprite_size_unchecked(size_t iSprite, unsigned int* pWidth, unsigned int* pHeight) const;
void get_sprite_size_unchecked(size_t iSprite, unsigned int* pWidth,
unsigned int* pHeight) const;
//! Get the best colour to represent the sprite.
/*!
@@ -523,13 +521,16 @@ public: // External API
@param iY Y position to draw the sprite.
@param iFlags Flags to apply for drawing.
*/
void draw_sprite(render_target* pCanvas, size_t iSprite, int iX, int iY, uint32_t iFlags);
void draw_sprite(render_target* pCanvas, size_t iSprite, int iX, int iY,
uint32_t iFlags);
//! Test whether a sprite was hit.
/*!
@param iSprite Sprite being tested.
@param iX X position of the point to test relative to the origin of the sprite.
@param iY Y position of the point to test relative to the origin of the sprite.
@param iX X position of the point to test relative to the origin of the
sprite.
@param iY Y position of the point to test relative to the origin of the
sprite.
@param iFlags Draw flags to apply to the sprite before testing.
@return Whether the sprite covers the give point.
*/
@@ -551,8 +552,7 @@ private:
#pragma pack(1)
#endif
//! Sprite structure in the table file.
struct th_sprite_properties
{
struct th_sprite_properties {
//! Position of the sprite in the chunk data file.
uint32_t position;
@@ -567,8 +567,7 @@ private:
#endif
//! Sprites of the sheet.
struct sprite
{
struct sprite {
//! SDL structure containing the sprite with original palette.
SDL_Texture* texture;
@@ -609,7 +608,8 @@ private:
//! Free the memory used by the sprites. Also releases the SDL bitmaps.
void _freeSprites();
//! Construct an alternative version (with its alternative palette map) of the sprite.
//! Construct an alternative version (with its alternative palette map) of
//! the sprite.
/*!
@param pSprite Sprite to change.
@return SDL texture containing the sprite.
@@ -617,8 +617,7 @@ private:
SDL_Texture* _makeAltBitmap(sprite* pSprite);
};
class cursor
{
class cursor {
public:
cursor();
~cursor();
@@ -631,6 +630,7 @@ public:
static bool set_position(render_target* pTarget, int iX, int iY);
void draw(render_target* pCanvas, int iX, int iY);
private:
SDL_Surface* bitmap;
SDL_Cursor* hidden_cursor;
@@ -638,9 +638,7 @@ private:
int hotspot_y;
};
class line
{
class line {
public:
line();
~line();
@@ -662,17 +660,14 @@ private:
friend class render_target;
void initialize();
enum class line_operation_type {
move,
line
};
enum class line_operation_type { move, line };
class line_operation : public link_list
{
class line_operation : public link_list {
public:
line_operation_type type;
double x, y;
line_operation(line_operation_type type, double x, double y) : type(type), x(x), y(y) {
line_operation(line_operation_type type, double x, double y)
: type(type), x(x), y(y) {
next = nullptr;
}
};

View File

@@ -20,12 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cstdio>
#include <cstring>
#include <stdexcept>
#include "bootstrap.h"
#include "th.h"
#include "th_lua_internal.h"
#include "bootstrap.h"
#include <cstring>
#include <cstdio>
#include <stdexcept>
void lua_register_anims(const lua_register_state* pState);
void lua_register_gfx(const lua_register_state* pState);
@@ -38,8 +38,7 @@ void lua_register_lfs_ext(const lua_register_state *pState);
void lua_register_iso_fs(const lua_register_state* pState);
//! Set a field on the environment table of an object
void luaT_setenvfield(lua_State *L, int index, const char *k)
{
void luaT_setenvfield(lua_State* L, int index, const char* k) {
lua_getfenv(L, index);
lua_pushstring(L, k);
lua_pushvalue(L, -3);
@@ -48,35 +47,27 @@ void luaT_setenvfield(lua_State *L, int index, const char *k)
}
//! Get a field from the environment table of an object
void luaT_getenvfield(lua_State *L, int index, const char *k)
{
void luaT_getenvfield(lua_State* L, int index, const char* k) {
lua_getfenv(L, index);
lua_getfield(L, -1, k);
lua_replace(L, -2);
}
#if LUA_VERSION_NUM >= 502
void luaT_getfenv52(lua_State *L, int iIndex)
{
void luaT_getfenv52(lua_State* L, int iIndex) {
int iType = lua_type(L, iIndex);
switch(iType)
{
switch (iType) {
case LUA_TUSERDATA:
lua_getuservalue(L, iIndex);
break;
case LUA_TFUNCTION:
if(lua_iscfunction(L, iIndex))
{
if (lua_iscfunction(L, iIndex)) {
// Our convention: upvalue at #1 is environment
if(lua_getupvalue(L, iIndex, 1) == nullptr)
lua_pushglobaltable(L);
}
else
{
if (lua_getupvalue(L, iIndex, 1) == nullptr) lua_pushglobaltable(L);
} else {
// Language convention: upvalue called _ENV is environment
const char* sUpName = nullptr;
for(int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)) ; ++i)
{
for (int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)); ++i) {
if (std::strcmp(sUpName, "_ENV") == 0)
return;
else
@@ -86,41 +77,37 @@ void luaT_getfenv52(lua_State *L, int iIndex)
}
break;
default:
luaL_error(L, "Unable to get environment of a %s in 5.2", lua_typename(L, iType));
luaL_error(L, "Unable to get environment of a %s in 5.2",
lua_typename(L, iType));
break;
}
}
int luaT_setfenv52(lua_State *L, int iIndex)
{
int luaT_setfenv52(lua_State* L, int iIndex) {
int iType = lua_type(L, iIndex);
switch(iType)
{
switch (iType) {
case LUA_TUSERDATA:
lua_setuservalue(L, iIndex);
return 1;
case LUA_TFUNCTION:
if(lua_iscfunction(L, iIndex))
{
if (lua_iscfunction(L, iIndex)) {
// Our convention: upvalue at #1 is environment
if(lua_setupvalue(L, iIndex, 1) == nullptr)
{
if (lua_setupvalue(L, iIndex, 1) == nullptr) {
lua_pop(L, 1);
return 0;
}
return 1;
}
else
{
// Language convention: upvalue called _ENV is environment, which
// might be shared with other functions.
} else {
// Language convention: upvalue called _ENV is environment,
// which might be shared with other functions.
const char* sUpName = nullptr;
for(int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)) ; ++i)
{
lua_pop(L, 1); // lua_getupvalue puts the value on the stack, but we just want to replace it
if(std::strcmp(sUpName, "_ENV") == 0)
{
luaL_loadstring(L, "local upv = ... return function() return upv end");
for (int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)); ++i) {
lua_pop(L, 1); // lua_getupvalue puts the value on the
// stack, but we just want to replace it
if (std::strcmp(sUpName, "_ENV") == 0) {
luaL_loadstring(L,
"local upv = ... return function() return upv "
"end");
lua_insert(L, -2);
lua_call(L, 1, 1);
lua_upvaluejoin(L, iIndex, i, -1, 1);
@@ -138,8 +125,7 @@ int luaT_setfenv52(lua_State *L, int iIndex)
#endif
//! Push a C closure as a callable table
void luaT_pushcclosuretable(lua_State *L, lua_CFunction fn, int n)
{
void luaT_pushcclosuretable(lua_State* L, lua_CFunction fn, int n) {
luaT_pushcclosure(L, fn, n); // .. fn <top
lua_createtable(L, 0, 1); // .. fn mt <top
lua_pushliteral(L, "__call"); // .. fn mt __call <top
@@ -151,62 +137,50 @@ void luaT_pushcclosuretable(lua_State *L, lua_CFunction fn, int n)
}
//! Check for a string or userdata
const uint8_t* luaT_checkfile(lua_State *L, int idx, size_t* pDataLen)
{
const uint8_t* luaT_checkfile(lua_State* L, int idx, size_t* pDataLen) {
const uint8_t* pData;
size_t iLength;
if(lua_type(L, idx) == LUA_TUSERDATA)
{
if (lua_type(L, idx) == LUA_TUSERDATA) {
pData = reinterpret_cast<const uint8_t*>(lua_touserdata(L, idx));
iLength = lua_objlen(L, idx);
} else {
pData =
reinterpret_cast<const uint8_t*>(luaL_checklstring(L, idx, &iLength));
}
else
{
pData = reinterpret_cast<const uint8_t*>(luaL_checklstring(L, idx, &iLength));
}
if(pDataLen != 0)
*pDataLen = iLength;
if (pDataLen != 0) *pDataLen = iLength;
return pData;
}
namespace {
int l_load_strings(lua_State *L)
{
int l_load_strings(lua_State* L) {
size_t iDataLength;
const uint8_t* pData = luaT_checkfile(L, 1, &iDataLength);
try
{
try {
th_string_list oStrings(pData, iDataLength);
lua_settop(L, 0);
lua_createtable(L, static_cast<int>(oStrings.get_section_count()), 0);
for(size_t iSec = 0; iSec < oStrings.get_section_count(); ++iSec)
{
for (size_t iSec = 0; iSec < oStrings.get_section_count(); ++iSec) {
size_t iCount = oStrings.get_section_size(iSec);
lua_createtable(L, static_cast<int>(iCount), 0);
for(size_t iStr = 0; iStr < iCount; ++iStr)
{
for (size_t iStr = 0; iStr < iCount; ++iStr) {
lua_pushstring(L, oStrings.get_string(iSec, iStr));
lua_rawseti(L, 2, static_cast<int>(iStr + 1));
}
lua_rawseti(L, 1, static_cast<int>(iSec + 1));
}
}
catch(std::invalid_argument)
{
} catch (std::invalid_argument) {
lua_pushboolean(L, 0);
}
return 1;
}
int get_api_version()
{
int get_api_version() {
#include "../Lua/api_version.lua"
}
int l_get_compile_options(lua_State *L)
{
int l_get_compile_options(lua_State* L) {
lua_settop(L, 0);
lua_newtable(L);
@@ -229,12 +203,9 @@ int l_get_compile_options(lua_State *L)
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, -1, "jit");
if(lua_type(L, -1) == LUA_TNIL)
{
if (lua_type(L, -1) == LUA_TNIL) {
lua_replace(L, -2);
}
else
{
} else {
lua_getfield(L, -1, "version");
lua_replace(L, -3);
lua_pop(L, 1);
@@ -249,20 +220,19 @@ int l_get_compile_options(lua_State *L)
} // namespace
void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps) {
void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
size_t iUps) {
luaT_pushcclosure(pState->L, fn, iUps);
}
int luaopen_th(lua_State *L)
{
int luaopen_th(lua_State* L) {
lua_settop(L, 0);
lua_checkstack(L, 16 + static_cast<int>(lua_metatable::count));
lua_register_state oState;
const lua_register_state* pState = &oState;
oState.L = L;
for(int i = 0; i < static_cast<int>(lua_metatable::count); ++i)
{
for (int i = 0; i < static_cast<int>(lua_metatable::count); ++i) {
lua_createtable(L, 0, 5);
oState.metatables[i] = lua_gettop(L);
}
@@ -291,26 +261,23 @@ int luaopen_th(lua_State *L)
return 1;
}
void luaT_execute_loadstring(lua_State *L, const char* sLuaString)
{
void luaT_execute_loadstring(lua_State* L, const char* sLuaString) {
static const int iRegistryCacheIndex = 7;
lua_rawgeti(L, LUA_REGISTRYINDEX, iRegistryCacheIndex);
if(lua_isnil(L, -1))
{
if (lua_isnil(L, -1)) {
// Cache not yet created - create it.
lua_pop(L, 1);
lua_getglobal(L, "setmetatable");
if(lua_isnil(L, -1))
{
if (lua_isnil(L, -1)) {
// Base library not yet loaded - fallback to simple
// uncached loadstring
lua_pop(L, 1);
if(luaL_loadstring(L, sLuaString))
lua_error(L);
if (luaL_loadstring(L, sLuaString)) lua_error(L);
}
lua_pop(L, 1);
#if LUA_VERSION_NUM >= 502
luaL_loadstring(L, "local assert, load = assert, load\n"
luaL_loadstring(L,
"local assert, load = assert, load\n"
"return setmetatable({}, {__mode = [[v]], \n"
"__index = function(t, k)\n"
"local v = assert(load(k))\n"
@@ -318,7 +285,8 @@ void luaT_execute_loadstring(lua_State *L, const char* sLuaString)
"return v\n"
"end})");
#else
luaL_loadstring(L, "local assert, loadstring = assert, loadstring\n"
luaL_loadstring(L,
"local assert, loadstring = assert, loadstring\n"
"return setmetatable({}, {__mode = [[v]], \n"
"__index = function(t, k)\n"
"local v = assert(loadstring(k))\n"
@@ -334,43 +302,30 @@ void luaT_execute_loadstring(lua_State *L, const char* sLuaString)
lua_replace(L, -2);
}
void luaT_execute(lua_State *L, const char* sLuaString)
{
void luaT_execute(lua_State* L, const char* sLuaString) {
luaT_execute_loadstring(L, sLuaString);
lua_call(L, 0, LUA_MULTRET);
}
void luaT_push(lua_State *L, lua_CFunction f)
{
luaT_pushcfunction(L, f);
}
void luaT_push(lua_State* L, lua_CFunction f) { luaT_pushcfunction(L, f); }
void luaT_push(lua_State *L, int i)
{
lua_pushinteger(L, (lua_Integer)i);
}
void luaT_push(lua_State* L, int i) { lua_pushinteger(L, (lua_Integer)i); }
void luaT_push(lua_State *L, const char* s)
{
lua_pushstring(L, s);
}
void luaT_push(lua_State* L, const char* s) { lua_pushstring(L, s); }
void luaT_pushtablebool(lua_State *L, const char *k, bool v)
{
void luaT_pushtablebool(lua_State* L, const char* k, bool v) {
lua_pushstring(L, k);
lua_pushboolean(L, v);
lua_settable(L, -3);
}
void luaT_printstack(lua_State* L)
{
void luaT_printstack(lua_State* L) {
int i;
int top = lua_gettop(L);
std::printf("total items in stack %d\n", top);
for (i = 1; i <= top; i++)
{ /* repeat for each level */
for (i = 1; i <= top; i++) { /* repeat for each level */
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: /* strings */
@@ -387,20 +342,17 @@ void luaT_printstack(lua_State* L)
break;
}
std::printf(" "); /* put a separator */
}
std::printf("\n"); /* end the listing */
}
void luaT_printrawtable(lua_State* L, int idx)
{
void luaT_printrawtable(lua_State* L, int idx) {
int i;
int len = static_cast<int>(lua_objlen(L, idx));
std::printf("total items in table %d\n", len);
for (i = 1; i <= len; i++)
{
for (i = 1; i <= len; i++) {
lua_rawgeti(L, idx, i);
int t = lua_type(L, -1);
switch (t) {

View File

@@ -23,10 +23,10 @@ SOFTWARE.
#ifndef CORSIX_TH_TH_LUA_H_
#define CORSIX_TH_TH_LUA_H_
#include "config.h"
#include "lua.hpp"
#include <cstdio>
#include <new>
#include <vector>
#include "lua.hpp"
int luaopen_th(lua_State* L);
@@ -37,8 +37,7 @@ const int luaT_environindex = lua_upvalueindex(1);
const int luaT_environindex = LUA_ENVIRONINDEX;
#endif
inline int luaT_upvalueindex(int i)
{
inline int luaT_upvalueindex(int i) {
#if LUA_VERSION_NUM >= 502
return lua_upvalueindex(i + 1);
#else
@@ -47,8 +46,7 @@ inline int luaT_upvalueindex(int i)
}
template <class Collection>
inline void luaT_register(lua_State *L, const char *n, Collection &l)
{
inline void luaT_register(lua_State* L, const char* n, Collection& l) {
#if LUA_VERSION_NUM >= 502
lua_createtable(L, 0, static_cast<int>(l.size()));
lua_pushvalue(L, luaT_environindex);
@@ -60,8 +58,7 @@ inline void luaT_register(lua_State *L, const char *n, Collection &l)
#endif
}
inline void luaT_setfuncs(lua_State *L, const luaL_Reg *R)
{
inline void luaT_setfuncs(lua_State* L, const luaL_Reg* R) {
#if LUA_VERSION_NUM >= 502
lua_pushvalue(L, luaT_environindex);
luaL_setfuncs(L, R, 1);
@@ -70,8 +67,7 @@ inline void luaT_setfuncs(lua_State *L, const luaL_Reg *R)
#endif
}
inline void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups)
{
inline void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups) {
#if LUA_VERSION_NUM >= 502
++nups;
lua_pushvalue(L, luaT_environindex);
@@ -82,13 +78,11 @@ inline void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups)
#endif
}
inline void luaT_pushcfunction(lua_State *L, lua_CFunction f)
{
inline void luaT_pushcfunction(lua_State* L, lua_CFunction f) {
luaT_pushcclosure(L, f, 0);
}
inline int luaT_cpcall(lua_State *L, lua_CFunction f, void *u)
{
inline int luaT_cpcall(lua_State* L, lua_CFunction f, void* u) {
#if LUA_VERSION_NUM >= 502
lua_checkstack(L, 2);
lua_pushcfunction(L, f);
@@ -100,8 +94,8 @@ inline int luaT_cpcall(lua_State *L, lua_CFunction f, void *u)
}
// Compatibility for missing mode argument on lua_load in 5.1
inline int luaT_load(lua_State *L, lua_Reader r, void *d, const char *s, const char *m)
{
inline int luaT_load(lua_State* L, lua_Reader r, void* d, const char* s,
const char* m) {
#if LUA_VERSION_NUM >= 502
return lua_load(L, r, d, s, m);
#else
@@ -110,8 +104,7 @@ inline int luaT_load(lua_State *L, lua_Reader r, void *d, const char *s, const c
}
// Compatibility for missing from argument on lua_resume in 5.1
inline int luaT_resume(lua_State *L, lua_State *f, int n)
{
inline int luaT_resume(lua_State* L, lua_State* f, int n) {
#if LUA_VERSION_NUM >= 502
return lua_resume(L, f, n);
#else
@@ -129,8 +122,7 @@ inline int luaT_resume(lua_State *L, lua_State *f, int n)
table and metatable for the userdata.
*/
template <typename T, typename... Ts>
T* luaT_new(lua_State* L, Ts ...args)
{
T* luaT_new(lua_State* L, Ts... args) {
return new (lua_newuserdata(L, sizeof(T))) T(args...);
}
@@ -161,191 +153,207 @@ void luaT_setenvfield(lua_State *L, int index, const char *k);
void luaT_getenvfield(lua_State* L, int index, const char* k);
template <class T>
inline T* luaT_stdnew(lua_State *L, int mt_idx = luaT_environindex, bool env = false)
{
inline T* luaT_stdnew(lua_State* L, int mt_idx = luaT_environindex,
bool env = false) {
T* p = luaT_new<T>(L);
lua_pushvalue(L, mt_idx);
lua_setmetatable(L, -2);
if(env)
{
if (env) {
lua_newtable(L);
lua_setfenv(L, -2);
}
return p;
}
template <typename T> struct luaT_classinfo {};
template <typename T>
struct luaT_classinfo {};
class render_target;
template <> struct luaT_classinfo<render_target> {
template <>
struct luaT_classinfo<render_target> {
static inline const char* name() { return "Surface"; }
};
class level_map;
template <> struct luaT_classinfo<level_map> {
template <>
struct luaT_classinfo<level_map> {
static inline const char* name() { return "Map"; }
};
class sprite_sheet;
template <> struct luaT_classinfo<sprite_sheet> {
template <>
struct luaT_classinfo<sprite_sheet> {
static inline const char* name() { return "SpriteSheet"; }
};
class animation;
template <> struct luaT_classinfo<animation> {
template <>
struct luaT_classinfo<animation> {
static inline const char* name() { return "Animation"; }
};
class animation_manager;
template <> struct luaT_classinfo<animation_manager> {
template <>
struct luaT_classinfo<animation_manager> {
static inline const char* name() { return "Animator"; }
};
class palette;
template <> struct luaT_classinfo<palette> {
template <>
struct luaT_classinfo<palette> {
static inline const char* name() { return "Palette"; }
};
class raw_bitmap;
template <> struct luaT_classinfo<raw_bitmap> {
template <>
struct luaT_classinfo<raw_bitmap> {
static inline const char* name() { return "RawBitmap"; }
};
class font;
template <> struct luaT_classinfo<font> {
template <>
struct luaT_classinfo<font> {
static inline const char* name() { return "Font"; }
};
class bitmap_font;
template <> struct luaT_classinfo<bitmap_font> {
template <>
struct luaT_classinfo<bitmap_font> {
static inline const char* name() { return "BitmapFont"; }
};
#ifdef CORSIX_TH_USE_FREETYPE2
class freetype_font;
template <> struct luaT_classinfo<freetype_font> {
template <>
struct luaT_classinfo<freetype_font> {
static inline const char* name() { return "FreeTypeFont"; }
};
#endif
struct layers;
template <> struct luaT_classinfo<layers> {
template <>
struct luaT_classinfo<layers> {
static inline const char* name() { return "Layers"; }
};
class pathfinder;
template <> struct luaT_classinfo<pathfinder> {
template <>
struct luaT_classinfo<pathfinder> {
static inline const char* name() { return "Pathfinder"; }
};
class cursor;
template <> struct luaT_classinfo<cursor> {
template <>
struct luaT_classinfo<cursor> {
static inline const char* name() { return "Cursor"; }
};
class line;
template <> struct luaT_classinfo<line> {
template <>
struct luaT_classinfo<line> {
static inline const char* name() { return "Line"; }
};
class music;
template <> struct luaT_classinfo<music> {
template <>
struct luaT_classinfo<music> {
static inline const char* name() { return "Music"; }
};
class sound_archive;
template <> struct luaT_classinfo<sound_archive> {
template <>
struct luaT_classinfo<sound_archive> {
static inline const char* name() { return "SoundArchive"; }
};
class sound_player;
template <> struct luaT_classinfo<sound_player> {
template <>
struct luaT_classinfo<sound_player> {
static inline const char* name() { return "SoundEffects"; }
};
class movie_player;
template <> struct luaT_classinfo<movie_player> {
template <>
struct luaT_classinfo<movie_player> {
static inline const char* name() { return "Movie"; }
};
class abstract_window;
template <> struct luaT_classinfo<abstract_window> {
template <>
struct luaT_classinfo<abstract_window> {
static inline const char* name() { return "WindowBase"; }
};
class sprite_render_list;
template <> struct luaT_classinfo<sprite_render_list> {
template <>
struct luaT_classinfo<sprite_render_list> {
static inline const char* name() { return "SpriteRenderList"; }
};
class string_proxy;
template <> struct luaT_classinfo<string_proxy> {
template <>
struct luaT_classinfo<string_proxy> {
static inline const char* name() { return "StringProxy"; }
};
class lfs_ext;
template <> struct luaT_classinfo <lfs_ext> {
template <>
struct luaT_classinfo<lfs_ext> {
static inline const char* name() { return "LfsExt"; }
};
class iso_filesystem;
template <> struct luaT_classinfo<iso_filesystem> {
template <>
struct luaT_classinfo<iso_filesystem> {
static inline const char* name() { return "ISO Filesystem"; }
};
template <> struct luaT_classinfo<std::FILE*> {
template <>
struct luaT_classinfo<std::FILE*> {
static inline const char* name() { return "file"; }
};
template <class T>
T* luaT_testuserdata(lua_State *L, int idx, int mt_idx, bool required = true)
{
T* luaT_testuserdata(lua_State* L, int idx, int mt_idx, bool required = true) {
// Turn mt_idx into an absolute index, as the stack size changes.
if (mt_idx > LUA_REGISTRYINDEX && mt_idx < 0)
mt_idx = lua_gettop(L) + mt_idx + 1;
void* ud = lua_touserdata(L, idx);
if(ud != nullptr && lua_getmetatable(L, idx) != 0)
{
while(true)
{
if(lua_equal(L, mt_idx, -1) != 0)
{
if (ud != nullptr && lua_getmetatable(L, idx) != 0) {
while (true) {
if (lua_equal(L, mt_idx, -1) != 0) {
lua_pop(L, 1);
return (T*)ud;
}
// Go up one inheritance level, if there is one.
if(lua_type(L, -1) != LUA_TTABLE)
break;
if (lua_type(L, -1) != LUA_TTABLE) break;
lua_rawgeti(L, -1, 1);
lua_replace(L, -2);
}
lua_pop(L, 1);
}
if (required)
{
const char *msg = lua_pushfstring(L, "%s expected, got %s", luaT_classinfo<T>::name(), luaL_typename(L, idx));
if (required) {
const char* msg =
lua_pushfstring(L, "%s expected, got %s", luaT_classinfo<T>::name(),
luaL_typename(L, idx));
luaL_argerror(L, idx, msg);
}
return nullptr;
}
template <class T>
T* luaT_testuserdata(lua_State *L, int idx = 1)
{
T* luaT_testuserdata(lua_State* L, int idx = 1) {
int iMetaIndex = luaT_environindex;
if(idx > 1)
iMetaIndex = luaT_upvalueindex(idx - 1);
if (idx > 1) iMetaIndex = luaT_upvalueindex(idx - 1);
return luaT_testuserdata<T>(L, idx, iMetaIndex);
}
template <class T, int mt>
int luaT_stdgc(lua_State *L)
{
int luaT_stdgc(lua_State* L) {
T* p = luaT_testuserdata<T>(L, 1, mt, false);
if(p != nullptr)
{
if (p != nullptr) {
p->~T();
}
return 0;
@@ -359,17 +367,14 @@ void luaT_push(lua_State *L, int i);
void luaT_push(lua_State* L, const char* s);
template <class T>
void luaT_execute(lua_State *L, const char* sLuaString, T arg)
{
void luaT_execute(lua_State* L, const char* sLuaString, T arg) {
luaT_execute_loadstring(L, sLuaString);
luaT_push(L, arg);
lua_call(L, 1, LUA_MULTRET);
}
template <class T1, class T2>
void luaT_execute(lua_State *L, const char* sLuaString,
T1 arg1, T2 arg2)
{
void luaT_execute(lua_State* L, const char* sLuaString, T1 arg1, T2 arg2) {
luaT_execute_loadstring(L, sLuaString);
luaT_push(L, arg1);
luaT_push(L, arg2);
@@ -377,9 +382,8 @@ void luaT_execute(lua_State *L, const char* sLuaString,
}
template <class T1, class T2, class T3>
void luaT_execute(lua_State *L, const char* sLuaString,
T1 arg1, T2 arg2, T3 arg3)
{
void luaT_execute(lua_State* L, const char* sLuaString, T1 arg1, T2 arg2,
T3 arg3) {
luaT_execute_loadstring(L, sLuaString);
luaT_push(L, arg1);
luaT_push(L, arg2);
@@ -388,9 +392,8 @@ void luaT_execute(lua_State *L, const char* sLuaString,
}
template <class T1, class T2, class T3, class T4>
void luaT_execute(lua_State *L, const char* sLuaString,
T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
void luaT_execute(lua_State* L, const char* sLuaString, T1 arg1, T2 arg2,
T3 arg3, T4 arg4) {
luaT_execute_loadstring(L, sLuaString);
luaT_push(L, arg1);
luaT_push(L, arg2);

View File

@@ -20,24 +20,24 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_lua_internal.h"
#include "th_gfx.h"
#include "th_lua_internal.h"
#include "th_map.h"
namespace {
/* this variable is used to determine the layer of the animation, it should be rewriten at some
point so that the it is passed as an argument in the function l_anim_set_tile */
/* this variable is used to determine the layer of the animation, it should be
rewriten at some
point so that the it is passed as an argument in the function l_anim_set_tile
*/
int last_layer = 2;
int l_anims_new(lua_State *L)
{
int l_anims_new(lua_State* L) {
luaT_stdnew<animation_manager>(L, luaT_environindex, true);
return 1;
}
int l_anims_set_spritesheet(lua_State *L)
{
int l_anims_set_spritesheet(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
sprite_sheet* pSheet = luaT_testuserdata<sprite_sheet>(L, 2);
lua_settop(L, 2);
@@ -51,8 +51,7 @@ int l_anims_set_spritesheet(lua_State *L)
/*!
setCanvas(<video-surface>)
*/
int l_anims_set_canvas(lua_State *L)
{
int l_anims_set_canvas(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
render_target* pCanvas = luaT_testuserdata<render_target>(L, 2);
lua_settop(L, 2);
@@ -62,22 +61,20 @@ int l_anims_set_canvas(lua_State *L)
return 1;
}
int l_anims_load(lua_State *L)
{
int l_anims_load(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
size_t iStartDataLength, iFrameDataLength, iListDataLength, iElementDataLength;
size_t iStartDataLength, iFrameDataLength, iListDataLength,
iElementDataLength;
const uint8_t* pStartData = luaT_checkfile(L, 2, &iStartDataLength);
const uint8_t* pFrameData = luaT_checkfile(L, 3, &iFrameDataLength);
const uint8_t* pListData = luaT_checkfile(L, 4, &iListDataLength);
const uint8_t* pElementData = luaT_checkfile(L, 5, &iElementDataLength);
if(pAnims->load_from_th_file(pStartData, iStartDataLength, pFrameData, iFrameDataLength,
pListData, iListDataLength, pElementData, iElementDataLength))
{
if (pAnims->load_from_th_file(pStartData, iStartDataLength, pFrameData,
iFrameDataLength, pListData, iListDataLength,
pElementData, iElementDataLength)) {
lua_pushboolean(L, 1);
}
else
{
} else {
lua_pushboolean(L, 0);
}
@@ -88,18 +85,14 @@ int l_anims_load(lua_State *L)
/*!
loadCustom(<data-of-an-animation-file>) -> true/false
*/
int l_anims_loadcustom(lua_State *L)
{
int l_anims_loadcustom(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
size_t iDataLength;
const uint8_t* pData = luaT_checkfile(L, 2, &iDataLength);
if (pAnims->load_custom_animations(pData, iDataLength))
{
if (pAnims->load_custom_animations(pData, iDataLength)) {
lua_pushboolean(L, 1);
}
else
{
} else {
lua_pushboolean(L, 0);
}
@@ -109,25 +102,40 @@ int l_anims_loadcustom(lua_State *L)
//! Lua interface for getting a set of animations by name and tile size (one for
//! each view direction, 'nil' if no animation is available for a direction).
/*!
getAnimations(<tile-size>, <animation-name>) -> (<anim-north>, <anim-east>, <anim-south>, <anim-west>)
getAnimations(<tile-size>, <animation-name>) -> (<anim-north>, <anim-east>,
<anim-south>, <anim-west>)
*/
int l_anims_getanims(lua_State *L)
{
int l_anims_getanims(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
int iTileSize = static_cast<int>(luaL_checkinteger(L, 2));
const char* pName = luaL_checkstring(L, 3);
const animation_start_frames &oFrames = pAnims->get_named_animations(pName, iTileSize);
if (oFrames.north < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast<double>(oFrames.north)); }
if (oFrames.east < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast<double>(oFrames.east)); }
if (oFrames.south < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast<double>(oFrames.south)); }
if (oFrames.west < 0) { lua_pushnil(L); } else { lua_pushnumber(L, static_cast<double>(oFrames.west)); }
const animation_start_frames& oFrames =
pAnims->get_named_animations(pName, iTileSize);
if (oFrames.north < 0) {
lua_pushnil(L);
} else {
lua_pushnumber(L, static_cast<double>(oFrames.north));
}
if (oFrames.east < 0) {
lua_pushnil(L);
} else {
lua_pushnumber(L, static_cast<double>(oFrames.east));
}
if (oFrames.south < 0) {
lua_pushnil(L);
} else {
lua_pushnumber(L, static_cast<double>(oFrames.south));
}
if (oFrames.west < 0) {
lua_pushnil(L);
} else {
lua_pushnumber(L, static_cast<double>(oFrames.west));
}
return 4;
}
int l_anims_getfirst(lua_State *L)
{
int l_anims_getfirst(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
int iAnim = static_cast<int>(luaL_checkinteger(L, 2));
@@ -135,8 +143,7 @@ int l_anims_getfirst(lua_State *L)
return 1;
}
int l_anims_getnext(lua_State *L)
{
int l_anims_getnext(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
int iFrame = static_cast<int>(luaL_checkinteger(L, 2));
@@ -144,14 +151,12 @@ int l_anims_getnext(lua_State *L)
return 1;
}
int l_anims_set_alt_pal(lua_State *L)
{
int l_anims_set_alt_pal(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
size_t iAnimation = luaL_checkinteger(L, 2);
size_t iPalLen;
const uint8_t* pPal = luaT_checkfile(L, 3, &iPalLen);
if(iPalLen != 256)
{
if (iPalLen != 256) {
return luaL_argerror(L, 3, "GhostPalette string is not a valid palette");
}
uint32_t iAlt32 = static_cast<uint32_t>(luaL_checkinteger(L, 4));
@@ -166,24 +171,29 @@ int l_anims_set_alt_pal(lua_State *L)
return 1;
}
int l_anims_set_marker(lua_State *L)
{
int l_anims_set_marker(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
lua_pushboolean(L, pAnims->set_frame_marker(luaL_checkinteger(L, 2),
static_cast<int>(luaL_checkinteger(L, 3)), static_cast<int>(luaL_checkinteger(L, 4))) ? 1 : 0);
lua_pushboolean(
L, pAnims->set_frame_marker(luaL_checkinteger(L, 2),
static_cast<int>(luaL_checkinteger(L, 3)),
static_cast<int>(luaL_checkinteger(L, 4)))
? 1
: 0);
return 1;
}
int l_anims_set_secondary_marker(lua_State *L)
{
int l_anims_set_secondary_marker(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
lua_pushboolean(L, pAnims->set_frame_secondary_marker(luaL_checkinteger(L, 2),
static_cast<int>(luaL_checkinteger(L, 3)), static_cast<int>(luaL_checkinteger(L, 4))) ? 1 : 0);
lua_pushboolean(
L, pAnims->set_frame_secondary_marker(
luaL_checkinteger(L, 2), static_cast<int>(luaL_checkinteger(L, 3)),
static_cast<int>(luaL_checkinteger(L, 4)))
? 1
: 0);
return 1;
}
int l_anims_draw(lua_State *L)
{
int l_anims_draw(lua_State* L) {
animation_manager* pAnims = luaT_testuserdata<animation_manager>(L);
render_target* pCanvas = luaT_testuserdata<render_target>(L, 2);
size_t iFrame = luaL_checkinteger(L, 3);
@@ -199,8 +209,7 @@ int l_anims_draw(lua_State *L)
}
template <typename T>
int l_anim_new(lua_State *L)
{
int l_anim_new(lua_State* L) {
T* pAnimation = luaT_stdnew<T>(L, luaT_environindex, true);
lua_rawgeti(L, luaT_environindex, 2);
lua_pushlightuserdata(L, pAnimation);
@@ -211,16 +220,12 @@ int l_anim_new(lua_State *L)
}
template <typename T>
int l_anim_persist(lua_State *L)
{
int l_anim_persist(lua_State* L) {
T* pAnimation;
if(lua_gettop(L) == 2)
{
if (lua_gettop(L) == 2) {
pAnimation = luaT_testuserdata<T>(L, 1, luaT_environindex, false);
lua_insert(L, 1);
}
else
{
} else {
// Fast __persist call
pAnimation = (T*)lua_touserdata(L, -1);
}
@@ -236,8 +241,7 @@ int l_anim_persist(lua_State *L)
}
template <typename T>
int l_anim_pre_depersist(lua_State *L)
{
int l_anim_pre_depersist(lua_State* L) {
// Note that anims and the map have nice reference cycles between them
// and hence we cannot be sure which is depersisted first. To ensure that
// things work nicely, we initialise all the fields of a THAnimation as
@@ -252,8 +256,7 @@ int l_anim_pre_depersist(lua_State *L)
}
template <typename T>
int l_anim_depersist(lua_State *L)
{
int l_anim_depersist(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
lua_settop(L, 2);
lua_insert(L, 1);
@@ -267,15 +270,13 @@ int l_anim_depersist(lua_State *L)
pAnimation->depersist(pReader);
lua_rawgeti(L, luaT_environindex, 1);
lua_pushlightuserdata(L, pAnimation);
if(!pReader->read_stack_object())
return 0;
if (!pReader->read_stack_object()) return 0;
lua_settable(L, -3);
lua_pop(L, 1);
return 0;
}
int l_anim_set_hitresult(lua_State *L)
{
int l_anim_set_hitresult(lua_State* L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_settop(L, 2);
lua_rawgeti(L, luaT_environindex, 1);
@@ -286,48 +287,44 @@ int l_anim_set_hitresult(lua_State *L)
return 1;
}
int l_anim_set_frame(lua_State *L)
{
int l_anim_set_frame(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
pAnimation->set_frame(luaL_checkinteger(L, 2));
lua_settop(L, 1);
return 1;
}
int l_anim_get_frame(lua_State *L)
{
int l_anim_get_frame(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
lua_pushinteger(L, pAnimation->get_frame());
return 1;
}
int l_anim_set_crop(lua_State *L)
{
int l_anim_set_crop(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
pAnimation->set_crop_column(static_cast<int>(luaL_checkinteger(L, 2)));
lua_settop(L, 1);
return 1;
}
int l_anim_get_crop(lua_State *L)
{
int l_anim_get_crop(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
lua_pushinteger(L, pAnimation->get_crop_column());
return 1;
}
int l_anim_set_anim(lua_State *L)
{
int l_anim_set_anim(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
animation_manager* pManager = luaT_testuserdata<animation_manager>(L, 2);
size_t iAnim = luaL_checkinteger(L, 3);
if (iAnim < 0 || iAnim >= pManager->get_animation_count())
luaL_argerror(L, 3, "Animation index out of bounds");
if(lua_isnoneornil(L, 4))
if (lua_isnoneornil(L, 4)) {
pAnimation->set_flags(0);
else
} else {
pAnimation->set_flags(static_cast<uint32_t>(luaL_checkinteger(L, 4)));
}
pAnimation->set_animation(pManager, iAnim);
lua_settop(L, 2);
@@ -338,14 +335,15 @@ int l_anim_set_anim(lua_State *L)
return 1;
}
int l_anim_set_morph(lua_State *L)
{
int l_anim_set_morph(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
animation* pMorphTarget = luaT_testuserdata<animation>(L, 2, luaT_environindex);
animation* pMorphTarget =
luaT_testuserdata<animation>(L, 2, luaT_environindex);
unsigned int iDurationFactor = 1;
if(!lua_isnoneornil(L, 3) && luaL_checkinteger(L, 3) > 0)
if (!lua_isnoneornil(L, 3) && luaL_checkinteger(L, 3) > 0) {
iDurationFactor = static_cast<unsigned int>(luaL_checkinteger(L, 3));
}
pAnimation->set_morph_target(pMorphTarget, iDurationFactor);
lua_settop(L, 2);
@@ -354,14 +352,12 @@ int l_anim_set_morph(lua_State *L)
return 1;
}
int l_anim_set_drawable_layer(lua_State *L)
{
int l_anim_set_drawable_layer(lua_State* L) {
last_layer = static_cast<int>(luaL_checkinteger(L, 2));
return 1;
}
int l_anim_get_anim(lua_State *L)
{
int l_anim_get_anim(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
lua_pushinteger(L, pAnimation->get_animation());
@@ -369,29 +365,26 @@ int l_anim_get_anim(lua_State *L)
}
template <typename T>
int l_anim_set_tile(lua_State *L)
{
int l_anim_set_tile(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
if(lua_isnoneornil(L, 2))
{
if (lua_isnoneornil(L, 2)) {
pAnimation->remove_from_tile();
lua_pushnil(L);
luaT_setenvfield(L, 1, "map");
lua_settop(L, 1);
}
else
{
} else {
level_map* pMap = luaT_testuserdata<level_map>(L, 2);
map_tile* pNode = pMap->get_tile(static_cast<int>(luaL_checkinteger(L, 3) - 1), static_cast<int>(luaL_checkinteger(L, 4) - 1));
if(pNode)
map_tile* pNode =
pMap->get_tile(static_cast<int>(luaL_checkinteger(L, 3) - 1),
static_cast<int>(luaL_checkinteger(L, 4) - 1));
if (pNode) {
pAnimation->attach_to_tile(pNode, last_layer);
else
{
luaL_argerror(L, 3, lua_pushfstring(L, "Map index out of bounds ("
LUA_NUMBER_FMT "," LUA_NUMBER_FMT ")", lua_tonumber(L, 3),
lua_tonumber(L, 4)));
} else {
luaL_argerror(L, 3,
lua_pushfstring(L,
"Map index out of bounds (" LUA_NUMBER_FMT
"," LUA_NUMBER_FMT ")",
lua_tonumber(L, 3), lua_tonumber(L, 4)));
}
lua_settop(L, 2);
@@ -401,21 +394,18 @@ int l_anim_set_tile(lua_State *L)
return 1;
}
int l_anim_get_tile(lua_State *L)
{
int l_anim_get_tile(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
lua_settop(L, 1);
lua_getfenv(L, 1);
lua_getfield(L, 2, "map");
lua_replace(L, 2);
if(lua_isnil(L, 2))
{
if (lua_isnil(L, 2)) {
return 0;
}
level_map* pMap = (level_map*)lua_touserdata(L, 2);
const link_list* pListNode = pAnimation->get_previous();
while(pListNode->prev)
{
while (pListNode->prev) {
pListNode = pListNode->prev;
}
// Casting pListNode to a map_tile* is slightly dubious, but it should
@@ -435,18 +425,17 @@ int l_anim_get_tile(lua_State *L)
return 3; // map, x, y
}
int l_anim_set_parent(lua_State *L)
{
int l_anim_set_parent(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
animation* pParent = luaT_testuserdata<animation>(L, 2, luaT_environindex, false);
animation* pParent =
luaT_testuserdata<animation>(L, 2, luaT_environindex, false);
pAnimation->set_parent(pParent);
lua_settop(L, 1);
return 1;
}
template <typename T>
int l_anim_set_flag(lua_State *L)
{
int l_anim_set_flag(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->set_flags(static_cast<uint32_t>(luaL_checkinteger(L, 2)));
@@ -455,16 +444,12 @@ int l_anim_set_flag(lua_State *L)
}
template <typename T>
int l_anim_set_flag_partial(lua_State *L)
{
int l_anim_set_flag_partial(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
uint32_t iFlags = static_cast<uint32_t>(luaL_checkinteger(L, 2));
if(lua_isnone(L, 3) || lua_toboolean(L, 3))
{
if (lua_isnone(L, 3) || lua_toboolean(L, 3)) {
pAnimation->set_flags(pAnimation->get_flags() | iFlags);
}
else
{
} else {
pAnimation->set_flags(pAnimation->get_flags() & ~iFlags);
}
lua_settop(L, 1);
@@ -472,28 +457,27 @@ int l_anim_set_flag_partial(lua_State *L)
}
template <typename T>
int l_anim_make_visible(lua_State *L)
{
int l_anim_make_visible(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->set_flags(pAnimation->get_flags() & ~static_cast<uint32_t>(thdf_alpha_50 | thdf_alpha_75));
pAnimation->set_flags(pAnimation->get_flags() &
~static_cast<uint32_t>(thdf_alpha_50 | thdf_alpha_75));
lua_settop(L, 1);
return 1;
}
template <typename T>
int l_anim_make_invisible(lua_State *L)
{
int l_anim_make_invisible(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->set_flags(pAnimation->get_flags() | static_cast<uint32_t>(thdf_alpha_50 | thdf_alpha_75));
pAnimation->set_flags(pAnimation->get_flags() |
static_cast<uint32_t>(thdf_alpha_50 | thdf_alpha_75));
lua_settop(L, 1);
return 1;
}
template <typename T>
int l_anim_get_flag(lua_State *L)
{
int l_anim_get_flag(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
lua_pushinteger(L, pAnimation->get_flags());
@@ -501,18 +485,17 @@ int l_anim_get_flag(lua_State *L)
}
template <typename T>
int l_anim_set_position(lua_State *L)
{
int l_anim_set_position(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->set_position(static_cast<int>(luaL_checkinteger(L, 2)), static_cast<int>(luaL_checkinteger(L, 3)));
pAnimation->set_position(static_cast<int>(luaL_checkinteger(L, 2)),
static_cast<int>(luaL_checkinteger(L, 3)));
lua_settop(L, 1);
return 1;
}
int l_anim_get_position(lua_State *L)
{
int l_anim_get_position(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
lua_pushinteger(L, pAnimation->get_x());
@@ -522,31 +505,31 @@ int l_anim_get_position(lua_State *L)
}
template <typename T>
int l_anim_set_speed(lua_State *L)
{
int l_anim_set_speed(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->set_speed(static_cast<int>(luaL_optinteger(L, 2, 0)), static_cast<int>(luaL_optinteger(L, 3, 0)));
pAnimation->set_speed(static_cast<int>(luaL_optinteger(L, 2, 0)),
static_cast<int>(luaL_optinteger(L, 3, 0)));
lua_settop(L, 1);
return 1;
}
template <typename T>
int l_anim_set_layer(lua_State *L)
{
int l_anim_set_layer(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->set_layer(static_cast<int>(luaL_checkinteger(L, 2)), static_cast<int>(luaL_optinteger(L, 3, 0)));
pAnimation->set_layer(static_cast<int>(luaL_checkinteger(L, 2)),
static_cast<int>(luaL_optinteger(L, 3, 0)));
lua_settop(L, 1);
return 1;
}
int l_anim_set_layers_from(lua_State *L)
{
int l_anim_set_layers_from(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
const animation* pAnimationSrc = luaT_testuserdata<animation>(L, 2, luaT_environindex);
const animation* pAnimationSrc =
luaT_testuserdata<animation>(L, 2, luaT_environindex);
pAnimation->set_layers_from(pAnimationSrc);
@@ -554,16 +537,14 @@ int l_anim_set_layers_from(lua_State *L)
return 1;
}
int l_anim_set_tag(lua_State *L)
{
int l_anim_set_tag(lua_State* L) {
luaT_testuserdata<animation>(L);
lua_settop(L, 2);
luaT_setenvfield(L, 1, "tag");
return 1;
}
int l_anim_get_tag(lua_State *L)
{
int l_anim_get_tag(lua_State* L) {
luaT_testuserdata<animation>(L);
lua_settop(L, 1);
lua_getfenv(L, 1);
@@ -571,8 +552,7 @@ int l_anim_get_tag(lua_State *L)
return 1;
}
int l_anim_get_marker(lua_State *L)
{
int l_anim_get_marker(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
int iX = 0;
int iY = 0;
@@ -582,8 +562,7 @@ int l_anim_get_marker(lua_State *L)
return 2;
}
int l_anim_get_secondary_marker(lua_State *L)
{
int l_anim_get_secondary_marker(lua_State* L) {
animation* pAnimation = luaT_testuserdata<animation>(L);
int iX = 0;
int iY = 0;
@@ -594,8 +573,7 @@ int l_anim_get_secondary_marker(lua_State *L)
}
template <typename T>
int l_anim_tick(lua_State *L)
{
int l_anim_tick(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
pAnimation->tick();
lua_settop(L, 1);
@@ -603,17 +581,16 @@ int l_anim_tick(lua_State *L)
}
template <typename T>
int l_anim_draw(lua_State *L)
{
int l_anim_draw(lua_State* L) {
T* pAnimation = luaT_testuserdata<T>(L);
render_target* pCanvas = luaT_testuserdata<render_target>(L, 2);
pAnimation->draw(pCanvas, static_cast<int>(luaL_checkinteger(L, 3)), static_cast<int>(luaL_checkinteger(L, 4)));
pAnimation->draw(pCanvas, static_cast<int>(luaL_checkinteger(L, 3)),
static_cast<int>(luaL_checkinteger(L, 4)));
lua_settop(L, 1);
return 1;
}
int l_srl_set_sheet(lua_State *L)
{
int l_srl_set_sheet(lua_State* L) {
sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
sprite_sheet* pSheet = luaT_testuserdata<sprite_sheet>(L, 2);
pSrl->set_sheet(pSheet);
@@ -623,25 +600,23 @@ int l_srl_set_sheet(lua_State *L)
return 1;
}
int l_srl_append(lua_State *L)
{
int l_srl_append(lua_State* L) {
sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
pSrl->append_sprite(luaL_checkinteger(L, 2),
static_cast<int>(luaL_checkinteger(L, 3)), static_cast<int>(luaL_checkinteger(L, 4)));
static_cast<int>(luaL_checkinteger(L, 3)),
static_cast<int>(luaL_checkinteger(L, 4)));
lua_settop(L, 1);
return 1;
}
int l_srl_set_lifetime(lua_State *L)
{
int l_srl_set_lifetime(lua_State* L) {
sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
pSrl->set_lifetime(static_cast<int>(luaL_checkinteger(L, 2)));
lua_settop(L, 1);
return 1;
}
int l_srl_is_dead(lua_State *L)
{
int l_srl_is_dead(lua_State* L) {
sprite_render_list* pSrl = luaT_testuserdata<sprite_render_list>(L);
lua_pushboolean(L, pSrl->is_dead() ? 1 : 0);
return 1;
@@ -649,11 +624,11 @@ int l_srl_is_dead(lua_State *L)
} // namespace
void lua_register_anims(const lua_register_state *pState)
{
void lua_register_anims(const lua_register_state* pState) {
// Anims
{
lua_class_binding<animation_manager> lcb(pState, "anims", l_anims_new, lua_metatable::anims);
lua_class_binding<animation_manager> lcb(pState, "anims", l_anims_new,
lua_metatable::anims);
lcb.add_function(l_anims_load, "load");
lcb.add_function(l_anims_loadcustom, "loadCustom");
lcb.add_function(l_anims_set_spritesheet, "setSheet", lua_metatable::sheet);
@@ -664,7 +639,8 @@ void lua_register_anims(const lua_register_state *pState)
lcb.add_function(l_anims_set_alt_pal, "setAnimationGhostPalette");
lcb.add_function(l_anims_set_marker, "setFrameMarker");
lcb.add_function(l_anims_set_secondary_marker, "setFrameSecondaryMarker");
lcb.add_function(l_anims_draw, "draw", lua_metatable::surface, lua_metatable::layers);
lcb.add_function(l_anims_draw, "draw", lua_metatable::surface,
lua_metatable::layers);
lcb.add_constant("Alt32_GreyScale", thdf_alt32_grey_scale);
lcb.add_constant("Alt32_BlueRedSwap", thdf_alt32_blue_red_swap);
}
@@ -676,7 +652,8 @@ void lua_register_anims(const lua_register_state *pState)
lua_pushliteral(pState->L, "v");
lua_setfield(pState->L, -2, "__mode");
lua_setmetatable(pState->L, -2);
lua_rawseti(pState->L, pState->metatables[static_cast<size_t>(lua_metatable::anim)], 1);
lua_rawseti(pState->L,
pState->metatables[static_cast<size_t>(lua_metatable::anim)], 1);
// Weak table at AnimMetatable[2] for light UD -> full UD lookup
// For persisting Map
@@ -685,11 +662,13 @@ void lua_register_anims(const lua_register_state *pState)
lua_pushliteral(pState->L, "v");
lua_setfield(pState->L, -2, "__mode");
lua_setmetatable(pState->L, -2);
lua_rawseti(pState->L, pState->metatables[static_cast<size_t>(lua_metatable::anim)], 2);
lua_rawseti(pState->L,
pState->metatables[static_cast<size_t>(lua_metatable::anim)], 2);
// Anim
{
lua_class_binding<animation> lcb(pState, "animation", l_anim_new<animation>, lua_metatable::anim);
lua_class_binding<animation> lcb(pState, "animation", l_anim_new<animation>,
lua_metatable::anim);
lcb.add_metamethod(l_anim_persist<animation>, "persist");
lcb.add_metamethod(l_anim_pre_depersist<animation>, "pre_depersist");
lcb.add_metamethod(l_anim_depersist<animation>, "depersist");
@@ -724,31 +703,44 @@ void lua_register_anims(const lua_register_state *pState)
}
// Duplicate AnimMetatable[1,2] to SpriteListMetatable[1,2]
lua_rawgeti(pState->L, pState->metatables[static_cast<size_t>(lua_metatable::anim)], 1);
lua_rawseti(pState->L, pState->metatables[static_cast<size_t>(lua_metatable::sprite_list)], 1);
lua_rawgeti(pState->L, pState->metatables[static_cast<size_t>(lua_metatable::anim)], 2);
lua_rawseti(pState->L, pState->metatables[static_cast<size_t>(lua_metatable::sprite_list)], 2);
lua_rawgeti(pState->L,
pState->metatables[static_cast<size_t>(lua_metatable::anim)], 1);
lua_rawseti(
pState->L,
pState->metatables[static_cast<size_t>(lua_metatable::sprite_list)], 1);
lua_rawgeti(pState->L,
pState->metatables[static_cast<size_t>(lua_metatable::anim)], 2);
lua_rawseti(
pState->L,
pState->metatables[static_cast<size_t>(lua_metatable::sprite_list)], 2);
// SpriteList
{
lua_class_binding<sprite_render_list> lcb(pState, "spriteList", l_anim_new<sprite_render_list>, lua_metatable::sprite_list);
lua_class_binding<sprite_render_list> lcb(pState, "spriteList",
l_anim_new<sprite_render_list>,
lua_metatable::sprite_list);
lcb.add_metamethod(l_anim_persist<sprite_render_list>, "persist");
lcb.add_metamethod(l_anim_pre_depersist<sprite_render_list>, "pre_depersist");
lcb.add_metamethod(l_anim_pre_depersist<sprite_render_list>,
"pre_depersist");
lcb.add_metamethod(l_anim_depersist<sprite_render_list>, "depersist");
lcb.add_function(l_srl_set_sheet, "setSheet", lua_metatable::sheet);
lcb.add_function(l_srl_append, "append");
lcb.add_function(l_srl_set_lifetime, "setLifetime");
lcb.add_function(l_srl_is_dead, "isDead");
lcb.add_function(l_anim_set_tile<sprite_render_list>, "setTile", lua_metatable::map);
lcb.add_function(l_anim_set_tile<sprite_render_list>, "setTile",
lua_metatable::map);
lcb.add_function(l_anim_set_flag<sprite_render_list>, "setFlag");
lcb.add_function(l_anim_set_flag_partial<sprite_render_list>, "setPartialFlag");
lcb.add_function(l_anim_set_flag_partial<sprite_render_list>,
"setPartialFlag");
lcb.add_function(l_anim_get_flag<sprite_render_list>, "getFlag");
lcb.add_function(l_anim_make_visible<sprite_render_list>, "makeVisible");
lcb.add_function(l_anim_make_invisible<sprite_render_list>, "makeInvisible");
lcb.add_function(l_anim_make_invisible<sprite_render_list>,
"makeInvisible");
lcb.add_function(l_anim_set_position<sprite_render_list>, "setPosition");
lcb.add_function(l_anim_set_speed<sprite_render_list>, "setSpeed");
lcb.add_function(l_anim_set_layer<sprite_render_list>, "setLayer");
lcb.add_function(l_anim_tick<sprite_render_list>, "tick");
lcb.add_function(l_anim_draw<sprite_render_list>, "draw", lua_metatable::surface);
lcb.add_function(l_anim_draw<sprite_render_list>, "draw",
lua_metatable::surface);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -57,26 +57,27 @@ enum class lua_metatable {
count
};
struct lua_register_state
{
struct lua_register_state {
lua_State* L;
int metatables[static_cast<size_t>(lua_metatable::count)];
int main_table;
int top;
};
void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps);
void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
size_t iUps);
template <typename... Args>
void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps,
lua_metatable eMetatable1, Args... args) {
lua_pushvalue(pState->L, pState->metatables[static_cast<size_t>(eMetatable1)]);
void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
size_t iUps, lua_metatable eMetatable1, Args... args) {
lua_pushvalue(pState->L,
pState->metatables[static_cast<size_t>(eMetatable1)]);
luaT_setclosure(pState, fn, iUps + 1, args...);
}
template <typename... Args>
void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t iUps,
const char* str, Args... args) {
void luaT_setclosure(const lua_register_state* pState, lua_CFunction fn,
size_t iUps, const char* str, Args... args) {
lua_pushstring(pState->L, str);
luaT_setclosure(pState, fn, iUps + 1, args...);
}
@@ -90,8 +91,8 @@ void luaT_setclosure(const lua_register_state *pState, lua_CFunction fn, size_t
* @param args The upvalues to associate with the function in lua
*/
template <typename... Args>
void add_lua_function(const lua_register_state* pState, lua_CFunction fn, const char* name, Args... args)
{
void add_lua_function(const lua_register_state* pState, lua_CFunction fn,
const char* name, Args... args) {
luaT_setclosure(pState, fn, 0, args...);
lua_setfield(pState->L, -2, name);
}
@@ -103,8 +104,7 @@ void add_lua_function(const lua_register_state* pState, lua_CFunction fn, const
* functions, metamethods and constants to complete the creation of the bind.
*/
template <typename T>
class lua_class_binding final
{
class lua_class_binding final {
public:
lua_class_binding() = delete;
lua_class_binding(const lua_class_binding&) = delete;
@@ -120,13 +120,13 @@ public:
* @param new_fn The fuction to call when a new class is created.
* @param mt The metatable id for the class
*/
lua_class_binding(const lua_register_state* pState, const char* name, lua_CFunction new_fn, lua_metatable mt) :
pState(pState),
lua_class_binding(const lua_register_state* pState, const char* name,
lua_CFunction new_fn, lua_metatable mt)
: pState(pState),
class_name(name),
class_metatable(pState->metatables[static_cast<size_t>(mt)])
{
class_metatable(pState->metatables[static_cast<size_t>(mt)]) {
lua_settop(pState->L, pState->top);
/* Make metatable the environment for registered functions */ \
/* Make metatable the environment for registered functions */
lua_pushvalue(pState->L, class_metatable);
lua_replace(pState->L, luaT_environindex);
/* Set the __gc metamethod to C++ destructor */
@@ -152,10 +152,10 @@ public:
*
* @param super_mt The metatable id of the super class.
*/
void set_superclass(lua_metatable super_mt)
{
void set_superclass(lua_metatable super_mt) {
lua_getmetatable(pState->L, -1);
lua_getfield(pState->L, pState->metatables[static_cast<size_t>(super_mt)], "__index");
lua_getfield(pState->L, pState->metatables[static_cast<size_t>(super_mt)],
"__index");
lua_setfield(pState->L, -2, "__index");
lua_pop(pState->L, 1);
/* Set metatable[1] to super_mt */
@@ -170,8 +170,7 @@ public:
* @param value (tested with int) Value of the constant.
*/
template <typename V>
void add_constant(const char* name, V value)
{
void add_constant(const char* name, V value) {
luaT_push(pState->L, value);
lua_setfield(pState->L, -2, name);
}
@@ -184,10 +183,10 @@ public:
* @param args The upvalues for the function.
*/
template <typename... Args>
void add_metamethod(lua_CFunction fn, const char* name, Args... args)
{
void add_metamethod(lua_CFunction fn, const char* name, Args... args) {
luaT_setclosure(pState, fn, 0, args...);
lua_setfield(pState->L, class_metatable, std::string("__").append(name).c_str());
lua_setfield(pState->L, class_metatable,
std::string("__").append(name).c_str());
}
/**
@@ -198,16 +197,14 @@ public:
* @param args The upvalues for the function
*/
template <typename... Args>
void add_function(lua_CFunction fn, const char* name, Args... args)
{
void add_function(lua_CFunction fn, const char* name, Args... args) {
add_lua_function(pState, fn, name, args...);
}
/**
* Destructor which finalizes the lua binding
*/
~lua_class_binding()
{
~lua_class_binding() {
lua_setfield(pState->L, pState->main_table, class_name);
}

View File

@@ -20,52 +20,44 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_lua_internal.h"
#include "iso_fs.h"
#include <cstdio>
#include "iso_fs.h"
#include "th_lua_internal.h"
namespace {
int l_isofs_new(lua_State *L)
{
int l_isofs_new(lua_State* L) {
luaT_stdnew<iso_filesystem>(L, luaT_environindex, true);
return 1;
}
int l_isofs_set_path_separator(lua_State *L)
{
int l_isofs_set_path_separator(lua_State* L) {
iso_filesystem* pSelf = luaT_testuserdata<iso_filesystem>(L);
pSelf->set_path_separator(luaL_checkstring(L, 2)[0]);
lua_settop(L, 1);
return 1;
}
int l_isofs_set_root(lua_State *L)
{
int l_isofs_set_root(lua_State* L) {
iso_filesystem* pSelf = luaT_testuserdata<iso_filesystem>(L);
std::FILE* fIso = *luaT_testuserdata<std::FILE*>(L, 2, false);
if(pSelf->initialise(fIso))
{
if (pSelf->initialise(fIso)) {
lua_pushvalue(L, 2);
luaT_setenvfield(L, 1, "file");
lua_settop(L, 1);
return 1;
}
else
{
} else {
lua_pushnil(L);
lua_pushstring(L, pSelf->get_error());
return 2;
}
}
int l_isofs_file_exists(lua_State *L)
{
int l_isofs_file_exists(lua_State* L) {
iso_filesystem* pSelf = luaT_testuserdata<iso_filesystem>(L);
const char* sFilename = luaL_checkstring(L, 2);
iso_filesystem::file_handle iFile = pSelf->find_file(sFilename);
if(!iso_filesystem::isHandleGood(iFile))
{
if (!iso_filesystem::isHandleGood(iFile)) {
lua_pushnil(L);
lua_pushfstring(L, "Could not find \'%s\' in .iso image", sFilename);
return 2;
@@ -74,13 +66,11 @@ int l_isofs_file_exists(lua_State *L)
return 1;
}
int l_isofs_file_size(lua_State *L)
{
int l_isofs_file_size(lua_State* L) {
iso_filesystem* pSelf = luaT_testuserdata<iso_filesystem>(L);
const char* sFilename = luaL_checkstring(L, 2);
iso_filesystem::file_handle iFile = pSelf->find_file(sFilename);
if(!iso_filesystem::isHandleGood(iFile))
{
if (!iso_filesystem::isHandleGood(iFile)) {
lua_pushnil(L);
lua_pushfstring(L, "Could not find \'%s\' in .iso image", sFilename);
return 2;
@@ -89,38 +79,34 @@ int l_isofs_file_size(lua_State *L)
return 1;
}
int l_isofs_read_contents(lua_State *L)
{
int l_isofs_read_contents(lua_State* L) {
iso_filesystem* pSelf = luaT_testuserdata<iso_filesystem>(L);
const char* sFilename = luaL_checkstring(L, 2);
iso_filesystem::file_handle iFile = pSelf->find_file(sFilename);
if(!iso_filesystem::isHandleGood(iFile))
{
if (!iso_filesystem::isHandleGood(iFile)) {
lua_pushnil(L);
lua_pushfstring(L, "Could not find \'%s\' in .iso image", sFilename);
return 2;
}
void* pBuffer = lua_newuserdata(L, pSelf->get_file_size(iFile));
if(!pSelf->get_file_data(iFile, reinterpret_cast<uint8_t*>(pBuffer)))
{
if (!pSelf->get_file_data(iFile, reinterpret_cast<uint8_t*>(pBuffer))) {
lua_pushnil(L);
lua_pushstring(L, pSelf->get_error());
return 2;
}
lua_pushlstring(L, reinterpret_cast<char*>(pBuffer), pSelf->get_file_size(iFile));
lua_pushlstring(L, reinterpret_cast<char*>(pBuffer),
pSelf->get_file_size(iFile));
return 1;
}
void l_isofs_list_files_callback(void *p, const char* name, const char* path)
{
void l_isofs_list_files_callback(void* p, const char* name, const char* path) {
lua_State* L = reinterpret_cast<lua_State*>(p);
lua_pushstring(L, name);
lua_pushstring(L, path);
lua_settable(L, 3);
}
int l_isofs_list_files(lua_State *L)
{
int l_isofs_list_files(lua_State* L) {
iso_filesystem* pSelf = luaT_testuserdata<iso_filesystem>(L);
const char* sPath = luaL_checkstring(L, 2);
lua_settop(L, 2);
@@ -131,9 +117,9 @@ int l_isofs_list_files(lua_State *L)
} // namespace
void lua_register_iso_fs(const lua_register_state* pState)
{
lua_class_binding<iso_filesystem> lcb(pState, "iso_fs", l_isofs_new, lua_metatable::iso_fs);
void lua_register_iso_fs(const lua_register_state* pState) {
lua_class_binding<iso_filesystem> lcb(pState, "iso_fs", l_isofs_new,
lua_metatable::iso_fs);
lcb.add_function(l_isofs_set_path_separator, "setPathSeparator");
lcb.add_function(l_isofs_set_root, "setRoot");
lcb.add_function(l_isofs_file_exists, "fileExists");

View File

@@ -21,8 +21,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_lua_internal.h"
#include "config.h"
#include "th_lua_internal.h"
#ifdef CORSIX_TH_USE_WIN32_SDK
#include <windows.h>
#endif
@@ -31,29 +31,24 @@ class lfs_ext {};
namespace {
int l_lfs_ext_new(lua_State *L)
{
int l_lfs_ext_new(lua_State* L) {
luaT_stdnew<lfs_ext>(L, luaT_environindex, true);
return 1;
}
#ifdef _WIN32
#ifdef CORSIX_TH_USE_WIN32_SDK
int l_volume_list(lua_State *L)
{
int l_volume_list(lua_State* L) {
/* Windows, using the Win32 API. */
DWORD iDriveMask = GetLogicalDrives();
int iNDrives = 0;
char cDrive;
lua_settop(L, 0);
lua_newtable(L);
for (cDrive = 'A'; cDrive <= 'Z'; ++cDrive)
{
if (iDriveMask & (1 << (cDrive - 'A')))
{
for (cDrive = 'A'; cDrive <= 'Z'; ++cDrive) {
if (iDriveMask & (1 << (cDrive - 'A'))) {
char sName[4] = {cDrive, ':', '\\', 0};
if (GetDriveTypeA(sName) > DRIVE_NO_ROOT_DIR)
{
if (GetDriveTypeA(sName) > DRIVE_NO_ROOT_DIR) {
lua_pushlstring(L, sName, 2);
lua_rawseti(L, 1, ++iNDrives);
}
@@ -62,22 +57,19 @@ int l_volume_list(lua_State *L)
return 1;
}
#else
int l_volume_list(lua_State *L)
{
int l_volume_list(lua_State* L) {
/* Windows, without the Win32 API. */
int iNDrives = 0;
char cDrive;
lua_settop(L, 0);
lua_newtable(L);
lua_getfield(L, luaT_upvalueindex(1), "attributes");
for (cDrive = 'A'; cDrive <= 'Z'; ++cDrive)
{
for (cDrive = 'A'; cDrive <= 'Z'; ++cDrive) {
lua_pushvalue(L, 2);
lua_pushfstring(L, "%c:\\", cDrive);
lua_pushliteral(L, "mode");
lua_call(L, 2, 1);
if (lua_toboolean(L, 3) != 0)
{
if (lua_toboolean(L, 3) != 0) {
lua_pushfstring(L, "%c:", cDrive);
lua_rawseti(L, 1, ++iNDrives);
}
@@ -87,8 +79,7 @@ int l_volume_list(lua_State *L)
}
#endif
#else
int l_volume_list(lua_State *L)
{
int l_volume_list(lua_State* L) {
/* Non-Windows systems. Assume that / is the root of the filesystem. */
lua_settop(L, 0);
lua_newtable(L);
@@ -100,8 +91,8 @@ int l_volume_list(lua_State *L)
} // namespace
void lua_register_lfs_ext(const lua_register_state *pState)
{
lua_class_binding<lfs_ext> lcb(pState, "lfsExt", l_lfs_ext_new, lua_metatable::lfs_ext);
void lua_register_lfs_ext(const lua_register_state* pState) {
lua_class_binding<lfs_ext> lcb(pState, "lfsExt", l_lfs_ext_new,
lua_metatable::lfs_ext);
lcb.add_function(l_volume_list, "volumes");
}

File diff suppressed because it is too large Load Diff

View File

@@ -20,35 +20,31 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_gfx.h"
#include "th_lua_internal.h"
#include "th_movie.h"
#include "th_gfx.h"
namespace {
int l_movie_new(lua_State *L)
{
int l_movie_new(lua_State* L) {
luaT_stdnew<movie_player>(L, luaT_environindex, true);
return 1;
}
int l_movie_set_renderer(lua_State *L)
{
int l_movie_set_renderer(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
render_target* pRenderTarget = luaT_testuserdata<render_target>(L, 2);
pMovie->set_renderer(pRenderTarget->get_renderer());
return 0;
}
int l_movie_enabled(lua_State *L)
{
int l_movie_enabled(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
lua_pushboolean(L, pMovie->movies_enabled());
return 1;
}
int l_movie_load(lua_State *L)
{
int l_movie_load(lua_State* L) {
bool loaded;
const char* warning;
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
@@ -61,73 +57,62 @@ int l_movie_load(lua_State *L)
return 2;
}
int l_movie_unload(lua_State *L)
{
int l_movie_unload(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
pMovie->unload();
return 0;
}
int l_movie_play(lua_State *L)
{
int l_movie_play(lua_State* L) {
const char* warning;
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
pMovie->clear_last_error();
pMovie->play(
static_cast<int>(luaL_checkinteger(L, 2)));
pMovie->play(static_cast<int>(luaL_checkinteger(L, 2)));
warning = pMovie->get_last_error();
lua_pushstring(L, warning);
return 1;
}
int l_movie_stop(lua_State *L)
{
int l_movie_stop(lua_State* L) {
movie_player* pVideo = luaT_testuserdata<movie_player>(L);
pVideo->stop();
return 0;
}
int l_movie_get_native_height(lua_State *L)
{
int l_movie_get_native_height(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
lua_pushinteger(L, pMovie->get_native_height());
return 1;
}
int l_movie_get_native_width(lua_State *L)
{
int l_movie_get_native_width(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
lua_pushinteger(L, pMovie->get_native_width());
return 1;
}
int l_movie_has_audio_track(lua_State *L)
{
int l_movie_has_audio_track(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
lua_pushboolean(L, pMovie->has_audio_track());
return 1;
}
int l_movie_refresh(lua_State *L)
{
int l_movie_refresh(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
pMovie->refresh(SDL_Rect{
static_cast<int>(luaL_checkinteger(L, 2)),
pMovie->refresh(SDL_Rect{static_cast<int>(luaL_checkinteger(L, 2)),
static_cast<int>(luaL_checkinteger(L, 3)),
static_cast<int>(luaL_checkinteger(L, 4)),
static_cast<int>(luaL_checkinteger(L, 5))});
return 0;
}
int l_movie_allocate_picture_buffer(lua_State *L)
{
int l_movie_allocate_picture_buffer(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
pMovie->allocate_picture_buffer();
return 0;
}
int l_movie_deallocate_picture_buffer(lua_State *L)
{
int l_movie_deallocate_picture_buffer(lua_State* L) {
movie_player* pMovie = luaT_testuserdata<movie_player>(L);
pMovie->deallocate_picture_buffer();
return 0;
@@ -135,9 +120,9 @@ int l_movie_deallocate_picture_buffer(lua_State *L)
} // namespace
void lua_register_movie(const lua_register_state *pState)
{
lua_class_binding<movie_player> lcb(pState, "moviePlayer", l_movie_new, lua_metatable::movie);
void lua_register_movie(const lua_register_state* pState) {
lua_class_binding<movie_player> lcb(pState, "moviePlayer", l_movie_new,
lua_metatable::movie);
lcb.add_function(l_movie_set_renderer, "setRenderer", lua_metatable::surface);
lcb.add_function(l_movie_enabled, "getEnabled");
lcb.add_function(l_movie_load, "load");
@@ -149,5 +134,6 @@ void lua_register_movie(const lua_register_state *pState)
lcb.add_function(l_movie_has_audio_track, "hasAudioTrack");
lcb.add_function(l_movie_refresh, "refresh");
lcb.add_function(l_movie_allocate_picture_buffer, "allocatePictureBuffer");
lcb.add_function(l_movie_deallocate_picture_buffer, "deallocatePictureBuffer");
lcb.add_function(l_movie_deallocate_picture_buffer,
"deallocatePictureBuffer");
}

View File

@@ -20,13 +20,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_lua_internal.h"
#include "th_sound.h"
#include "th_lua.h"
#include "lua_sdl.h"
#include <cctype>
#include <cstring>
#include <map>
#include <cctype>
#include "lua_sdl.h"
#include "th_lua.h"
#include "th_lua_internal.h"
#include "th_sound.h"
namespace {
@@ -34,14 +34,12 @@ int played_sound_callback_ids[1000];
int played_sound_callback_index = 0;
std::map<int, SDL_TimerID> map_sound_timers;
int l_soundarc_new(lua_State *L)
{
int l_soundarc_new(lua_State* L) {
luaT_stdnew<sound_archive>(L, luaT_environindex, true);
return 1;
}
int l_soundarc_load(lua_State *L)
{
int l_soundarc_load(lua_State* L) {
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L);
size_t iDataLen;
const uint8_t* pData = luaT_checkfile(L, 2, &iDataLen);
@@ -53,8 +51,7 @@ int l_soundarc_load(lua_State *L)
return 1;
}
int l_soundarc_count(lua_State *L)
{
int l_soundarc_count(lua_State* L) {
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L);
lua_pushnumber(L, (lua_Number)pArchive->get_number_of_sounds());
return 1;
@@ -67,12 +64,9 @@ int l_soundarc_count(lua_State *L)
* @return Negative number when \a s1 should be before \a s2, zero if both
* string are equal, else a positive number.
*/
int ignorecase_cmp(const char *s1, const char *s2)
{
while(*s1 && *s2)
{
if (std::tolower(*s1) != std::tolower(*s2))
break;
int ignorecase_cmp(const char* s1, const char* s2) {
while (*s1 && *s2) {
if (std::tolower(*s1) != std::tolower(*s2)) break;
s1++;
s2++;
@@ -80,16 +74,15 @@ int ignorecase_cmp(const char *s1, const char *s2)
return std::tolower(*s1) - std::tolower(*s2);
}
size_t l_soundarc_checkidx(lua_State *L, int iArg, sound_archive* pArchive)
{
if(lua_isnumber(L, iArg))
{
size_t l_soundarc_checkidx(lua_State* L, int iArg, sound_archive* pArchive) {
if (lua_isnumber(L, iArg)) {
size_t iIndex = (size_t)lua_tonumber(L, iArg);
if(iIndex >= pArchive->get_number_of_sounds())
{
if (iIndex >= pArchive->get_number_of_sounds()) {
lua_pushnil(L);
lua_pushfstring(L, "Sound index out of "
"bounds (%f is not in range [0, %d])", lua_tonumber(L, iArg),
lua_pushfstring(L,
"Sound index out of "
"bounds (%f is not in range [0, %d])",
lua_tonumber(L, iArg),
static_cast<int>(pArchive->get_number_of_sounds()) - 1);
return pArchive->get_number_of_sounds();
}
@@ -99,18 +92,15 @@ size_t l_soundarc_checkidx(lua_State *L, int iArg, sound_archive* pArchive)
lua_getfenv(L, 1);
lua_pushvalue(L, iArg);
lua_rawget(L, -2);
if(lua_type(L, -1) == LUA_TLIGHTUSERDATA)
{
if (lua_type(L, -1) == LUA_TLIGHTUSERDATA) {
size_t iIndex = (size_t)lua_topointer(L, -1);
lua_pop(L, 2);
return iIndex;
}
lua_pop(L, 2);
size_t iCount = pArchive->get_number_of_sounds();
for(size_t i = 0; i < iCount; ++i)
{
if(ignorecase_cmp(sName, pArchive->get_sound_name(i)) == 0)
{
for (size_t i = 0; i < iCount; ++i) {
if (ignorecase_cmp(sName, pArchive->get_sound_name(i)) == 0) {
lua_getfenv(L, 1);
lua_pushvalue(L, iArg);
lua_pushlightuserdata(L, (void*)i);
@@ -126,36 +116,30 @@ size_t l_soundarc_checkidx(lua_State *L, int iArg, sound_archive* pArchive)
return pArchive->get_number_of_sounds();
}
int l_soundarc_sound_name(lua_State *L)
{
int l_soundarc_sound_name(lua_State* L) {
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L);
size_t iIndex = l_soundarc_checkidx(L, 2, pArchive);
if(iIndex == pArchive->get_number_of_sounds())
return 2;
if (iIndex == pArchive->get_number_of_sounds()) return 2;
lua_pushstring(L, pArchive->get_sound_name(iIndex));
return 1;
}
int l_soundarc_duration(lua_State *L)
{
int l_soundarc_duration(lua_State* L) {
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L);
size_t iIndex = l_soundarc_checkidx(L, 2, pArchive);
if(iIndex == pArchive->get_number_of_sounds())
return 2;
if (iIndex == pArchive->get_number_of_sounds()) return 2;
size_t iDuration = pArchive->get_sound_duration(iIndex);
lua_pushnumber(L, static_cast<lua_Number>(iDuration) / static_cast<lua_Number>(1000));
lua_pushnumber(
L, static_cast<lua_Number>(iDuration) / static_cast<lua_Number>(1000));
return 1;
}
int l_soundarc_data(lua_State *L)
{
int l_soundarc_data(lua_State* L) {
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L);
size_t iIndex = l_soundarc_checkidx(L, 2, pArchive);
if(iIndex == pArchive->get_number_of_sounds())
return 2;
if (iIndex == pArchive->get_number_of_sounds()) return 2;
SDL_RWops* pRWops = pArchive->load_sound(iIndex);
if(!pRWops)
return 0;
if (!pRWops) return 0;
size_t iLength = SDL_RWseek(pRWops, 0, SEEK_END);
SDL_RWseek(pRWops, 0, SEEK_SET);
// There is a potential leak of pRWops if either of these Lua calls cause
@@ -168,8 +152,7 @@ int l_soundarc_data(lua_State *L)
return 1;
}
int l_soundarc_sound_exists(lua_State *L)
{
int l_soundarc_sound_exists(lua_State* L) {
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L);
size_t iIndex = l_soundarc_checkidx(L, 2, pArchive);
if (iIndex == pArchive->get_number_of_sounds())
@@ -179,14 +162,12 @@ int l_soundarc_sound_exists(lua_State *L)
return 1;
}
int l_soundfx_new(lua_State *L)
{
int l_soundfx_new(lua_State* L) {
luaT_stdnew<sound_player>(L, luaT_environindex, true);
return 1;
}
int l_soundfx_set_archive(lua_State *L)
{
int l_soundfx_set_archive(lua_State* L) {
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
sound_archive* pArchive = luaT_testuserdata<sound_archive>(L, 2);
pEffects->populate_from(pArchive);
@@ -195,22 +176,19 @@ int l_soundfx_set_archive(lua_State *L)
return 1;
}
int l_soundfx_set_sound_volume(lua_State *L)
{
int l_soundfx_set_sound_volume(lua_State* L) {
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
pEffects->set_sound_effect_volume(luaL_checknumber(L, 2));
return 1;
}
int l_soundfx_set_sound_effects_on(lua_State *L)
{
int l_soundfx_set_sound_effects_on(lua_State* L) {
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
pEffects->set_sound_effects_enabled(lua_toboolean(L, 2) != 0);
return 1;
}
Uint32 played_sound_callback(Uint32 interval, void* param)
{
Uint32 played_sound_callback(Uint32 interval, void* param) {
SDL_Event e;
e.type = SDL_USEREVENT_SOUND_OVER;
e.user.data1 = param;
@@ -222,35 +200,30 @@ Uint32 played_sound_callback(Uint32 interval, void* param)
return interval;
}
int l_soundfx_play(lua_State *L)
{
int l_soundfx_play(lua_State* L) {
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
lua_settop(L, 7);
lua_getfenv(L, 1);
lua_pushliteral(L, "archive");
lua_rawget(L, 8);
sound_archive* pArchive = (sound_archive*)lua_touserdata(L, 9);
if(pArchive == nullptr)
{
if (pArchive == nullptr) {
return 0;
}
// l_soundarc_checkidx requires the archive at the bottom of the stack
lua_replace(L, 1);
size_t iIndex = l_soundarc_checkidx(L, 2, pArchive);
if(iIndex == pArchive->get_number_of_sounds())
return 2;
if(lua_isnil(L, 4))
{
if (iIndex == pArchive->get_number_of_sounds()) return 2;
if (lua_isnil(L, 4)) {
pEffects->play(iIndex, luaL_checknumber(L, 3));
}
else
{
pEffects->play_at(iIndex, luaL_checknumber(L, 3), static_cast<int>(luaL_checkinteger(L, 4)), static_cast<int>(luaL_checkinteger(L, 5)));
} else {
pEffects->play_at(iIndex, luaL_checknumber(L, 3),
static_cast<int>(luaL_checkinteger(L, 4)),
static_cast<int>(luaL_checkinteger(L, 5)));
}
// SDL SOUND_OVER Callback Timer:
// 6: unusedPlayedCallbackID
if(!lua_isnil(L, 6))
{
if (!lua_isnil(L, 6)) {
// 7: Callback delay
int iPlayedCallbackDelay = 0; // ms
if (!lua_isnil(L, 7))
@@ -259,12 +232,15 @@ int l_soundfx_play(lua_State *L)
if (played_sound_callback_index == sizeof(played_sound_callback_ids))
played_sound_callback_index = 0;
played_sound_callback_ids[played_sound_callback_index] = static_cast<int>(luaL_checkinteger(L, 6));
size_t interval = pArchive->get_sound_duration(iIndex) + iPlayedCallbackDelay;
SDL_TimerID timersID = SDL_AddTimer(static_cast<Uint32>(interval),
played_sound_callback,
played_sound_callback_ids[played_sound_callback_index] =
static_cast<int>(luaL_checkinteger(L, 6));
size_t interval =
pArchive->get_sound_duration(iIndex) + iPlayedCallbackDelay;
SDL_TimerID timersID =
SDL_AddTimer(static_cast<Uint32>(interval), played_sound_callback,
&(played_sound_callback_ids[played_sound_callback_index]));
map_sound_timers.insert(std::pair<int, SDL_TimerID>(played_sound_callback_ids[played_sound_callback_index], timersID));
map_sound_timers.insert(std::pair<int, SDL_TimerID>(
played_sound_callback_ids[played_sound_callback_index], timersID));
played_sound_callback_index++;
}
@@ -272,15 +248,15 @@ int l_soundfx_play(lua_State *L)
return 1;
}
int l_soundfx_set_camera(lua_State *L)
{
int l_soundfx_set_camera(lua_State* L) {
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
pEffects->set_camera(static_cast<int>(luaL_checkinteger(L, 2)), static_cast<int>(luaL_checkinteger(L, 3)), static_cast<int>(luaL_checkinteger(L, 4)));
pEffects->set_camera(static_cast<int>(luaL_checkinteger(L, 2)),
static_cast<int>(luaL_checkinteger(L, 3)),
static_cast<int>(luaL_checkinteger(L, 4)));
return 0;
}
int l_soundfx_reserve_channel(lua_State *L)
{
int l_soundfx_reserve_channel(lua_State* L) {
int iChannel;
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
iChannel = pEffects->reserve_channel();
@@ -288,8 +264,7 @@ int l_soundfx_reserve_channel(lua_State *L)
return 1;
}
int l_soundfx_release_channel(lua_State *L)
{
int l_soundfx_release_channel(lua_State* L) {
sound_player* pEffects = luaT_testuserdata<sound_player>(L);
pEffects->release_channel(static_cast<int>(luaL_checkinteger(L, 2)));
return 1;
@@ -297,23 +272,27 @@ int l_soundfx_release_channel(lua_State *L)
} // namespace
void lua_register_sound(const lua_register_state *pState)
{
void lua_register_sound(const lua_register_state* pState) {
// Sound Archive
{
lua_class_binding<sound_archive> lcb(pState, "soundArchive", l_soundarc_new, lua_metatable::sound_archive);
lua_class_binding<sound_archive> lcb(pState, "soundArchive", l_soundarc_new,
lua_metatable::sound_archive);
lcb.add_metamethod(l_soundarc_count, "len");
lcb.add_function(l_soundarc_load, "load");
lcb.add_function(l_soundarc_sound_name, "getFilename"); // Bad name, doesn't represent a file
lcb.add_function(l_soundarc_sound_name,
"getFilename"); // Bad name, doesn't represent a file
lcb.add_function(l_soundarc_duration, "getDuration");
lcb.add_function(l_soundarc_data, "getFileData"); // Bad name, doesn't represent a file
lcb.add_function(l_soundarc_data,
"getFileData"); // Bad name, doesn't represent a file
lcb.add_function(l_soundarc_sound_exists, "soundExists");
}
// Sound Effects
{
lua_class_binding<sound_player> lcb(pState, "soundEffects", l_soundfx_new, lua_metatable::sound_fx);
lcb.add_function(l_soundfx_set_archive, "setSoundArchive", lua_metatable::sound_archive);
lua_class_binding<sound_player> lcb(pState, "soundEffects", l_soundfx_new,
lua_metatable::sound_fx);
lcb.add_function(l_soundfx_set_archive, "setSoundArchive",
lua_metatable::sound_archive);
lcb.add_function(l_soundfx_play, "play");
lcb.add_function(l_soundfx_set_sound_volume, "setSoundVolume");
lcb.add_function(l_soundfx_set_sound_effects_on, "setSoundEffectsOn");

View File

@@ -20,9 +20,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_lua_internal.h"
#include "persist_lua.h"
#include <cstring>
#include "persist_lua.h"
#include "th_lua_internal.h"
/*
This file implements a string proxy system. A string proxy is a userdata
@@ -59,15 +59,13 @@ namespace {
// which we get by having 2 bytes of dummy global variables.
uint8_t weak_table_keys[2] = {0};
inline void aux_push_weak_table(lua_State *L, int iIndex)
{
inline void aux_push_weak_table(lua_State* L, int iIndex) {
lua_pushlightuserdata(L, &weak_table_keys[iIndex]);
lua_rawget(L, LUA_REGISTRYINDEX);
}
// Replace the value at the top of the stack with a userdata proxy
int l_str_new_aux(lua_State *L)
{
int l_str_new_aux(lua_State* L) {
luaT_stdnew<string_proxy>(L);
aux_push_weak_table(L, 0);
lua_pushvalue(L, -2);
@@ -79,14 +77,12 @@ int l_str_new_aux(lua_State *L)
}
// Create a new root-level userdata proxy
int l_str_new(lua_State *L)
{
int l_str_new(lua_State* L) {
// Pack extra arguments into a table
int iNArgs = lua_gettop(L);
lua_createtable(L, iNArgs - 2, 0);
lua_replace(L, 1); // Value inserted by __call
for(int i = iNArgs; i >= 3; --i)
lua_rawseti(L, 1, i - 2);
for (int i = iNArgs; i >= 3; --i) lua_rawseti(L, 1, i - 2);
// Make proxy
luaL_checkany(L, 2);
@@ -99,22 +95,18 @@ int l_str_new(lua_State *L)
}
// Helper function to make an array in Lua
void aux_mk_table(lua_State *L, int nliterals, int nvalues, ...)
{
void aux_mk_table(lua_State* L, int nliterals, int nvalues, ...) {
lua_createtable(L, nliterals + nvalues, 0);
va_list args;
va_start(args, nvalues);
for(int i = 1; i <= nliterals; ++i)
{
for (int i = 1; i <= nliterals; ++i) {
const char* sStr = va_arg(args, const char*);
lua_pushstring(L, sStr);
lua_rawseti(L, -2, i);
}
for(int i = nliterals + 1; i <= nliterals + nvalues; ++i)
{
for (int i = nliterals + 1; i <= nliterals + nvalues; ++i) {
int iValue = va_arg(args, int);
if(0 > iValue && iValue > LUA_REGISTRYINDEX)
--iValue;
if (0 > iValue && iValue > LUA_REGISTRYINDEX) --iValue;
lua_pushvalue(L, iValue);
lua_rawseti(L, -2, i);
}
@@ -123,22 +115,19 @@ void aux_mk_table(lua_State *L, int nliterals, int nvalues, ...)
// Helper function which pushes onto the stack a random key from the table
// (previously) on the top of the stack.
void aux_push_random_key(lua_State *L)
{
void aux_push_random_key(lua_State* L) {
int iNKeys = 0;
lua_newtable(L);
lua_getglobal(L, "pairs");
lua_pushvalue(L, -3);
lua_call(L, 1, 3);
while(true)
{
while (true) {
lua_pushvalue(L, -3);
lua_pushvalue(L, -3);
lua_pushvalue(L, -3);
lua_remove(L, -4);
lua_call(L, 2, 1);
if(lua_isnil(L, -1))
break;
if (lua_isnil(L, -1)) break;
++iNKeys;
lua_pushvalue(L, -1);
lua_rawseti(L, -5, iNKeys);
@@ -157,8 +146,7 @@ void aux_push_random_key(lua_State *L)
// __index metamethod handler.
// For proxied tables, return proxies of children, preferably cached
// For proxied strings, return methods
int l_str_index(lua_State *L)
{
int l_str_index(lua_State* L) {
// Look up cached value, and return it if present
aux_push_weak_table(L, 1);
lua_pushvalue(L, 1);
@@ -166,8 +154,7 @@ int l_str_index(lua_State *L)
lua_replace(L, 3);
lua_pushvalue(L, 2);
lua_rawget(L, 3);
if(!lua_isnil(L, 4))
return 1;
if (!lua_isnil(L, 4)) return 1;
lua_pop(L, 1);
// Fetch the proxied value
@@ -177,8 +164,7 @@ int l_str_index(lua_State *L)
lua_replace(L, 4);
// Handle string methods
if(lua_type(L, 4) == LUA_TSTRING)
{
if (lua_type(L, 4) == LUA_TSTRING) {
lua_rawgeti(L, luaT_environindex, 4);
lua_pushvalue(L, 2);
lua_gettable(L, 5);
@@ -186,12 +172,10 @@ int l_str_index(lua_State *L)
}
// Handle __random, as it shouldn't be cached
if(lua_type(L, 2) == LUA_TSTRING)
{
if (lua_type(L, 2) == LUA_TSTRING) {
size_t iLen;
const char* sKey = lua_tolstring(L, 2, &iLen);
if(iLen == 8 && std::strcmp(sKey, "__random") == 0)
{
if (iLen == 8 && std::strcmp(sKey, "__random") == 0) {
aux_push_random_key(L);
lua_replace(L, 2);
lua_settop(L, 2);
@@ -217,15 +201,13 @@ int l_str_index(lua_State *L)
}
// __newindex metamethod handler
int l_str_newindex(lua_State *L)
{
int l_str_newindex(lua_State* L) {
return luaL_error(L, "String tables are read-only");
}
// Generic string method handler
// The name of the method is stored at upvalue 1
int l_str_func(lua_State *L)
{
int l_str_func(lua_State* L) {
int iArgCount = lua_gettop(L);
lua_checkstack(L, iArgCount + 10);
@@ -233,11 +215,9 @@ int l_str_func(lua_State *L)
// Construct the resulting value
aux_push_weak_table(L, 0);
for(int i = 1; i <= iArgCount; ++i)
{
for (int i = 1; i <= iArgCount; ++i) {
lua_pushvalue(L, i);
if(lua_type(L, i) == LUA_TUSERDATA)
{
if (lua_type(L, i) == LUA_TUSERDATA) {
lua_rawget(L, iArgCount + 1);
++iUserdataCount;
}
@@ -248,8 +228,7 @@ int l_str_func(lua_State *L)
lua_call(L, iArgCount, 1);
// Trivial case of result not depending upon any proxies
if(iUserdataCount == 0)
return 1;
if (iUserdataCount == 0) return 1;
// Wrap result in a proxy
l_str_new_aux(L);
@@ -258,8 +237,7 @@ int l_str_func(lua_State *L)
lua_createtable(L, iArgCount + 1, 0);
lua_pushvalue(L, luaT_upvalueindex(1));
lua_rawseti(L, -2, 1);
for(int i = 1; i <= iArgCount; ++i)
{
for (int i = 1; i <= iArgCount; ++i) {
lua_pushvalue(L, i);
lua_rawseti(L, -2, i + 1);
}
@@ -270,8 +248,7 @@ int l_str_func(lua_State *L)
// __concat metamethod handler
// Simple (but inefficient) handling by converting concat into format
int l_str_concat(lua_State *L)
{
int l_str_concat(lua_State* L) {
int iParent = (lua_type(L, 1) == LUA_TUSERDATA) ? 1 : 2;
lua_getfield(L, iParent, "format");
lua_insert(L, 1);
@@ -282,8 +259,7 @@ int l_str_concat(lua_State *L)
}
// pairs() metamethod handler
int l_str_pairs(lua_State *L)
{
int l_str_pairs(lua_State* L) {
lua_settop(L, 1);
lua_getfield(L, luaT_environindex, "__next");
lua_pushvalue(L, 1);
@@ -292,8 +268,7 @@ int l_str_pairs(lua_State *L)
}
// ipairs() metamethod handler
int l_str_ipairs(lua_State *L)
{
int l_str_ipairs(lua_State* L) {
lua_settop(L, 1);
lua_getfield(L, luaT_environindex, "__inext");
lua_pushvalue(L, 1);
@@ -302,8 +277,7 @@ int l_str_ipairs(lua_State *L)
}
// pairs() iterator function
int l_str_next(lua_State *L)
{
int l_str_next(lua_State* L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_settop(L, 2);
@@ -322,8 +296,7 @@ int l_str_next(lua_State *L)
// Get the next key
lua_pushvalue(L, 2);
lua_call(L, 2, 1);
if(lua_isnil(L, -1))
return 0;
if (lua_isnil(L, -1)) return 0;
// Get the (proxied) value which goes with the key
lua_pushvalue(L, -1);
@@ -332,8 +305,7 @@ int l_str_next(lua_State *L)
}
// __len metamethod handler
int l_str_len(lua_State *L)
{
int l_str_len(lua_State* L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
// Fetch proxied value
@@ -343,8 +315,7 @@ int l_str_len(lua_State *L)
// String tables are proxied in Lua, and Lua tables do not honour __len
// so use ipairs to get the unproxied table to call __len on.
if(lua_type(L, -1) == LUA_TTABLE)
{
if (lua_type(L, -1) == LUA_TTABLE) {
lua_getglobal(L, "ipairs");
lua_insert(L, -2);
lua_call(L, 1, 2);
@@ -356,15 +327,13 @@ int l_str_len(lua_State *L)
}
// ipairs() iterator function
int l_str_inext(lua_State *L)
{
int l_str_inext(lua_State* L) {
lua_Integer n = luaL_checkinteger(L, 2) + 1;
lua_settop(L, 1);
l_str_len(L);
lua_Integer len = lua_tointeger(L, -1);
if(n > len)
return 0;
if (n > len) return 0;
// Fetch proxied value
lua_settop(L, 2);
@@ -379,8 +348,7 @@ int l_str_inext(lua_State *L)
}
// tostring() metamethod handler for debugging / diagnostics
int l_str_tostring(lua_State *L)
{
int l_str_tostring(lua_State* L) {
// Convert the proxy to a string, recursively calling tostring()
lua_settop(L, 1);
aux_push_weak_table(L, 0);
@@ -388,8 +356,7 @@ int l_str_tostring(lua_State *L)
lua_rawget(L, 2);
if (lua_isnil(L, 3))
lua_pop(L, 2);
else
{
else {
lua_replace(L, 1);
lua_pop(L, 1);
}
@@ -406,8 +373,7 @@ int l_str_tostring(lua_State *L)
// __call metamethod handler
// Required to support the compatibility hack for calling _S
int l_str_call(lua_State *L)
{
int l_str_call(lua_State* L) {
luaL_checkany(L, 1);
// Fetch the proxied value
@@ -427,8 +393,7 @@ int l_str_call(lua_State *L)
// to create nice user-interface listing of strings. Note that this will mean
// that persist->change language->depersist will result in a "random" ordering
// of the resulting list, but this is generally acceptable.
int l_str_lt(lua_State *L)
{
int l_str_lt(lua_State* L) {
luaL_checkany(L, 1);
luaL_checkany(L, 2);
lua_settop(L, 2);
@@ -442,8 +407,7 @@ int l_str_lt(lua_State *L)
}
// __persist metamethod handler
int l_str_persist(lua_State *L)
{
int l_str_persist(lua_State* L) {
lua_settop(L, 2);
lua_insert(L, 1);
lua_persist_writer* pWriter = (lua_persist_writer*)lua_touserdata(L, 1);
@@ -456,8 +420,7 @@ int l_str_persist(lua_State *L)
// If there were no instructions (i.e. for the root object) then write the
// value as well.
if(lua_objlen(L, -1) == 0)
{
if (lua_objlen(L, -1) == 0) {
lua_pop(L, 2);
aux_push_weak_table(L, 0);
lua_pushvalue(L, 2);
@@ -468,30 +431,24 @@ int l_str_persist(lua_State *L)
}
// __depersist metamethod handler
int l_str_depersist(lua_State *L)
{
int l_str_depersist(lua_State* L) {
lua_settop(L, 2);
lua_insert(L, 1);
lua_persist_reader* pReader = (lua_persist_reader*)lua_touserdata(L, 1);
// Read the instructions for re-creating the value
if(!pReader->read_stack_object())
return 0;
if(lua_type(L, 3) == LUA_TBOOLEAN && lua_toboolean(L, 3) == 1)
{
if (!pReader->read_stack_object()) return 0;
if (lua_type(L, 3) == LUA_TBOOLEAN && lua_toboolean(L, 3) == 1) {
// The current code uses a boolean marker to indicate that the
// instructions were stored in the environment. Replace the marker
// with them.
lua_getfenv(L, 2);
lua_replace(L, 3);
}
else
{
} else {
// Older versions of the code wrote the instructions here, or nil for
// no instructions. Convert nil to the empty table, and store the
// instructions as the userdata's environment.
if(lua_type(L, 3) == LUA_TNIL)
{
if (lua_type(L, 3) == LUA_TNIL) {
lua_newtable(L);
lua_replace(L, 3);
}
@@ -503,42 +460,31 @@ int l_str_depersist(lua_State *L)
aux_push_weak_table(L, 0);
lua_pushvalue(L, 2);
if(lua_objlen(L, 3) == 0)
{
if (lua_objlen(L, 3) == 0) {
// No instructions provided, so read the value itself
if(!pReader->read_stack_object())
return 0;
}
else
{
if (!pReader->read_stack_object()) return 0;
} else {
// The instructions are a table of values; unpack them and replace
// proxies with their values.
bool bIsIndexOperation = false;
int iCount = (int)lua_objlen(L, 3);
lua_checkstack(L, iCount + 1);
for(int i = 1; i <= iCount; ++i)
{
for (int i = 1; i <= iCount; ++i) {
lua_rawgeti(L, 3, i);
if(lua_type(L, -1) == LUA_TUSERDATA)
{
if(i == 1)
bIsIndexOperation = true;
if (lua_type(L, -1) == LUA_TUSERDATA) {
if (i == 1) bIsIndexOperation = true;
lua_rawget(L, 4);
}
}
if(iCount == 2 && bIsIndexOperation)
{
if (iCount == 2 && bIsIndexOperation) {
// If there were two values, and the first was a proxy, then the
// instruction is to perform a table lookup.
lua_gettable(L, -2);
lua_replace(L, -2);
}
else
{
} else {
// Otherwise, the first value was a method or method name.
if(lua_type(L, 6) != LUA_TFUNCTION)
{
if (lua_type(L, 6) != LUA_TFUNCTION) {
lua_pushvalue(L, 6);
lua_gettable(L, 7);
lua_replace(L, 6);
@@ -552,8 +498,7 @@ int l_str_depersist(lua_State *L)
return 0;
}
int l_str_reload_actual(lua_State *L)
{
int l_str_reload_actual(lua_State* L) {
// Reload a single string proxy
// Stack: reload_cache proxy_to_reload <top
@@ -568,19 +513,15 @@ int l_str_reload_actual(lua_State *L)
int iCount = (int)lua_objlen(L, 3);
aux_push_weak_table(L, 0);
lua_pushvalue(L, 2);
if(iCount != 0)
{
if (iCount != 0) {
// Fetch reconstruction information, reloading any de-proxying any
// string proxies which we come across. Also replace any references
// to the root with the new root.
lua_checkstack(L, iCount + 1);
for(int i = 1; i <= iCount; ++i)
{
for (int i = 1; i <= iCount; ++i) {
lua_rawgeti(L, 3, i);
if(lua_type(L, -1) == LUA_TUSERDATA)
{
if(i == 1)
bIsIndexOperation = true;
if (lua_type(L, -1) == LUA_TUSERDATA) {
if (i == 1) bIsIndexOperation = true;
lua_gettable(L, 1); // reload / change root
lua_pushvalue(L, -1);
lua_rawseti(L, 3, i);
@@ -588,27 +529,21 @@ int l_str_reload_actual(lua_State *L)
}
}
if(iCount == 2 && bIsIndexOperation)
{
if (iCount == 2 && bIsIndexOperation) {
// If there were two values, and the first was a proxy, then the
// instruction is to perform a table lookup.
lua_gettable(L, -2);
lua_replace(L, -2);
}
else
{
} else {
// Otherwise, the first value was a method or method name.
if(lua_type(L, 6) != LUA_TFUNCTION)
{
if (lua_type(L, 6) != LUA_TFUNCTION) {
lua_pushvalue(L, 6);
lua_gettable(L, 7);
lua_replace(L, 6);
}
lua_call(L, iCount - 1, 1);
}
}
else
{
} else {
// Root object
lua_settop(L, 2);
return 1;
@@ -619,27 +554,22 @@ int l_str_reload_actual(lua_State *L)
return 1;
}
int l_str_unwrap(lua_State *L)
{
int l_str_unwrap(lua_State* L) {
luaL_checkany(L, 1);
lua_settop(L, 1);
aux_push_weak_table(L, 0);
lua_pushvalue(L, 1);
lua_rawget(L, 2);
if(lua_isnil(L, 3))
{
if (lua_isnil(L, 3)) {
lua_settop(L, 1);
lua_pushboolean(L, 0);
}
else
{
} else {
lua_pushboolean(L, 1);
}
return 2;
}
int l_str_reload(lua_State *L)
{
int l_str_reload(lua_State* L) {
// The first argument should be the old root object, second argument the
// new one.
luaL_checktype(L, 1, LUA_TUSERDATA);
@@ -664,16 +594,14 @@ int l_str_reload(lua_State *L)
"local proxies_copy = {}\n"
"for k, v in pairs(all_proxies) do proxies_copy[k] = v end\n"
// Do the reloading
"for k in pairs(proxies_copy) do _ = reload[k] end\n"
);
"for k in pairs(proxies_copy) do _ = reload[k] end\n");
lua_insert(L, 1);
lua_call(L, 2, 0);
return 0;
}
int l_mk_cache(lua_State *L)
{
int l_mk_cache(lua_State* L) {
lua_newtable(L);
lua_pushvalue(L, luaT_upvalueindex(1));
lua_setmetatable(L, -2);
@@ -685,10 +613,8 @@ int l_mk_cache(lua_State *L)
} // namespace
const char* luaT_checkstring(lua_State *L, int idx, size_t* pLength)
{
if(lua_isuserdata(L, idx))
{
const char* luaT_checkstring(lua_State* L, int idx, size_t* pLength) {
if (lua_isuserdata(L, idx)) {
aux_push_weak_table(L, 0);
bool bRel = (0 > idx && idx > LUA_REGISTRYINDEX);
lua_pushvalue(L, bRel ? (idx - 1) : idx);
@@ -699,21 +625,18 @@ const char* luaT_checkstring(lua_State *L, int idx, size_t* pLength)
return luaL_checklstring(L, idx, pLength);
}
void lua_register_strings(const lua_register_state *pState)
{
void lua_register_strings(const lua_register_state* pState) {
lua_State* L = pState->L;
// Create Value, and Cache weak tables for inside-out objects.
for(int i = 0; i <= 1; ++i)
{
for (int i = 0; i <= 1; ++i) {
lua_pushlightuserdata(L, &weak_table_keys[i]);
lua_newtable(L);
lua_createtable(L, 0, 1);
lua_pushliteral(L, "__mode");
lua_pushliteral(L, "k");
lua_rawset(L, -3);
if(i == 1)
{
if (i == 1) {
// Have the cache weak table automatically create caches on demand
lua_pushliteral(L, "__index");
lua_createtable(L, 0, 1);
@@ -732,10 +655,15 @@ void lua_register_strings(const lua_register_state *pState)
lua_rawget(L, LUA_REGISTRYINDEX);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_class_binding<string_proxy> lcb(pState, "stringProxy", l_str_new, lua_metatable::string_proxy);
lua_class_binding<string_proxy> lcb(pState, "stringProxy", l_str_new,
lua_metatable::string_proxy);
// As we overwrite __index, move methods to lua_metatable::string_proxy[4]
lua_getfield(L, pState->metatables[static_cast<size_t>(lua_metatable::string_proxy)], "__index");
lua_rawseti(L, pState->metatables[static_cast<size_t>(lua_metatable::string_proxy)], 4);
lua_getfield(
L, pState->metatables[static_cast<size_t>(lua_metatable::string_proxy)],
"__index");
lua_rawseti(
L, pState->metatables[static_cast<size_t>(lua_metatable::string_proxy)],
4);
lcb.add_metamethod(l_str_index, "index");
lcb.add_metamethod(l_str_newindex, "newindex");
lcb.add_metamethod(l_str_concat, "concat");

View File

@@ -20,38 +20,38 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "th_lua_internal.h"
#include "th_gfx.h"
#include "th_map.h"
#include <algorithm>
#include "th_gfx.h"
#include "th_lua_internal.h"
#include "th_map.h"
class abstract_window {};
namespace {
int l_abstract_window_new(lua_State *L)
{
return luaL_error(L, "windowBase can only be used a base class - "
int l_abstract_window_new(lua_State* L) {
return luaL_error(L,
"windowBase can only be used a base class - "
" do not create a windowBase directly.");
}
uint8_t range_scale(uint16_t low, uint16_t high, uint16_t val, uint16_t start, uint16_t end)
{
return static_cast<uint8_t>(std::max(start + (end - start) * (val - low) / (high - low), 0xFF));
uint8_t range_scale(uint16_t low, uint16_t high, uint16_t val, uint16_t start,
uint16_t end) {
return static_cast<uint8_t>(
std::max(start + (end - start) * (val - low) / (high - low), 0xFF));
}
inline bool is_wall(uint16_t blk)
{
inline bool is_wall(uint16_t blk) {
return ((82 <= ((blk)&0xFF)) && (((blk)&0xFF) <= 164));
}
inline bool is_wall_drawn(const level_map &map, const map_tile &node, const map_tile &original_node, size_t n)
{
return map.get_tile_owner(&node) != 0 ? is_wall(node.iBlock[n]) : is_wall(original_node.iBlock[n]);
inline bool is_wall_drawn(const level_map& map, const map_tile& node,
const map_tile& original_node, size_t n) {
return map.get_tile_owner(&node) != 0 ? is_wall(node.iBlock[n])
: is_wall(original_node.iBlock[n]);
}
int l_town_map_draw(lua_State *L)
{
int l_town_map_draw(lua_State* L) {
luaL_checktype(L, 1, LUA_TTABLE);
level_map* pMap = luaT_testuserdata<level_map>(L, 2);
render_target* pCanvas = luaT_testuserdata<render_target>(L, 3);
@@ -68,24 +68,19 @@ int l_town_map_draw(lua_State *L)
const map_tile* pOriginalNode = pMap->get_original_tile_unchecked(0, 0);
int iCanvasY = iCanvasYBase + 3;
int iMapWidth = pMap->get_width();
for(int iY = 0; iY < pMap->get_height(); ++iY, iCanvasY += 3)
{
for (int iY = 0; iY < pMap->get_height(); ++iY, iCanvasY += 3) {
int iCanvasX = iCanvasXBase;
for(int iX = 0; iX < iMapWidth; ++iX, ++pNode, ++pOriginalNode, iCanvasX += 3)
{
if(pOriginalNode->flags.hospital)
{
for (int iX = 0; iX < iMapWidth;
++iX, ++pNode, ++pOriginalNode, iCanvasX += 3) {
if (pOriginalNode->flags.hospital) {
uint32_t iColour = iColourMyHosp;
if(!(pNode->flags.hospital))
{
if (!(pNode->flags.hospital)) {
// TODO: Replace 1 with player number
if (pMap->is_parcel_purchasable(pNode->iParcelId, 1))
iColour = iColourPurchasable;
else
goto dont_paint_tile;
}
else if(bShowHeat)
{
} else if (bShowHeat) {
uint16_t iTemp = pMap->get_tile_temperature(pNode);
if (iTemp < 5200) // Less than 4 degrees
iTemp = 0;
@@ -100,8 +95,7 @@ int l_town_map_draw(lua_State *L)
uint8_t iR = 0;
uint8_t iG = 0;
uint8_t iB = 0;
switch(pMap->get_temperature_display())
{
switch (pMap->get_temperature_display()) {
case temperature_theme::multi_colour:
iB = 70;
if (iTemp < minOkTemp) {
@@ -167,9 +161,11 @@ int l_town_map_draw(lua_State *L)
} // namespace
void lua_register_ui(const lua_register_state *pState)
{
void lua_register_ui(const lua_register_state* pState) {
// WindowBase
lua_class_binding<abstract_window> lcb(pState, "windowHelpers", l_abstract_window_new, lua_metatable::window_base);
lcb.add_function(l_town_map_draw, "townMapDraw", lua_metatable::map, lua_metatable::surface);
lua_class_binding<abstract_window> lcb(pState, "windowHelpers",
l_abstract_window_new,
lua_metatable::window_base);
lcb.add_function(l_town_map_draw, "townMapDraw", lua_metatable::map,
lua_metatable::surface);
}

File diff suppressed because it is too large Load Diff

View File

@@ -22,17 +22,16 @@ SOFTWARE.
#ifndef CORSIX_TH_TH_MAP_H_
#define CORSIX_TH_TH_MAP_H_
#include "th_gfx.h"
#include <list>
#include <string>
#include "th_gfx.h"
/*
Object type enumeration uses same values as original TH does.
See game string table section 39 for proof. Section 1 also has
names in this order.
*/
enum class object_type : uint8_t
{
enum class object_type : uint8_t {
no_object = 0,
desk = 1,
cabinet = 2,
@@ -104,8 +103,7 @@ enum class object_type : uint8_t
//! Map flags and object type
//! The point of storing the object type here is to allow pathfinding code
//! to use object types as pathfinding goals.
struct map_tile_flags
{
struct map_tile_flags {
enum class key : uint32_t {
passable_mask = 1 << 0,
can_travel_n_mask = 1 << 1,
@@ -172,8 +170,7 @@ enum class temperature_theme {
yellow_red //!< Gradients of yellow, orange, and red
};
struct map_tile : public link_list
{
struct map_tile : public link_list {
map_tile();
~map_tile();
@@ -226,12 +223,12 @@ class sprite_sheet;
* The object flags present in the map data. The meaning of this
value is left unspecified.
*/
typedef void (*map_load_object_callback_fn)(void*, int, int, object_type, uint8_t);
typedef void (*map_load_object_callback_fn)(void*, int, int, object_type,
uint8_t);
class map_overlay;
class level_map
{
class level_map {
public:
level_map();
~level_map();
@@ -261,7 +258,9 @@ public:
void update_pathfinding();
void update_shadows();
void set_temperature_display(temperature_theme eTempDisplay);
inline temperature_theme get_temperature_display() const {return current_temperature_theme;}
inline temperature_theme get_temperature_display() const {
return current_temperature_theme;
}
void update_temperatures(uint16_t iAirTemperature,
uint16_t iRadiatorTemperature);
@@ -362,8 +361,7 @@ public:
//! Convert world (tile) co-ordinates to absolute screen co-ordinates
template <typename T>
static inline void world_to_screen(T& x, T& y)
{
static inline void world_to_screen(T& x, T& y) {
T x_(x);
x = (T)32 * (x_ - y);
y = (T)16 * (x_ + y);
@@ -371,8 +369,7 @@ public:
//! Convert absolute screen co-ordinates to world (tile) co-ordinates
template <typename T>
static inline void screen_to_world(T& x, T& y)
{
static inline void screen_to_world(T& x, T& y) {
T x_(x);
x = y / (T)32 + x_ / (T)64;
y = y / (T)32 - x_ / (T)64;
@@ -389,14 +386,19 @@ private:
void read_tile_index(const uint8_t* pData, int& iX, int& iY) const;
void write_tile_index(uint8_t* pData, int iX, int iY) const;
//! Calculate a weighted impact of a neighbour tile on the temperature of the current tile.
//! \param iNeighbourSum Incremented by the temperature of the tile multiplied by the weight of the connection.
//! \param canTravel A tile flag indicating whether travel between this tile and it's neighbour is allowed.
//! \param relative_idx The index of the neighbour tile, relative to this tile into cells.
//! \param pNode A pointer to the current tile being tested.
//! \param prevTemp The array index into map_tile::temperature that currently stores the temperature of the tile (prior to this calculation).
//! \return The weight of the connection, 0 if there is no neighbour, 1 through walls, and 4 through air.
uint32_t thermal_neighbour(uint32_t &iNeighbourSum, bool canTravel, std::ptrdiff_t relative_idx, map_tile* pNode, int prevTemp) const;
//! Calculate a weighted impact of a neighbour tile on the temperature of
//! the current tile. \param iNeighbourSum Incremented by the temperature of
//! the tile multiplied by the weight of the connection. \param canTravel A
//! tile flag indicating whether travel between this tile and it's neighbour
//! is allowed. \param relative_idx The index of the neighbour tile,
//! relative to this tile into cells. \param pNode A pointer to the current
//! tile being tested. \param prevTemp The array index into
//! map_tile::temperature that currently stores the temperature of the tile
//! (prior to this calculation). \return The weight of the connection, 0 if
//! there is no neighbour, 1 through walls, and 4 through air.
uint32_t thermal_neighbour(uint32_t& iNeighbourSum, bool canTravel,
std::ptrdiff_t relative_idx, map_tile* pNode,
int prevTemp) const;
//! Create the adjacency matrix if it doesn't already exist
void make_adjacency_matrix();
@@ -451,8 +453,7 @@ enum class map_scanline_iterator_direction {
tiles right-to-left, wait until isLastOnScanline() returns true, then use
an instance of THMapScanlineIterator.
*/
class map_tile_iterator
{
class map_tile_iterator {
public:
map_tile_iterator();
@@ -469,7 +470,8 @@ public:
*/
map_tile_iterator(const level_map* pMap, int iScreenX, int iScreenY,
int iWidth, int iHeight,
map_scanline_iterator_direction eScanlineDirection = map_scanline_iterator_direction::forward);
map_scanline_iterator_direction eScanlineDirection =
map_scanline_iterator_direction::forward);
//! Returns false iff the iterator has exhausted its tiles
inline operator bool() const { return tile != nullptr; }
@@ -480,10 +482,12 @@ public:
//! Accessor for the current tile
inline const map_tile* operator->() const { return tile; }
//! Get the X position of the tile relative to the top-left corner of the screen-space rectangle
//! Get the X position of the tile relative to the top-left corner of the
//! screen-space rectangle
inline int tile_x_position_on_screen() const { return x_relative_to_screen; }
//! Get the Y position of the tile relative to the top-left corner of the screen-space rectangle
//! Get the Y position of the tile relative to the top-left corner of the
//! screen-space rectangle
inline int tile_y_position_on_screen() const { return y_relative_to_screen; }
inline int tile_x() const { return world_x; }
@@ -492,7 +496,9 @@ public:
inline const level_map* get_map() { return container; }
inline const map_tile* get_map_tile() { return tile; }
inline int get_scanline_count() { return scanline_count; }
inline int get_tile_step() {return (static_cast<int>(direction) - 1) * (1 - container->get_width());}
inline int get_tile_step() {
return (static_cast<int>(direction) - 1) * (1 - container->get_width());
}
//! Returns true iff the next tile will be on a different scanline
/*!
@@ -535,8 +541,7 @@ private:
};
//! Utility class for re-iterating a scanline visited by a map_tile_iterator
class map_scanline_iterator
{
class map_scanline_iterator {
public:
map_scanline_iterator();

View File

@@ -21,139 +21,128 @@ SOFTWARE.
*/
#include "th_map_overlays.h"
#include "th_gfx.h"
#include "th_map.h"
#include <sstream>
#include <array>
#include <sstream>
#include "th_gfx.h"
#include "th_gfx_font.h"
#include "th_map.h"
map_overlay_pair::map_overlay_pair()
{
map_overlay_pair::map_overlay_pair() {
first = nullptr;
second = nullptr;
owns_first = false;
owns_second = false;
}
map_overlay_pair::~map_overlay_pair()
{
map_overlay_pair::~map_overlay_pair() {
set_first(nullptr, false);
set_second(nullptr, false);
}
void map_overlay_pair::set_first(map_overlay* pOverlay, bool bTakeOwnership)
{
if(first && owns_first)
void map_overlay_pair::set_first(map_overlay* pOverlay, bool bTakeOwnership) {
if (first && owns_first) {
delete first;
}
first = pOverlay;
owns_first = bTakeOwnership;
}
void map_overlay_pair::set_second(map_overlay* pOverlay, bool bTakeOwnership)
{
if(second && owns_second)
void map_overlay_pair::set_second(map_overlay* pOverlay, bool bTakeOwnership) {
if (second && owns_second) {
delete second;
}
second = pOverlay;
owns_second = bTakeOwnership;
}
void map_overlay_pair::draw_cell(render_target* pCanvas, int iCanvasX,
int iCanvasY, const level_map* pMap, int iNodeX,
int iNodeY)
{
if(first)
int iCanvasY, const level_map* pMap,
int iNodeX, int iNodeY) {
if (first) {
first->draw_cell(pCanvas, iCanvasX, iCanvasY, pMap, iNodeX, iNodeY);
if(second)
}
if (second) {
second->draw_cell(pCanvas, iCanvasX, iCanvasY, pMap, iNodeX, iNodeY);
}
map_text_overlay::map_text_overlay()
{
background_sprite = 0;
}
void map_text_overlay::set_background_sprite(size_t iSprite)
{
map_text_overlay::map_text_overlay() { background_sprite = 0; }
void map_text_overlay::set_background_sprite(size_t iSprite) {
background_sprite = iSprite;
}
void map_text_overlay::draw_cell(render_target* pCanvas, int iCanvasX,
int iCanvasY, const level_map* pMap, int iNodeX,
int iNodeY)
{
if(sprites && background_sprite)
{
sprites->draw_sprite(pCanvas, background_sprite, iCanvasX,
iCanvasY, 0);
int iCanvasY, const level_map* pMap,
int iNodeX, int iNodeY) {
if (sprites && background_sprite) {
sprites->draw_sprite(pCanvas, background_sprite, iCanvasX, iCanvasY, 0);
}
if(font)
{
if (font) {
draw_text(pCanvas, iCanvasX, iCanvasY, get_text(pMap, iNodeX, iNodeY));
}
}
const std::string map_positions_overlay::get_text(const level_map* pMap, int iNodeX, int iNodeY)
{
const std::string map_positions_overlay::get_text(const level_map* pMap,
int iNodeX, int iNodeY) {
std::ostringstream str;
str << iNodeX + 1 << ',' << iNodeY + 1;
return str.str();
}
map_typical_overlay::map_typical_overlay()
{
map_typical_overlay::map_typical_overlay() {
sprites = nullptr;
font = nullptr;
owns_sprites = false;
owns_font = false;
}
map_typical_overlay::~map_typical_overlay()
{
map_typical_overlay::~map_typical_overlay() {
set_sprites(nullptr, false);
set_font(nullptr, false);
}
void map_flags_overlay::draw_cell(render_target* pCanvas, int iCanvasX,
int iCanvasY, const level_map* pMap, int iNodeX,
int iNodeY)
{
int iCanvasY, const level_map* pMap,
int iNodeX, int iNodeY) {
const map_tile* pNode = pMap->get_tile(iNodeX, iNodeY);
if(!pNode)
if (!pNode) {
return;
if(sprites)
{
if(pNode->flags.passable)
}
if (sprites) {
if (pNode->flags.passable) {
sprites->draw_sprite(pCanvas, 3, iCanvasX, iCanvasY, 0);
if(pNode->flags.hospital)
}
if (pNode->flags.hospital) {
sprites->draw_sprite(pCanvas, 8, iCanvasX, iCanvasY, 0);
if(pNode->flags.buildable)
}
if (pNode->flags.buildable) {
sprites->draw_sprite(pCanvas, 9, iCanvasX, iCanvasY, 0);
if(pNode->flags.can_travel_n && pMap->get_tile(iNodeX, iNodeY - 1)->flags.passable)
{
}
if (pNode->flags.can_travel_n &&
pMap->get_tile(iNodeX, iNodeY - 1)->flags.passable) {
sprites->draw_sprite(pCanvas, 4, iCanvasX, iCanvasY, 0);
}
if(pNode->flags.can_travel_e && pMap->get_tile(iNodeX + 1, iNodeY)->flags.passable)
{
if (pNode->flags.can_travel_e &&
pMap->get_tile(iNodeX + 1, iNodeY)->flags.passable) {
sprites->draw_sprite(pCanvas, 5, iCanvasX, iCanvasY, 0);
}
if(pNode->flags.can_travel_s && pMap->get_tile(iNodeX, iNodeY + 1)->flags.passable)
{
if (pNode->flags.can_travel_s &&
pMap->get_tile(iNodeX, iNodeY + 1)->flags.passable) {
sprites->draw_sprite(pCanvas, 6, iCanvasX, iCanvasY, 0);
}
if(pNode->flags.can_travel_w && pMap->get_tile(iNodeX - 1, iNodeY)->flags.passable)
{
if (pNode->flags.can_travel_w &&
pMap->get_tile(iNodeX - 1, iNodeY)->flags.passable) {
sprites->draw_sprite(pCanvas, 7, iCanvasX, iCanvasY, 0);
}
}
if(font)
{
if(!pNode->objects.empty())
{
if (font) {
if (!pNode->objects.empty()) {
std::ostringstream str;
str << 'T' << static_cast<int>(pNode->objects.front());
draw_text(pCanvas, iCanvasX, iCanvasY - 8, str.str());
}
if(pNode->iRoomId)
{
if (pNode->iRoomId) {
std::ostringstream str;
str << 'R' << static_cast<int>(pNode->iRoomId);
draw_text(pCanvas, iCanvasX, iCanvasY + 8, str.str());
@@ -165,66 +154,60 @@ namespace {
// The sprite to include if the tile in the direction indicated by dx,dy is
// not from the same parcel.
struct parcel_edge_sprite
{
struct parcel_edge_sprite {
int dx;
int dy;
size_t sprite;
};
// Parcel edge sprites for all four directions
constexpr std::array<parcel_edge_sprite, 4> parcel_edges {{
{0, -1, 18},
{1, 0, 19},
{0, 1, 20},
{-1, 0, 21}
}};
constexpr std::array<parcel_edge_sprite, 4> parcel_edges{
{{0, -1, 18}, {1, 0, 19}, {0, 1, 20}, {-1, 0, 21}}};
}
} // namespace
void map_parcels_overlay::draw_cell(render_target* pCanvas, int iCanvasX,
int iCanvasY, const level_map* pMap, int iNodeX,
int iNodeY)
{
int iCanvasY, const level_map* pMap,
int iNodeX, int iNodeY) {
const map_tile* pNode = pMap->get_tile(iNodeX, iNodeY);
if(!pNode)
if (!pNode) {
return;
if(font)
draw_text(pCanvas, iCanvasX, iCanvasY, std::to_string((int)pNode->iParcelId));
if(sprites)
{
for(const parcel_edge_sprite& dir_sprite : parcel_edges)
{
const map_tile* dir_node = pMap->get_tile(iNodeX + dir_sprite.dx, iNodeY + dir_sprite.dy);
if (!dir_node || dir_node->iParcelId == pNode->iParcelId)
{
}
if (font) {
draw_text(pCanvas, iCanvasX, iCanvasY,
std::to_string((int)pNode->iParcelId));
}
if (sprites) {
for (const parcel_edge_sprite& dir_sprite : parcel_edges) {
const map_tile* dir_node =
pMap->get_tile(iNodeX + dir_sprite.dx, iNodeY + dir_sprite.dy);
if (!dir_node || dir_node->iParcelId == pNode->iParcelId) {
sprites->draw_sprite(pCanvas, dir_sprite.sprite, iCanvasX, iCanvasY, 0);
}
}
}
}
void map_typical_overlay::draw_text(render_target* pCanvas, int iX, int iY,
std::string str)
{
std::string str) {
text_layout oArea = font->get_text_dimensions(str.c_str(), str.length());
font->draw_text(pCanvas, str.c_str(), str.length(), iX + (64 - oArea.end_x) / 2,
iY + (32 - oArea.end_y) / 2);
font->draw_text(pCanvas, str.c_str(), str.length(),
iX + (64 - oArea.end_x) / 2, iY + (32 - oArea.end_y) / 2);
}
void map_typical_overlay::set_sprites(sprite_sheet* pSheet, bool bTakeOwnership)
{
if(sprites && owns_sprites)
void map_typical_overlay::set_sprites(sprite_sheet* pSheet,
bool bTakeOwnership) {
if (sprites && owns_sprites) {
delete sprites;
}
sprites = pSheet;
owns_sprites = bTakeOwnership;
}
void map_typical_overlay::set_font(::font* font, bool take_ownership)
{
if(this->font && owns_font)
void map_typical_overlay::set_font(::font* font, bool take_ownership) {
if (this->font && owns_font) {
delete this->font;
}
this->font = font;
owns_font = take_ownership;
}

View File

@@ -31,8 +31,7 @@ class level_map;
class render_target;
class sprite_sheet;
class map_overlay
{
class map_overlay {
public:
virtual ~map_overlay() = default;
@@ -40,8 +39,7 @@ public:
const level_map* pMap, int iNodeX, int iNodeY) = 0;
};
class map_overlay_pair : public map_overlay
{
class map_overlay_pair : public map_overlay {
public:
map_overlay_pair();
virtual ~map_overlay_pair();
@@ -57,8 +55,7 @@ private:
bool owns_first, owns_second;
};
class map_typical_overlay : public map_overlay
{
class map_typical_overlay : public map_overlay {
public:
map_typical_overlay();
virtual ~map_typical_overlay();
@@ -77,8 +74,7 @@ private:
bool owns_font;
};
class map_text_overlay : public map_typical_overlay
{
class map_text_overlay : public map_typical_overlay {
public:
map_text_overlay();
virtual ~map_text_overlay() = default;
@@ -87,27 +83,26 @@ public:
const level_map* pMap, int iNodeX, int iNodeY);
void set_background_sprite(size_t iSprite);
virtual const std::string get_text(const level_map* pMap, int iNodeX, int iNodeY) = 0;
virtual const std::string get_text(const level_map* pMap, int iNodeX,
int iNodeY) = 0;
private:
size_t background_sprite;
};
class map_positions_overlay final : public map_text_overlay
{
class map_positions_overlay final : public map_text_overlay {
public:
const std::string get_text(const level_map* pMap, int iNodeX, int iNodeY) override;
const std::string get_text(const level_map* pMap, int iNodeX,
int iNodeY) override;
};
class map_flags_overlay final : public map_typical_overlay
{
class map_flags_overlay final : public map_typical_overlay {
public:
void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY,
const level_map* pMap, int iNodeX, int iNodeY) override;
};
class map_parcels_overlay final : public map_typical_overlay
{
class map_parcels_overlay final : public map_typical_overlay {
public:
void draw_cell(render_target* pCanvas, int iCanvasX, int iCanvasY,
const level_map* pMap, int iNodeX, int iNodeY) override;

File diff suppressed because it is too large Load Diff

View File

@@ -23,20 +23,20 @@ SOFTWARE.
#ifndef TH_VIDEO_H
#define TH_VIDEO_H
#include <string>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include "SDL.h"
#include "config.h"
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include "SDL.h"
#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && defined(CORSIX_TH_USE_SDL_MIXER)
#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && \
defined(CORSIX_TH_USE_SDL_MIXER)
#include "SDL_mixer.h"
extern "C"
{
extern "C" {
#ifndef INT64_C
#define INT64_C(c) (c##LL)
#define UINT64_C(c) (c##ULL)
@@ -51,24 +51,26 @@ extern "C"
#endif
}
#if (defined(CORSIX_TH_USE_FFMEPG) && LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 74, 100)) || \
(defined(CORSIX_TH_USE_LIBAV) && LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 42, 0))
#if (defined(CORSIX_TH_USE_FFMEPG) && \
LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 74, 100)) || \
(defined(CORSIX_TH_USE_LIBAV) && \
LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 42, 0))
#define AVPixelFormat PixelFormat
#define AV_PIX_FMT_RBG24 PIX_FMT_RGB24
#endif
#if (defined(CORSIX_TH_USE_LIBAV) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 16, 0)) || \
(defined(CORSIX_TH_USE_FFMPEG) && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100))
#if (defined(CORSIX_TH_USE_LIBAV) && \
LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 16, 0)) || \
(defined(CORSIX_TH_USE_FFMPEG) && \
LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100))
#define CORSIX_TH_MOVIE_USE_SEND_PACKET_API
#endif
//! \brief A picture in movie_picture_buffer
//!
//! Stores the picture from a frame in the movie from the time that it is
//! processed until it should be drawn.
class movie_picture
{
class movie_picture {
public:
movie_picture();
~movie_picture();
@@ -88,8 +90,7 @@ public:
};
//! A buffer for holding movie pictures and drawing them to the renderer
class movie_picture_buffer
{
class movie_picture_buffer {
public:
movie_picture_buffer();
~movie_picture_buffer();
@@ -132,16 +133,16 @@ public:
//! Return whether there are any pictures left to draw in the picture queue
//!
//! \remark If the movie_picture_buffer is not allocated it cannot be read from
//! or written to. Consequently it is both full and empty.
//! \remark If the movie_picture_buffer is not allocated it cannot be read
//! from or written to. Consequently it is both full and empty.
bool empty();
// NB: These functions are called by a second thread
//! Return whether there is space to add any more frame data to the queue
//!
//! \remark If the movie_picture_buffer is not allocated it cannot be read from
//! or written to. Consequently it is both full and empty.
//! \remark If the movie_picture_buffer is not allocated it cannot be read
//! from or written to. Consequently it is both full and empty.
bool full();
//! Write the given frame (and presentation time stamp) to the picture
@@ -151,28 +152,39 @@ public:
//! \retval -1 Abort is in progress
//! \retval 1 An error writing the frame
int write(AVFrame* pFrame, double dPts);
private:
//! Return whether there is space to add any more frame data to the queue
//!
//! \remark Requires external locking
bool unsafe_full();
static constexpr size_t picture_buffer_size = 4; ///< The number of elements to allocate in the picture queue
static constexpr size_t picture_buffer_size =
4; ///< The number of elements to allocate in the picture queue
std::atomic<bool> aborting; ///< Whether we are in the process of aborting
bool allocated; ///< Whether the picture buffer has been allocated (and hasn't since been deallocated)
int picture_count; ///< The number of elements currently written to the picture queue
bool allocated; ///< Whether the picture buffer has been allocated (and
///< hasn't since been deallocated)
int picture_count; ///< The number of elements currently written to the
///< picture queue
int read_index; ///< The position in the picture queue to be read next
int write_index; ///< The position in the picture queue to be written to next
SwsContext* sws_context; ///< The context for software scaling and pixel conversion when writing to the picture queue
SDL_Texture *texture; ///< The (potentially hardware) texture to draw the picture to. In OpenGL this should only be accessed on the main thread
std::mutex mutex; ///< A mutex for restricting access to the picture buffer to a single thread
std::condition_variable cond; ///< A condition for indicating access to the picture buffer
movie_picture picture_queue[picture_buffer_size]; ///< The picture queue, a looping FIFO queue of movie_pictures
int write_index; ///< The position in the picture queue to be written to
///< next
SwsContext* sws_context; ///< The context for software scaling and pixel
///< conversion when writing to the picture queue
SDL_Texture* texture; ///< The (potentially hardware) texture to draw the
///< picture to. In OpenGL this should only be
///< accessed on the main thread
std::mutex mutex; ///< A mutex for restricting access to the picture buffer
///< to a single thread
std::condition_variable
cond; ///< A condition for indicating access to the picture buffer
movie_picture picture_queue[picture_buffer_size]; ///< The picture queue, a
///< looping FIFO queue
///< of movie_pictures
};
//! The AVPacketQueue is a thread safe queue of movie packets
class av_packet_queue
{
class av_packet_queue {
public:
//! Construct a new empty packet queue
av_packet_queue();
@@ -197,12 +209,15 @@ public:
//! Release a blocking pull without writing a new packet to the queue.
void release();
private:
AVPacketList* first_packet; ///< The packet at the front of the queue
AVPacketList* last_packet; ///< The packet at the end of the queue
int count; ///< The number of packets in the queue
std::mutex mutex; ///< A mutex restricting access to the packet queue to a single thread
std::condition_variable cond; ///< A condition to wait on for signaling the packet queue
std::mutex mutex; ///< A mutex restricting access to the packet queue to a
///< single thread
std::condition_variable
cond; ///< A condition to wait on for signaling the packet queue
};
#endif // CORSIX_TH_USE_FFMPEG || CORSIX_TH_USE_LIBAV
@@ -210,10 +225,9 @@ private:
//!
//! The movie player is designed to be preinitialized and used for multiple
//! movies. After initializing the movie player, call movie_player::set_renderer
//! to assign the current SDL renderer to the movie player. Then movie_player::load
//! the desired movie and finally movie_player::play it.
class movie_player
{
//! to assign the current SDL renderer to the movie player. Then
//! movie_player::load the desired movie and finally movie_player::play it.
class movie_player {
public:
//! Construct a new movie_player
movie_player();
@@ -271,9 +285,9 @@ public:
//! \remark This destroys the textures and other resources that may lock
//! the renderer from being deleted. If the target changes you would call
//! this, then free and switch renderers in the outside program, then call
//! movie_player::set_renderer and finally movie_player::allocate_picture_buffer.
//! \remark Up to the size of the picture buffer frames may be lost during
//! this process.
//! movie_player::set_renderer and finally
//! movie_player::allocate_picture_buffer. \remark Up to the size of the
//! picture buffer frames may be lost during this process.
void deallocate_picture_buffer();
//! Allocate the picture buffer for the current renderer
@@ -298,17 +312,23 @@ public:
void copy_audio_to_stream(uint8_t* pbStream, int iStreamSize);
private:
#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && defined(CORSIX_TH_USE_SDL_MIXER)
static constexpr size_t movie_error_buffer_capacity = 128; ///< Buffer to hold last error description
static constexpr size_t audio_chunk_buffer_capacity = 1024; ///< Buffer for audio playback
#if (defined(CORSIX_TH_USE_FFMPEG) || defined(CORSIX_TH_USE_LIBAV)) && \
defined(CORSIX_TH_USE_SDL_MIXER)
static constexpr size_t movie_error_buffer_capacity =
128; ///< Buffer to hold last error description
static constexpr size_t audio_chunk_buffer_capacity =
1024; ///< Buffer for audio playback
//! Get the AVCodecContext associated with a given stream
AVCodecContext* get_codec_context_for_stream(AVCodec* codec, AVStream* stream) const;
AVCodecContext* get_codec_context_for_stream(AVCodec* codec,
AVStream* stream) const;
//! Get the time the given frame should be played (from the start of the stream)
//! Get the time the given frame should be played (from the start of the
//! stream)
//!
//! \param frame The video or audio frame
//! \param streamIndex The position of the stream in m_pFormatContexts streams array
//! \param streamIndex The position of the stream in m_pFormatContexts
//! streams array
double get_presentation_time_for_frame(AVFrame* frame, int streamIndex) const;
//! Decode audio from the movie into a format suitable for playback
@@ -344,11 +364,14 @@ private:
std::mutex decoding_audio_mutex; ///< Synchronize access to #m_pAudioBuffer
AVFormatContext* format_context; ///< Information related to the loaded movie and all of its streams
AVFormatContext* format_context; ///< Information related to the loaded
///< movie and all of its streams
int video_stream_index; ///< The index of the video stream
int audio_stream_index; ///< The index of the audio stream
AVCodecContext *video_codec_context; ///< The video codec and information related to video
AVCodecContext *audio_codec_context; ///< The audio codec and information related to audio
AVCodecContext* video_codec_context; ///< The video codec and information
///< related to video
AVCodecContext* audio_codec_context; ///< The audio codec and information
///< related to audio
// queues for transferring data between threads
av_packet_queue* video_queue; ///< Packets from the video stream
@@ -357,35 +380,49 @@ private:
// clock sync parameters
int current_sync_pts_system_time; ///< System time matching #m_iCurSyncPts
double current_sync_pts; ///< The current presentation time stamp (from the audio stream)
double current_sync_pts; ///< The current presentation time stamp (from the
///< audio stream)
#ifdef CORSIX_TH_USE_FFMPEG
SwrContext* audio_resample_context; ///< Context for resampling audio for playback with ffmpeg
SwrContext* audio_resample_context; ///< Context for resampling audio for
///< playback with ffmpeg
#elif defined(CORSIX_TH_USE_LIBAV)
AVAudioResampleContext* audio_resample_context; ///< Context for resampling audio for playback with libav
AVAudioResampleContext*
audio_resample_context; ///< Context for resampling audio for
///< playback with libav
#endif
int audio_buffer_size; ///< The current size of audio data in #m_pbAudioBuffer
int audio_buffer_index; ///< The current position for writing in #m_pbAudioBuffer
int audio_buffer_max_size; ///< The capacity of #m_pbAudioBuffer (allocated size)
int audio_buffer_size; ///< The current size of audio data in
///< #m_pbAudioBuffer
int audio_buffer_index; ///< The current position for writing in
///< #m_pbAudioBuffer
int audio_buffer_max_size; ///< The capacity of #m_pbAudioBuffer (allocated
///< size)
uint8_t* audio_buffer; ///< An audio buffer for playback
AVPacket* audio_packet; ///< The current audio packet being decoded (audio frames don't necessarily line up with packets)
AVPacket* audio_packet; ///< The current audio packet being decoded (audio
///< frames don't necessarily line up with packets)
int audio_packet_size; ///< The size of #m_pbAudioPacketData
uint8_t *audio_packet_data; ///< Original data for #m_pAudioPacket, kept so that it can be freed after the packet is processed
uint8_t* audio_packet_data; ///< Original data for #m_pAudioPacket, kept so
///< that it can be freed after the packet is
///< processed
AVFrame* audio_frame; ///< The frame we are decoding audio into
Mix_Chunk* empty_audio_chunk; ///< Empty chunk needed for SDL_mixer
uint8_t* audio_chunk_buffer; ///< 0'd out buffer for the SDL_Mixer chunk
int audio_channel; ///< The channel to play audio on, -1 for none
int mixer_channels; ///< How many channels to play on (1 - mono, 2 - stereo)
int mixer_channels; ///< How many channels to play on (1 - mono, 2 -
///< stereo)
int mixer_frequency; ///< The frequency of audio expected by SDL_Mixer
AVPacket* flush_packet; ///< A representative packet indicating a flush is required.
AVPacket* flush_packet; ///< A representative packet indicating a flush is
///< required.
std::thread stream_thread; ///< The thread responsible for reading the movie streams
std::thread video_thread; ///< The thread responsible for decoding the video stream
std::thread stream_thread; ///< The thread responsible for reading the
///< movie streams
std::thread video_thread; ///< The thread responsible for decoding the
///< video stream
#endif // CORSIX_TH_USE_FFMPEG || CORSIX_TH_USE_LIBAV
};

View File

@@ -20,20 +20,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "th_pathfind.h"
#include "persist_lua.h"
#include "lua.hpp"
#include "config.h"
#include <cmath>
#include <cstdlib>
#include <queue>
#include <cmath>
#include <vector>
#include "lua.hpp"
#include "persist_lua.h"
abstract_pathfinder::abstract_pathfinder(pathfinder *pf) : parent(pf)
{ }
abstract_pathfinder::abstract_pathfinder(pathfinder* pf) : parent(pf) {}
path_node *abstract_pathfinder::init(const level_map *pMap, int iStartX, int iStartY)
{
path_node* abstract_pathfinder::init(const level_map* pMap, int iStartX,
int iStartY) {
int iWidth = pMap->get_width();
parent->destination = nullptr;
parent->allocate_node_cache(iWidth, pMap->get_height());
@@ -51,37 +50,46 @@ path_node *abstract_pathfinder::init(const level_map *pMap, int iStartX, int iSt
flags are set as to prevent travelling off the map (as well as to
prevent walking through walls).
*/
bool abstract_pathfinder::search_neighbours(path_node *pNode, map_tile_flags flags, int iWidth)
{
if(flags.can_travel_w)
if(try_node(pNode, flags, pNode - 1, travel_direction::west)) return true;
bool abstract_pathfinder::search_neighbours(path_node* pNode,
map_tile_flags flags, int iWidth) {
if (flags.can_travel_w) {
if (try_node(pNode, flags, pNode - 1, travel_direction::west)) {
return true;
}
}
if(flags.can_travel_e)
if (try_node(pNode, flags, pNode + 1, travel_direction::east)) return true;
if (flags.can_travel_e) {
if (try_node(pNode, flags, pNode + 1, travel_direction::east)) {
return true;
}
}
if(flags.can_travel_n)
if (try_node(pNode, flags, pNode - iWidth, travel_direction::north)) return true;
if (flags.can_travel_n) {
if (try_node(pNode, flags, pNode - iWidth, travel_direction::north)) {
return true;
}
}
if(flags.can_travel_s)
if (try_node(pNode, flags, pNode + iWidth, travel_direction::south)) return true;
if (flags.can_travel_s) {
if (try_node(pNode, flags, pNode + iWidth, travel_direction::south)) {
return true;
}
}
return false;
}
void abstract_pathfinder::record_neighbour_if_passable(path_node *pNode, map_tile_flags neighbour_flags, bool passable, path_node *pNeighbour)
{
if(neighbour_flags.passable || !passable)
{
if(pNeighbour->prev == pNeighbour)
{
void abstract_pathfinder::record_neighbour_if_passable(
path_node* pNode, map_tile_flags neighbour_flags, bool passable,
path_node* pNeighbour) {
if (neighbour_flags.passable || !passable) {
if (pNeighbour->prev == pNeighbour) {
pNeighbour->prev = pNode;
pNeighbour->distance = pNode->distance + 1;
pNeighbour->guess = guess_distance(pNeighbour);
parent->dirty_node_list[parent->dirty_node_count++] = pNeighbour;
parent->push_to_open_heap(pNeighbour);
}
else if(pNode->distance + 1 < pNeighbour->distance)
{
} else if (pNode->distance + 1 < pNeighbour->distance) {
pNeighbour->prev = pNode;
pNeighbour->distance = pNode->distance + 1;
/* guess doesn't change, and already in the dirty list */
@@ -90,28 +98,29 @@ void abstract_pathfinder::record_neighbour_if_passable(path_node *pNode, map_til
}
}
int basic_pathfinder::guess_distance(path_node *pNode)
{
int basic_pathfinder::guess_distance(path_node* pNode) {
// As diagonal movement is not allowed, the minimum distance between two
// points is the sum of the distance in X and the distance in Y.
return abs(pNode->x - destination_x) + abs(pNode->y - destination_y);
}
bool basic_pathfinder::try_node(path_node* pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction)
{
map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
path_node* pNeighbour,
travel_direction direction) {
map_tile_flags neighbour_flags =
map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
return false;
}
bool basic_pathfinder::find_path(const level_map *pMap, int iStartX, int iStartY, int iEndX, int iEndY)
{
if(pMap == nullptr)
bool basic_pathfinder::find_path(const level_map* pMap, int iStartX,
int iStartY, int iEndX, int iEndY) {
if (pMap == nullptr) {
pMap = parent->default_map;
if(pMap == nullptr || pMap->get_tile(iEndX, iEndY) == nullptr
|| !pMap->get_tile_unchecked(iEndX, iEndY)->flags.passable)
{
}
if (pMap == nullptr || pMap->get_tile(iEndX, iEndY) == nullptr ||
!pMap->get_tile_unchecked(iEndX, iEndY)->flags.passable) {
parent->destination = nullptr;
return false;
}
@@ -124,16 +133,16 @@ bool basic_pathfinder::find_path(const level_map *pMap, int iStartX, int iStartY
int iWidth = pMap->get_width();
path_node* pTarget = parent->nodes + iEndY * iWidth + iEndX;
while(true)
{
if(pNode == pTarget)
{
while (true) {
if (pNode == pTarget) {
parent->destination = pTarget;
return true;
}
map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags;
if (search_neighbours(pNode, flags, iWidth)) return true;
if (search_neighbours(pNode, flags, iWidth)) {
return true;
}
if (parent->open_heap.empty()) {
parent->destination = nullptr;
@@ -145,26 +154,25 @@ bool basic_pathfinder::find_path(const level_map *pMap, int iStartX, int iStartY
return false;
}
int hospital_finder::guess_distance(path_node *pNode)
{
return 0;
}
int hospital_finder::guess_distance(path_node* pNode) { return 0; }
bool hospital_finder::try_node(path_node* pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction)
{
map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
path_node* pNeighbour,
travel_direction direction) {
map_tile_flags neighbour_flags =
map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
return false;
}
bool hospital_finder::find_path_to_hospital(const level_map *pMap, int iStartX, int iStartY)
{
if(pMap == nullptr)
bool hospital_finder::find_path_to_hospital(const level_map* pMap, int iStartX,
int iStartY) {
if (pMap == nullptr) {
pMap = parent->default_map;
if(pMap == nullptr || pMap->get_tile(iStartX, iStartY) == nullptr
|| !pMap->get_tile_unchecked(iStartX, iStartY)->flags.passable)
{
}
if (pMap == nullptr || pMap->get_tile(iStartX, iStartY) == nullptr ||
!pMap->get_tile_unchecked(iStartX, iStartY)->flags.passable) {
parent->destination = nullptr;
return false;
}
@@ -174,17 +182,17 @@ bool hospital_finder::find_path_to_hospital(const level_map *pMap, int iStartX,
path_node* pNode = init(pMap, iStartX, iStartY);
int iWidth = pMap->get_width();
while(true)
{
while (true) {
map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags;
if(flags.hospital)
{
if (flags.hospital) {
parent->destination = pNode;
return true;
}
if (search_neighbours(pNode, flags, iWidth)) return true;
if (search_neighbours(pNode, flags, iWidth)) {
return true;
}
if (parent->open_heap.empty()) {
parent->destination = nullptr;
@@ -196,59 +204,63 @@ bool hospital_finder::find_path_to_hospital(const level_map *pMap, int iStartX,
return false;
}
int idle_tile_finder::guess_distance(path_node *pNode)
{
return 0;
}
int idle_tile_finder::guess_distance(path_node* pNode) { return 0; }
bool idle_tile_finder::try_node(path_node* pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction)
{
map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
path_node* pNeighbour,
travel_direction direction) {
map_tile_flags neighbour_flags =
map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
/* When finding an idle tile, do not navigate through doors */
switch(direction)
{
switch (direction) {
case travel_direction::north:
if(!flags.door_north)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!flags.door_north) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
case travel_direction::east:
if(!neighbour_flags.door_west)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!neighbour_flags.door_west) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
case travel_direction::south:
if(!neighbour_flags.door_north)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!neighbour_flags.door_north) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
case travel_direction::west:
if(!flags.door_west)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!flags.door_west) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
}
/* Identify the neighbour in the open list nearest to the start */
if(pNeighbour->prev != pNeighbour && pNeighbour->open_idx != -1)
{
if (pNeighbour->prev != pNeighbour && pNeighbour->open_idx != -1) {
int iDX = pNeighbour->x - start_x;
int iDY = pNeighbour->y - start_y;
double fDistance = sqrt((double)(iDX * iDX + iDY * iDY));
if(best_next_node == nullptr || fDistance < best_distance)
{
best_next_node = pNeighbour; best_distance = fDistance;
if (best_next_node == nullptr || fDistance < best_distance) {
best_next_node = pNeighbour;
best_distance = fDistance;
}
}
return false;
}
bool idle_tile_finder::find_idle_tile(const level_map *pMap, int iStartX, int iStartY, int iN)
{
if(pMap == nullptr)
bool idle_tile_finder::find_idle_tile(const level_map* pMap, int iStartX,
int iStartY, int iN) {
if (pMap == nullptr) {
pMap = parent->default_map;
if(pMap == nullptr)
{
}
if (pMap == nullptr) {
parent->destination = nullptr;
return false;
}
@@ -261,20 +273,15 @@ bool idle_tile_finder::find_idle_tile(const level_map *pMap, int iStartX, int iS
int iWidth = pMap->get_width();
path_node* pPossibleResult = nullptr;
while(true)
{
while (true) {
pNode->open_idx = -1;
map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags;
if(!flags.do_not_idle && flags.passable && flags.hospital)
{
if(iN == 0)
{
if (!flags.do_not_idle && flags.passable && flags.hospital) {
if (iN == 0) {
parent->destination = pNode;
return true;
}
else
{
} else {
pPossibleResult = pNode;
--iN;
}
@@ -283,50 +290,51 @@ bool idle_tile_finder::find_idle_tile(const level_map *pMap, int iStartX, int iS
best_next_node = nullptr;
best_distance = 0.0;
if (search_neighbours(pNode, flags, iWidth)) return true;
if (search_neighbours(pNode, flags, iWidth)) {
return true;
}
if (parent->open_heap.empty()) {
parent->destination = nullptr;
break;
}
if(best_next_node)
{
if (best_next_node) {
// Promote the best neighbour to the front of the open list
// This causes sequential iN to give neighbouring results for most iN
// This causes sequential iN to give neighbouring results for most
// iN
best_next_node->guess = -best_next_node->distance;
parent->open_heap_promote(best_next_node);
}
pNode = parent->pop_from_open_heap();
}
if(pPossibleResult)
{
if (pPossibleResult) {
parent->destination = pPossibleResult;
return true;
}
return false;
}
int object_visitor::guess_distance(path_node *pNode)
{
return 0;
}
int object_visitor::guess_distance(path_node* pNode) { return 0; }
bool object_visitor::try_node(path_node *pNode, map_tile_flags flags, path_node *pNeighbour, travel_direction direction)
{
bool object_visitor::try_node(path_node* pNode, map_tile_flags flags,
path_node* pNeighbour,
travel_direction direction) {
int iObjectNumber = 0;
const map_tile *pMapNode = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y);
map_tile_flags neighbour_flags = map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
for(auto thob : pMapNode->objects)
{
if(thob == target)
const map_tile* pMapNode =
map->get_tile_unchecked(pNeighbour->x, pNeighbour->y);
map_tile_flags neighbour_flags =
map->get_tile_unchecked(pNeighbour->x, pNeighbour->y)->flags;
for (auto thob : pMapNode->objects) {
if (thob == target) {
iObjectNumber++;
}
if(target_any_object_type)
}
if (target_any_object_type) {
iObjectNumber = 1;
}
bool bSucces = false;
for(int i = 0; i < iObjectNumber; i++)
{
for (int i = 0; i < iObjectNumber; i++) {
/* call the given Lua function, passing four arguments: */
/* The x and y position of the object (Lua tile co-ords) */
/* The direction which was last travelled in to reach (x,y); */
@@ -338,51 +346,57 @@ bool object_visitor::try_node(path_node *pNode, map_tile_flags flags, path_node
lua_pushinteger(L, static_cast<int>(direction));
lua_pushinteger(L, pNode->distance);
lua_call(L, 4, 1);
if(lua_toboolean(L, -1) != 0)
{
if (lua_toboolean(L, -1) != 0) {
bSucces = true;
}
lua_pop(L, 1);
}
if(bSucces)
if (bSucces) {
return true;
}
if(pNode->distance < max_distance)
{
switch(direction)
{
if (pNode->distance < max_distance) {
switch (direction) {
case travel_direction::north:
if(!flags.door_north)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!flags.door_north) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
case travel_direction::east:
if(!neighbour_flags.door_west)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!neighbour_flags.door_west) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
case travel_direction::south:
if(!neighbour_flags.door_north)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!neighbour_flags.door_north) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
case travel_direction::west:
if(!flags.door_west)
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable, pNeighbour);
if (!flags.door_west) {
record_neighbour_if_passable(pNode, neighbour_flags, flags.passable,
pNeighbour);
}
break;
}
}
return false;
}
bool object_visitor::visit_objects(const level_map *pMap, int iStartX, int iStartY,
object_type eTHOB, int iMaxDistance,
lua_State *L, int iVisitFunction, bool anyObjectType)
{
if(pMap == nullptr)
bool object_visitor::visit_objects(const level_map* pMap, int iStartX,
int iStartY, object_type eTHOB,
int iMaxDistance, lua_State* L,
int iVisitFunction, bool anyObjectType) {
if (pMap == nullptr) {
pMap = parent->default_map;
if(pMap == nullptr)
{
}
if (pMap == nullptr) {
parent->destination = nullptr;
return false;
}
@@ -397,10 +411,11 @@ bool object_visitor::visit_objects(const level_map *pMap, int iStartX, int iStar
path_node* pNode = init(pMap, iStartX, iStartY);
int iWidth = pMap->get_width();
while(true)
{
while (true) {
map_tile_flags flags = pMap->get_tile_unchecked(pNode->x, pNode->y)->flags;
if (search_neighbours(pNode, flags, iWidth)) return true;
if (search_neighbours(pNode, flags, iWidth)) {
return true;
}
if (parent->open_heap.empty()) {
parent->destination = nullptr;
@@ -412,10 +427,12 @@ bool object_visitor::visit_objects(const level_map *pMap, int iStartX, int iStar
return false;
}
pathfinder::pathfinder() : basic_pathfinder(this), hospital_finder(this),
idle_tile_finder(this), object_visitor(this),
open_heap()
{
pathfinder::pathfinder()
: basic_pathfinder(this),
hospital_finder(this),
idle_tile_finder(this),
object_visitor(this),
open_heap() {
nodes = nullptr;
dirty_node_list = nullptr;
destination = nullptr;
@@ -425,30 +442,20 @@ pathfinder::pathfinder() : basic_pathfinder(this), hospital_finder(this),
dirty_node_count = 0;
}
pathfinder::~pathfinder()
{
pathfinder::~pathfinder() {
delete[] nodes;
delete[] dirty_node_list;
}
void pathfinder::set_default_map(const level_map *pMap)
{
default_map = pMap;
}
void pathfinder::set_default_map(const level_map* pMap) { default_map = pMap; }
void pathfinder::allocate_node_cache(int iWidth, int iHeight)
{
if(node_cache_width != iWidth || node_cache_height != iHeight)
{
void pathfinder::allocate_node_cache(int iWidth, int iHeight) {
if (node_cache_width != iWidth || node_cache_height != iHeight) {
delete[] nodes;
nodes = new path_node[iWidth * iHeight];
path_node* pNode = nodes;
for(int iY = 0; iY < iHeight; ++iY)
{
for(int iX = 0; iX < iWidth; ++iX, ++pNode)
{
for (int iY = 0; iY < iHeight; ++iY) {
for (int iX = 0; iX < iWidth; ++iX, ++pNode) {
pNode->prev = pNode;
pNode->x = iX;
pNode->y = iY;
@@ -460,11 +467,8 @@ void pathfinder::allocate_node_cache(int iWidth, int iHeight)
dirty_node_list = new path_node*[iWidth * iHeight];
node_cache_width = iWidth;
node_cache_height = iHeight;
}
else
{
for(int i = 0; i < dirty_node_count; ++i)
{
} else {
for (int i = 0; i < dirty_node_count; ++i) {
dirty_node_list[i]->prev = dirty_node_list[i];
// Other fields are undefined as the node is not part of a path,
// and thus can keep their old values.
@@ -473,37 +477,37 @@ void pathfinder::allocate_node_cache(int iWidth, int iHeight)
dirty_node_count = 0;
}
int pathfinder::get_path_length() const
{
if(destination != nullptr)
int pathfinder::get_path_length() const {
if (destination != nullptr) {
return destination->distance;
else
} else {
return -1;
}
}
bool pathfinder::get_path_end(int* pX, int* pY) const
{
if(destination == nullptr)
{
if(pX)
bool pathfinder::get_path_end(int* pX, int* pY) const {
if (destination == nullptr) {
if (pX) {
*pX = -1;
if(pY)
}
if (pY) {
*pY = -1;
}
return false;
}
if(pX)
if (pX) {
*pX = destination->x;
if(pY)
}
if (pY) {
*pY = destination->y;
}
return true;
}
void pathfinder::push_result(lua_State *L) const
{
void pathfinder::push_result(lua_State* L) const {
lua_checkstack(L, 3);
if(destination == nullptr)
{
if (destination == nullptr) {
lua_pushnil(L);
lua_pushliteral(L, "no path");
return;
@@ -513,8 +517,7 @@ void pathfinder::push_result(lua_State *L) const
lua_createtable(L, iLength + 1, 0);
lua_createtable(L, iLength + 1, 0);
for(const path_node* pNode = destination; pNode; pNode = pNode->prev)
{
for (const path_node* pNode = destination; pNode; pNode = pNode->prev) {
lua_pushinteger(L, pNode->x + 1);
lua_rawseti(L, -3, pNode->distance + 1);
lua_pushinteger(L, pNode->y + 1);
@@ -522,22 +525,20 @@ void pathfinder::push_result(lua_State *L) const
}
}
void pathfinder::push_to_open_heap(path_node* pNode)
{
void pathfinder::push_to_open_heap(path_node* pNode) {
pNode->open_idx = open_heap.size();
open_heap.push_back(pNode);
open_heap_promote(pNode);
}
void pathfinder::open_heap_promote(path_node* pNode)
{
void pathfinder::open_heap_promote(path_node* pNode) {
int i = pNode->open_idx;
while(i > 0)
{
while (i > 0) {
int parent = (i - 1) / 2;
path_node* pParent = open_heap[parent];
if(pParent->value() <= pNode->value())
if (pParent->value() <= pNode->value()) {
break;
}
pParent->open_idx = i;
open_heap[i] = pParent;
open_heap[parent] = pNode;
@@ -546,8 +547,7 @@ void pathfinder::open_heap_promote(path_node* pNode)
pNode->open_idx = i;
}
path_node* pathfinder::pop_from_open_heap()
{
path_node* pathfinder::pop_from_open_heap() {
path_node* pResult = open_heap[0];
path_node* pNode = open_heap.back();
open_heap.pop_back();
@@ -561,23 +561,27 @@ path_node* pathfinder::pop_from_open_heap()
int min = 0;
int left = i * 2 + 1;
const int value = pNode->value();
while(left < open_heap.size())
{
while (left < open_heap.size()) {
min = i;
const int right = (i + 1) * 2;
int minvalue = value;
path_node* pSwap = nullptr;
path_node* pTest = open_heap[left];
if(pTest->value() < minvalue)
min = left, minvalue = pTest->value(), pSwap = pTest;
if(right < open_heap.size())
{
pTest = open_heap[right];
if(pTest->value() < minvalue)
min = right, pSwap = pTest;
if (pTest->value() < minvalue) {
min = left;
minvalue = pTest->value();
pSwap = pTest;
}
if(min == i)
if (right < open_heap.size()) {
pTest = open_heap[right];
if (pTest->value() < minvalue) {
min = right;
pSwap = pTest;
}
}
if (min == i) {
break;
}
pSwap->open_idx = i;
open_heap[i] = pSwap;
@@ -589,45 +593,45 @@ path_node* pathfinder::pop_from_open_heap()
return pResult;
}
void pathfinder::persist(lua_persist_writer *pWriter) const
{
if(destination == nullptr)
{
void pathfinder::persist(lua_persist_writer* pWriter) const {
if (destination == nullptr) {
pWriter->write_uint(0);
return;
}
pWriter->write_uint(get_path_length() + 1);
pWriter->write_uint(node_cache_width);
pWriter->write_uint(node_cache_height);
for(const path_node* pNode = destination; pNode; pNode = pNode->prev)
{
for (const path_node* pNode = destination; pNode; pNode = pNode->prev) {
pWriter->write_uint(pNode->x);
pWriter->write_uint(pNode->y);
}
}
void pathfinder::depersist(lua_persist_reader *pReader)
{
void pathfinder::depersist(lua_persist_reader* pReader) {
new (this) pathfinder; // Call constructor
int iLength;
if(!pReader->read_uint(iLength))
if (!pReader->read_uint(iLength)) {
return;
if(iLength == 0)
}
if (iLength == 0) {
return;
}
int iWidth, iHeight;
if(!pReader->read_uint(iWidth) || !pReader->read_uint(iHeight))
if (!pReader->read_uint(iWidth) || !pReader->read_uint(iHeight)) {
return;
}
allocate_node_cache(iWidth, iHeight);
int iX, iY;
if(!pReader->read_uint(iX) || !pReader->read_uint(iY))
if (!pReader->read_uint(iX) || !pReader->read_uint(iY)) {
return;
}
path_node* pNode = nodes + iY * iWidth + iX;
destination = pNode;
for(int i = 0; i <= iLength - 2; ++i)
{
if(!pReader->read_uint(iX) || !pReader->read_uint(iY))
for (int i = 0; i <= iLength - 2; ++i) {
if (!pReader->read_uint(iX) || !pReader->read_uint(iY)) {
return;
}
path_node* pPrevNode = nodes + iY * iWidth + iX;
pNode->distance = iLength - 1 - i;
pNode->prev = pPrevNode;

View File

@@ -37,8 +37,7 @@ enum class travel_direction {
};
/** Node in the path finder routines. */
struct path_node
{
struct path_node {
//! Pointer to the previous node in the path to this cell.
/*!
Points to nullptr if this is the first cell in the path, or points to
@@ -74,14 +73,14 @@ struct path_node
//! Total cost of this node.
/*!
@return Total cost of the node, traveled distance and guess to the destination.
@return Total cost of the node, traveled distance and guess to the
destination.
*/
inline int value() const { return distance + guess; }
};
/** Base class of the path finders. */
class abstract_pathfinder
{
class abstract_pathfinder {
public:
abstract_pathfinder(pathfinder* pf);
virtual ~abstract_pathfinder() = default;
@@ -104,7 +103,8 @@ public:
*/
bool search_neighbours(path_node* pNode, map_tile_flags flags, int iWidth);
void record_neighbour_if_passable(path_node *pNode, map_tile_flags neighbour_flags,
void record_neighbour_if_passable(path_node* pNode,
map_tile_flags neighbour_flags,
bool passable, path_node* pNeighbour);
//! Guess distance to the destination for \a pNode.
@@ -129,41 +129,39 @@ protected:
const level_map* map; ///< Map being searched.
};
class basic_pathfinder : public abstract_pathfinder
{
class basic_pathfinder : public abstract_pathfinder {
public:
basic_pathfinder(pathfinder* pf) : abstract_pathfinder(pf) {}
int guess_distance(path_node* pNode) override;
bool try_node(path_node *pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction) override;
bool try_node(path_node* pNode, map_tile_flags flags, path_node* pNeighbour,
travel_direction direction) override;
bool find_path(const level_map *pMap, int iStartX, int iStartY, int iEndX, int iEndY);
bool find_path(const level_map* pMap, int iStartX, int iStartY, int iEndX,
int iEndY);
int destination_x; ///< X coordinate of the destination of the path.
int destination_y; ///< Y coordinate of the destination of the path.
};
class hospital_finder : public abstract_pathfinder
{
class hospital_finder : public abstract_pathfinder {
public:
hospital_finder(pathfinder* pf) : abstract_pathfinder(pf) {}
int guess_distance(path_node* pNode) override;
bool try_node(path_node *pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction) override;
bool try_node(path_node* pNode, map_tile_flags flags, path_node* pNeighbour,
travel_direction direction) override;
bool find_path_to_hospital(const level_map* pMap, int iStartX, int iStartY);
};
class idle_tile_finder : public abstract_pathfinder
{
class idle_tile_finder : public abstract_pathfinder {
public:
idle_tile_finder(pathfinder* pf) : abstract_pathfinder(pf) {}
int guess_distance(path_node* pNode) override;
bool try_node(path_node *pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction) override;
bool try_node(path_node* pNode, map_tile_flags flags, path_node* pNeighbour,
travel_direction direction) override;
bool find_idle_tile(const level_map* pMap, int iStartX, int iStartY, int iN);
@@ -173,18 +171,17 @@ public:
int start_y; ///< Y coordinate of the start position.
};
class object_visitor : public abstract_pathfinder
{
class object_visitor : public abstract_pathfinder {
public:
object_visitor(pathfinder* pf) : abstract_pathfinder(pf) {}
int guess_distance(path_node* pNode) override;
bool try_node(path_node *pNode, map_tile_flags flags,
path_node *pNeighbour, travel_direction direction) override;
bool try_node(path_node* pNode, map_tile_flags flags, path_node* pNeighbour,
travel_direction direction) override;
bool visit_objects(const level_map* pMap, int iStartX, int iStartY,
object_type eTHOB, int iMaxDistance,
lua_State *L, int iVisitFunction, bool anyObjectType);
object_type eTHOB, int iMaxDistance, lua_State* L,
int iVisitFunction, bool anyObjectType);
lua_State* L;
int visit_function_index;
@@ -208,37 +205,34 @@ public:
the current search. The algorithm is implemented in such a way that most
path find operations do not need to allocate (or free) any memory.
*/
class pathfinder
{
class pathfinder {
public:
pathfinder();
~pathfinder();
void set_default_map(const level_map* pMap);
inline bool find_path(const level_map *pMap, int iStartX, int iStartY, int iEndX,
int iEndY)
{
inline bool find_path(const level_map* pMap, int iStartX, int iStartY,
int iEndX, int iEndY) {
return basic_pathfinder.find_path(pMap, iStartX, iStartY, iEndX, iEndY);
}
inline bool find_idle_tile(const level_map *pMap, int iStartX, int iStartY, int iN)
{
inline bool find_idle_tile(const level_map* pMap, int iStartX, int iStartY,
int iN) {
return idle_tile_finder.find_idle_tile(pMap, iStartX, iStartY, iN);
}
inline bool find_path_to_hospital(const level_map *pMap, int iStartX, int iStartY)
{
inline bool find_path_to_hospital(const level_map* pMap, int iStartX,
int iStartY) {
return hospital_finder.find_path_to_hospital(pMap, iStartX, iStartY);
}
inline bool visit_objects(const level_map* pMap, int iStartX, int iStartY,
object_type eTHOB, int iMaxDistance, lua_State* L,
int iVisitFunction, bool anyObjectType)
{
return object_visitor.visit_objects(
pMap, iStartX, iStartY, eTHOB, iMaxDistance,
L, iVisitFunction, anyObjectType);
int iVisitFunction, bool anyObjectType) {
return object_visitor.visit_objects(pMap, iStartX, iStartY, eTHOB,
iMaxDistance, L, iVisitFunction,
anyObjectType);
}
int get_path_length() const;

View File

@@ -20,66 +20,63 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "th_sound.h"
#include "th.h"
#include "config.h"
#include <cmath>
#include <new>
#include <cstring>
#include <new>
#include "th.h"
sound_archive::sound_archive()
{
sound_archive::sound_archive() {
sound_files = nullptr;
data = nullptr;
}
sound_archive::~sound_archive()
{
delete[] data;
sound_archive::~sound_archive() { delete[] data; }
bool sound_archive::load_from_th_file(const uint8_t* pData,
size_t iDataLength) {
if (iDataLength < sizeof(uint32_t) + sizeof(sound_dat_file_header)) {
return false;
}
bool sound_archive::load_from_th_file(const uint8_t* pData, size_t iDataLength)
{
if(iDataLength < sizeof(uint32_t) + sizeof(sound_dat_file_header))
uint32_t iHeaderPosition =
bytes_to_uint32_le(pData + iDataLength - sizeof(uint32_t));
if (static_cast<size_t>(iHeaderPosition) >=
iDataLength - sizeof(sound_dat_file_header)) {
return false;
}
uint32_t iHeaderPosition = bytes_to_uint32_le(pData + iDataLength - sizeof(uint32_t));
if(static_cast<size_t>(iHeaderPosition) >= iDataLength - sizeof(sound_dat_file_header))
return false;
header = *reinterpret_cast<const sound_dat_file_header*>(pData + iHeaderPosition);
header =
*reinterpret_cast<const sound_dat_file_header*>(pData + iHeaderPosition);
delete[] data;
data = new (std::nothrow) uint8_t[iDataLength];
if(data == nullptr)
if (data == nullptr) {
return false;
}
std::memcpy(data, pData, iDataLength);
sound_files = reinterpret_cast<sound_dat_sound_info*>(data + header.table_position);
sound_files =
reinterpret_cast<sound_dat_sound_info*>(data + header.table_position);
sound_file_count = header.table_length / sizeof(sound_dat_sound_info);
return true;
}
size_t sound_archive::get_number_of_sounds() const
{
return sound_file_count;
}
size_t sound_archive::get_number_of_sounds() const { return sound_file_count; }
const char* sound_archive::get_sound_name(size_t iIndex) const
{
if(iIndex >= sound_file_count)
return nullptr;
const char* sound_archive::get_sound_name(size_t iIndex) const {
if (iIndex >= sound_file_count) return nullptr;
return sound_files[iIndex].sound_name;
}
constexpr uint32_t fourcc(const char c1, const char c2, const char c3, const char c4)
{
return (
(static_cast<uint32_t>(static_cast<uint8_t>(c1)) << 0)
| (static_cast<uint32_t>(static_cast<uint8_t>(c2)) << 8)
| (static_cast<uint32_t>(static_cast<uint8_t>(c3)) << 16)
| (static_cast<uint32_t>(static_cast<uint8_t>(c4)) << 24));
constexpr uint32_t fourcc(const char c1, const char c2, const char c3,
const char c4) {
return ((static_cast<uint32_t>(static_cast<uint8_t>(c1)) << 0) |
(static_cast<uint32_t>(static_cast<uint8_t>(c2)) << 8) |
(static_cast<uint32_t>(static_cast<uint8_t>(c3)) << 16) |
(static_cast<uint32_t>(static_cast<uint8_t>(c4)) << 24));
}
namespace {
@@ -91,11 +88,11 @@ inline uint64_t mul64(A a, B b) {
} // namespace
size_t sound_archive::get_sound_duration(size_t iIndex)
{
size_t sound_archive::get_sound_duration(size_t iIndex) {
SDL_RWops* pFile = load_sound(iIndex);
if(!pFile)
if (!pFile) {
return 0;
}
uint16_t iWaveAudioFormat = 0;
uint16_t iWaveChannelCount = 0;
@@ -108,63 +105,69 @@ size_t sound_archive::get_sound_duration(size_t iIndex)
// This is a very crude RIFF parser, but it does the job.
uint32_t iFourCC;
uint32_t iChunkLength;
for(;;)
{
if(SDL_RWread(pFile, &iFourCC, 4, 1) != 1)
for (;;) {
if (SDL_RWread(pFile, &iFourCC, 4, 1) != 1) {
break;
if(SDL_RWread(pFile, &iChunkLength, 4, 1) != 1)
}
if (SDL_RWread(pFile, &iChunkLength, 4, 1) != 1) {
break;
if(iFourCC == fourcc('R','I','F','F') || iFourCC == fourcc('L','I','S','T'))
{
if(iChunkLength >= 4)
{
if(SDL_RWread(pFile, &iFourCC, 4, 1) != 1)
}
if (iFourCC == fourcc('R', 'I', 'F', 'F') ||
iFourCC == fourcc('L', 'I', 'S', 'T')) {
if (iChunkLength >= 4) {
if (SDL_RWread(pFile, &iFourCC, 4, 1) != 1) {
break;
else
} else {
continue;
}
}
if(iFourCC == fourcc('f','m','t',' ') && iChunkLength >= 16)
{
if(SDL_RWread(pFile, &iWaveAudioFormat, 2, 1) != 1)
}
if (iFourCC == fourcc('f', 'm', 't', ' ') && iChunkLength >= 16) {
if (SDL_RWread(pFile, &iWaveAudioFormat, 2, 1) != 1) {
break;
if(SDL_RWread(pFile, &iWaveChannelCount, 2, 1) != 1)
}
if (SDL_RWread(pFile, &iWaveChannelCount, 2, 1) != 1) {
break;
if(SDL_RWread(pFile, &iWaveSampleRate, 4, 1) != 1)
}
if (SDL_RWread(pFile, &iWaveSampleRate, 4, 1) != 1) {
break;
if(SDL_RWread(pFile, &iWaveByteRate, 4, 1) != 1)
}
if (SDL_RWread(pFile, &iWaveByteRate, 4, 1) != 1) {
break;
if(SDL_RWread(pFile, &iWaveBlockAlign, 2, 1) != 1)
}
if (SDL_RWread(pFile, &iWaveBlockAlign, 2, 1) != 1) {
break;
if(SDL_RWread(pFile, &iWaveBitsPerSample, 2, 1) != 1)
}
if (SDL_RWread(pFile, &iWaveBitsPerSample, 2, 1) != 1) {
break;
}
iChunkLength -= 16;
}
// Finally:
if(iFourCC == fourcc('d','a','t','a'))
{
if (iFourCC == fourcc('d', 'a', 't', 'a')) {
iWaveDataLength = iChunkLength;
break;
}
if(SDL_RWseek(pFile, iChunkLength + (iChunkLength & 1), RW_SEEK_CUR) == -1) {
if (SDL_RWseek(pFile, iChunkLength + (iChunkLength & 1), RW_SEEK_CUR) ==
-1) {
break;
}
}
SDL_RWclose(pFile);
if(iWaveAudioFormat != 1 || iWaveChannelCount == 0 || iWaveSampleRate == 0
|| iWaveDataLength == 0 || iWaveBitsPerSample == 0)
{
if (iWaveAudioFormat != 1 || iWaveChannelCount == 0 || iWaveSampleRate == 0 ||
iWaveDataLength == 0 || iWaveBitsPerSample == 0) {
return 0;
}
return static_cast<size_t>(mul64(iWaveDataLength, 8000) /
return static_cast<size_t>(
mul64(iWaveDataLength, 8000) /
mul64(mul64(iWaveBitsPerSample, iWaveChannelCount), iWaveSampleRate));
}
SDL_RWops* sound_archive::load_sound(size_t iIndex)
{
if(iIndex >= sound_file_count)
SDL_RWops* sound_archive::load_sound(size_t iIndex) {
if (iIndex >= sound_file_count) {
return nullptr;
}
sound_dat_sound_info* pFile = sound_files + iIndex;
return SDL_RWFromConstMem(data + pFile->position, pFile->length);
@@ -176,8 +179,7 @@ constexpr int number_of_channels = 32;
sound_player* sound_player::singleton = nullptr;
sound_player::sound_player()
{
sound_player::sound_player() {
sounds = nullptr;
sound_count = 0;
singleton = this;
@@ -195,125 +197,112 @@ sound_player::sound_player()
Mix_ChannelFinished(on_channel_finished);
}
sound_player::~sound_player()
{
sound_player::~sound_player() {
populate_from(nullptr);
if(singleton == this)
if (singleton == this) {
singleton = nullptr;
}
}
void sound_player::on_channel_finished(int iChannel)
{
void sound_player::on_channel_finished(int iChannel) {
sound_player* pThis = get_singleton();
if(pThis == nullptr)
return;
if (pThis == nullptr) return;
pThis->release_channel(iChannel);
}
sound_player* sound_player::get_singleton()
{
return singleton;
}
sound_player* sound_player::get_singleton() { return singleton; }
void sound_player::populate_from(sound_archive *pArchive)
{
for(size_t i = 0; i < sound_count; ++i)
{
void sound_player::populate_from(sound_archive* pArchive) {
for (size_t i = 0; i < sound_count; ++i) {
Mix_FreeChunk(sounds[i]);
}
delete[] sounds;
sounds = nullptr;
sound_count = 0;
if(pArchive == nullptr)
return;
if (pArchive == nullptr) return;
sounds = new Mix_Chunk*[pArchive->get_number_of_sounds()];
for(; sound_count < pArchive->get_number_of_sounds(); ++sound_count)
{
for (; sound_count < pArchive->get_number_of_sounds(); ++sound_count) {
sounds[sound_count] = nullptr;
SDL_RWops* pRwop = pArchive->load_sound(sound_count);
if(pRwop)
{
if (pRwop) {
sounds[sound_count] = Mix_LoadWAV_RW(pRwop, 1);
if(sounds[sound_count])
if (sounds[sound_count]) {
Mix_VolumeChunk(sounds[sound_count], MIX_MAX_VOLUME);
}
}
}
}
void sound_player::play(size_t iIndex, double dVolume)
{
if(available_channels_bitmap == 0 || iIndex >= sound_count || !sounds[iIndex])
void sound_player::play(size_t iIndex, double dVolume) {
if (available_channels_bitmap == 0 || iIndex >= sound_count ||
!sounds[iIndex]) {
return;
}
play_raw(iIndex, (int)(positionless_volume * dVolume));
}
void sound_player::play_at(size_t iIndex, int iX, int iY)
{
if(sound_effects_enabled)
void sound_player::play_at(size_t iIndex, int iX, int iY) {
if (sound_effects_enabled) {
play_at(iIndex, sound_effect_volume, iX, iY);
}
}
void sound_player::play_at(size_t iIndex, double dVolume, int iX, int iY)
{
if(available_channels_bitmap == 0 || iIndex >= sound_count || !sounds[iIndex])
void sound_player::play_at(size_t iIndex, double dVolume, int iX, int iY) {
if (available_channels_bitmap == 0 || iIndex >= sound_count ||
!sounds[iIndex]) {
return;
}
double fDX = (double)(iX - camera_x);
double fDY = (double)(iY - camera_y);
double fDistance = sqrt(fDX * fDX + fDY * fDY);
if(fDistance > camera_radius)
return;
if (fDistance > camera_radius) return;
fDistance = fDistance / camera_radius;
double fVolume = master_volume * (1.0 - fDistance * 0.8) * (double)MIX_MAX_VOLUME * dVolume;
double fVolume = master_volume * (1.0 - fDistance * 0.8) *
(double)MIX_MAX_VOLUME * dVolume;
play_raw(iIndex, (int)(fVolume + 0.5));
}
void sound_player::set_sound_effect_volume(double dVolume)
{
void sound_player::set_sound_effect_volume(double dVolume) {
sound_effect_volume = dVolume;
}
void sound_player::set_sound_effects_enabled(bool bOn)
{
void sound_player::set_sound_effects_enabled(bool bOn) {
sound_effects_enabled = bOn;
}
int sound_player::reserve_channel()
{
int sound_player::reserve_channel() {
// NB: Callers ensure that m_iChannelStatus != 0
int iChannel = 0;
for(; (available_channels_bitmap & (1 << iChannel)) == 0; ++iChannel) {}
for (; (available_channels_bitmap & (1 << iChannel)) == 0; ++iChannel) {
}
available_channels_bitmap &= ~(1 << iChannel);
return iChannel;
}
void sound_player::release_channel(int iChannel)
{
void sound_player::release_channel(int iChannel) {
available_channels_bitmap |= (1 << iChannel);
}
void sound_player::play_raw(size_t iIndex, int iVolume)
{
void sound_player::play_raw(size_t iIndex, int iVolume) {
int iChannel = reserve_channel();
Mix_Volume(iChannel, iVolume);
Mix_PlayChannelTimed(iChannel, sounds[iIndex], 0, -1);
}
void sound_player::set_camera(int iX, int iY, int iRadius)
{
void sound_player::set_camera(int iX, int iY, int iRadius) {
camera_x = iX;
camera_y = iY;
camera_radius = (double)iRadius;
if(camera_radius < 0.001)
camera_radius = 0.001;
if (camera_radius < 0.001) camera_radius = 0.001;
}
#else // CORSIX_TH_USE_SDL_MIXER

View File

@@ -22,14 +22,14 @@ SOFTWARE.
#ifndef CORSIX_TH_TH_SOUND_H_
#define CORSIX_TH_TH_SOUND_H_
#include "config.h"
#include <SDL.h>
#ifdef CORSIX_TH_USE_SDL_MIXER
#include <SDL_mixer.h>
#endif
//! Utility class for accessing Theme Hospital's SOUND-0.DAT
class sound_archive
{
class sound_archive {
public:
sound_archive();
~sound_archive();
@@ -56,8 +56,7 @@ private:
#pragma pack(push)
#pragma pack(1)
#endif
struct sound_dat_file_header
{
struct sound_dat_file_header {
uint8_t unknown1[50];
uint32_t table_position;
uint32_t unknown2;
@@ -69,8 +68,7 @@ private:
uint8_t unknown4[48];
} CORSIX_TH_PACKED_FLAGS;
struct sound_dat_sound_info
{
struct sound_dat_sound_info {
char sound_name[18];
uint32_t position;
uint32_t unknown1;
@@ -88,8 +86,7 @@ private:
size_t sound_file_count;
};
class sound_player
{
class sound_player {
public:
sound_player();
~sound_player();
@@ -116,7 +113,10 @@ private:
Mix_Chunk** sounds;
size_t sound_count;
uint32_t available_channels_bitmap; ///< The bit index corresponding to a channel is 1 if the channel is available and 0 if it is reserved or in use.
uint32_t available_channels_bitmap; ///< The bit index corresponding to a
///< channel is 1 if the channel is
///< available and 0 if it is reserved
///< or in use.
int camera_x;
int camera_y;
double camera_radius;

View File

@@ -22,8 +22,8 @@ SOFTWARE.
#include "config.h"
#ifdef CORSIX_TH_USE_SDL_MIXER
#include <cstring>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <new>
#include <vector>
@@ -31,95 +31,71 @@ SOFTWARE.
/*!
Utility class for reading or writing to memory as if it were a file.
*/
class memory_buffer
{
class memory_buffer {
public:
memory_buffer()
: data(nullptr), pointer(nullptr), data_end(nullptr), buffer_end(nullptr)
{
}
: data(nullptr),
pointer(nullptr),
data_end(nullptr),
buffer_end(nullptr) {}
memory_buffer(const uint8_t* pData, size_t iLength)
{
memory_buffer(const uint8_t* pData, size_t iLength) {
data = pointer = (char*)pData;
data_end = data + iLength;
buffer_end = nullptr;
}
~memory_buffer()
{
if(buffer_end != nullptr)
delete[] data;
~memory_buffer() {
if (buffer_end != nullptr) delete[] data;
}
uint8_t* take_data(size_t *pLength)
{
if(pLength)
*pLength = data_end - data;
uint8_t* take_data(size_t* pLength) {
if (pLength) *pLength = data_end - data;
uint8_t* pResult = (unsigned char*)data;
data = pointer = data_end = buffer_end = nullptr;
return pResult;
}
size_t tell() const
{
return pointer - data;
}
size_t tell() const { return pointer - data; }
bool seek(size_t position)
{
if(data + position > data_end)
{
if(!resize_buffer(position))
return false;
bool seek(size_t position) {
if (data + position > data_end) {
if (!resize_buffer(position)) return false;
}
pointer = data + position;
return true;
}
bool skip(int distance)
{
if(distance < 0)
{
if(pointer + distance < data)
return false;
bool skip(int distance) {
if (distance < 0) {
if (pointer + distance < data) return false;
}
return seek(pointer - data + distance);
}
bool scan_to(const void* pData, size_t iLength)
{
for(; pointer + iLength <= data_end; ++pointer)
{
if(std::memcmp(pointer, pData, iLength) == 0)
return true;
bool scan_to(const void* pData, size_t iLength) {
for (; pointer + iLength <= data_end; ++pointer) {
if (std::memcmp(pointer, pData, iLength) == 0) return true;
}
return false;
}
const char* get_pointer() const
{
return pointer;
}
const char* get_pointer() const { return pointer; }
template <class T>
bool read(T& value)
{
bool read(T& value) {
return read(&value, 1);
}
template <class T>
bool read(T* values, size_t count)
{
if(pointer + sizeof(T) * count > data_end)
return false;
bool read(T* values, size_t count) {
if (pointer + sizeof(T) * count > data_end) return false;
std::memcpy(values, pointer, sizeof(T) * count);
pointer += sizeof(T) * count;
return true;
}
unsigned int read_big_endian_uint24()
{
unsigned int read_big_endian_uint24() {
uint8_t iByte0, iByte1, iByte2;
if (read(iByte0) && read(iByte1) && read(iByte2))
return (((iByte0 << 8) | iByte1) << 8) | iByte2;
@@ -127,99 +103,78 @@ public:
return 0;
}
unsigned int read_variable_length_uint()
{
unsigned int read_variable_length_uint() {
unsigned int iValue = 0;
uint8_t iByte;
for(int i = 0; i < 4; ++i)
{
if(!read(iByte))
return false;
for (int i = 0; i < 4; ++i) {
if (!read(iByte)) return false;
iValue = (iValue << 7) | static_cast<unsigned int>(iByte & 0x7F);
if((iByte & 0x80) == 0)
break;
if ((iByte & 0x80) == 0) break;
}
return iValue;
}
template <class T>
bool write(const T& value)
{
bool write(const T& value) {
return write(&value, 1);
}
template <class T>
bool write(const T* values, size_t count)
{
if(!skip(static_cast<int>(sizeof(T) * count)))
return false;
bool write(const T* values, size_t count) {
if (!skip(static_cast<int>(sizeof(T) * count))) return false;
std::memcpy(pointer - sizeof(T) * count, values, sizeof(T) * count);
return true;
}
bool write_big_endian_uint16(uint16_t iValue)
{
bool write_big_endian_uint16(uint16_t iValue) {
return write(byte_swap(iValue));
}
bool write_big_endian_uint32(uint32_t iValue)
{
bool write_big_endian_uint32(uint32_t iValue) {
return write(byte_swap(iValue));
}
bool write_variable_length_uint(unsigned int iValue)
{
bool write_variable_length_uint(unsigned int iValue) {
int iByteCount = 1;
unsigned int iBuffer = iValue & 0x7F;
for(; iValue >>= 7; ++iByteCount)
{
for (; iValue >>= 7; ++iByteCount) {
iBuffer = (iBuffer << 8) | 0x80 | (iValue & 0x7F);
}
for(int i = 0; i < iByteCount; ++i)
{
for (int i = 0; i < iByteCount; ++i) {
uint8_t iByte = iBuffer & 0xFF;
if(!write(iByte))
return false;
if (!write(iByte)) return false;
iBuffer >>= 8;
}
return true;
}
bool is_end_of_buffer() const
{
return pointer == data_end;
}
bool is_end_of_buffer() const { return pointer == data_end; }
private:
template <class T>
static T byte_swap(T value)
{
static T byte_swap(T value) {
T swapped = 0;
for(int i = 0; i < static_cast<int>(sizeof(T)) * 8; i += 8)
{
swapped = static_cast<T>(swapped | ((value >> i) & 0xFF) << (sizeof(T) * 8 - 8 - i));
for (int i = 0; i < static_cast<int>(sizeof(T)) * 8; i += 8) {
swapped = static_cast<T>(swapped | ((value >> i) & 0xFF)
<< (sizeof(T) * 8 - 8 - i));
}
return swapped;
}
bool resize_buffer(size_t size)
{
if(data + size <= buffer_end)
{
bool resize_buffer(size_t size) {
if (data + size <= buffer_end) {
data_end = data + size;
return true;
}
char* pNewData = new (std::nothrow) char[size * 2];
if(pNewData == nullptr)
return false;
if (pNewData == nullptr) return false;
size_t iOldLength = data_end - data;
if (iOldLength > 0) {
std::memcpy(pNewData, data, size > iOldLength ? iOldLength : size);
}
pointer = pointer - data + pNewData;
if(buffer_end != nullptr)
delete[] data;
if (buffer_end != nullptr) delete[] data;
data = pNewData;
data_end = pNewData + size;
buffer_end = pNewData + size * 2;
@@ -229,8 +184,7 @@ private:
char *data, *pointer, *data_end, *buffer_end;
};
struct midi_token
{
struct midi_token {
int time;
unsigned int buffer_length;
const char* buffer;
@@ -238,15 +192,12 @@ struct midi_token
uint8_t data;
};
bool operator < (const midi_token& oLeft, const midi_token& oRight)
{
bool operator<(const midi_token& oLeft, const midi_token& oRight) {
return oLeft.time < oRight.time;
}
struct midi_token_list : std::vector<midi_token>
{
midi_token* append(int iTime, uint8_t iType)
{
struct midi_token_list : std::vector<midi_token> {
midi_token* append(int iTime, uint8_t iType) {
push_back(midi_token());
midi_token* pToken = &back();
pToken->time = iTime;
@@ -255,15 +206,15 @@ struct midi_token_list : std::vector<midi_token>
}
};
uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
size_t xmi_length, size_t* midi_length)
{
if (xmi_data == nullptr) { return nullptr; }
uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data, size_t xmi_length,
size_t* midi_length) {
if (xmi_data == nullptr) {
return nullptr;
}
memory_buffer bufInput(xmi_data, xmi_length);
if(!bufInput.scan_to("EVNT", 4) || !bufInput.skip(8))
return nullptr;
if (!bufInput.scan_to("EVNT", 4) || !bufInput.skip(8)) return nullptr;
midi_token_list lstTokens;
midi_token* pToken;
@@ -273,12 +224,9 @@ uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
bool bEnd = false;
uint8_t iTokenType, iExtendedType;
while(!bufInput.is_end_of_buffer() && !bEnd)
{
while(true)
{
if(!bufInput.read(iTokenType))
return nullptr;
while (!bufInput.is_end_of_buffer() && !bEnd) {
while (true) {
if (!bufInput.read(iTokenType)) return nullptr;
if (iTokenType & 0x80)
break;
@@ -287,54 +235,42 @@ uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
}
pToken = lstTokens.append(iTokenTime, iTokenType);
pToken->buffer = bufInput.get_pointer() + 1;
switch(iTokenType & 0xF0)
{
switch (iTokenType & 0xF0) {
case 0xC0:
case 0xD0:
if(!bufInput.read(pToken->data))
return nullptr;
if (!bufInput.read(pToken->data)) return nullptr;
pToken->buffer = nullptr;
break;
case 0x80:
case 0xA0:
case 0xB0:
case 0xE0:
if(!bufInput.read(pToken->data))
return nullptr;
if(!bufInput.skip(1))
return nullptr;
if (!bufInput.read(pToken->data)) return nullptr;
if (!bufInput.skip(1)) return nullptr;
break;
case 0x90:
if(!bufInput.read(iExtendedType))
return nullptr;
if (!bufInput.read(iExtendedType)) return nullptr;
pToken->data = iExtendedType;
if(!bufInput.skip(1))
return nullptr;
pToken = lstTokens.append(iTokenTime + bufInput.read_variable_length_uint() * 3,
iTokenType);
if (!bufInput.skip(1)) return nullptr;
pToken = lstTokens.append(
iTokenTime + bufInput.read_variable_length_uint() * 3, iTokenType);
pToken->data = iExtendedType;
pToken->buffer = "\0";
break;
case 0xF0:
iExtendedType = 0;
if(iTokenType == 0xFF)
{
if(!bufInput.read(iExtendedType))
return nullptr;
if (iTokenType == 0xFF) {
if (!bufInput.read(iExtendedType)) return nullptr;
if (iExtendedType == 0x2F)
bEnd = true;
else if(iExtendedType == 0x51)
{
if(!bTempoSet)
{
else if (iExtendedType == 0x51) {
if (!bTempoSet) {
bufInput.skip(1);
iTempo = bufInput.read_big_endian_uint24() * 3;
bTempoSet = true;
bufInput.skip(-4);
}
else
{
} else {
lstTokens.pop_back();
if (!bufInput.skip(bufInput.read_variable_length_uint()))
return nullptr;
@@ -345,22 +281,19 @@ uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
pToken->data = iExtendedType;
pToken->buffer_length = bufInput.read_variable_length_uint();
pToken->buffer = bufInput.get_pointer();
if(!bufInput.skip(pToken->buffer_length))
return nullptr;
if (!bufInput.skip(pToken->buffer_length)) return nullptr;
break;
}
}
if(lstTokens.empty())
return nullptr;
if (lstTokens.empty()) return nullptr;
memory_buffer bufOutput;
if(!bufOutput.write("MThd\0\0\0\x06\0\0\0\x01", 12))
return nullptr;
if(!bufOutput.write_big_endian_uint16(static_cast<uint16_t>((iTempo * 3) / 25000)))
return nullptr;
if(!bufOutput.write("MTrk\xBA\xAD\xF0\x0D", 8))
if (!bufOutput.write("MThd\0\0\0\x06\0\0\0\x01", 12)) return nullptr;
if (!bufOutput.write_big_endian_uint16(
static_cast<uint16_t>((iTempo * 3) / 25000)))
return nullptr;
if (!bufOutput.write("MTrk\xBA\xAD\xF0\x0D", 8)) return nullptr;
std::sort(lstTokens.begin(), lstTokens.end());
@@ -369,40 +302,27 @@ uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
bEnd = false;
for (midi_token_list::iterator itr = lstTokens.begin(),
itrEnd = lstTokens.end(); itr != itrEnd && !bEnd; ++itr)
{
itrEnd = lstTokens.end();
itr != itrEnd && !bEnd; ++itr) {
if (!bufOutput.write_variable_length_uint(itr->time - iTokenTime))
return nullptr;
iTokenTime = itr->time;
if(itr->type >= 0xF0)
{
if(!bufOutput.write(iTokenType = itr->type))
return nullptr;
if(iTokenType == 0xFF)
{
if(!bufOutput.write(itr->data))
return nullptr;
if(itr->data == 0x2F)
bEnd = true;
if (itr->type >= 0xF0) {
if (!bufOutput.write(iTokenType = itr->type)) return nullptr;
if (iTokenType == 0xFF) {
if (!bufOutput.write(itr->data)) return nullptr;
if (itr->data == 0x2F) bEnd = true;
}
if (!bufOutput.write_variable_length_uint(itr->buffer_length))
return nullptr;
if(!bufOutput.write(itr->buffer, itr->buffer_length))
return nullptr;
if (!bufOutput.write(itr->buffer, itr->buffer_length)) return nullptr;
} else {
if (itr->type != iTokenType) {
if (!bufOutput.write(iTokenType = itr->type)) return nullptr;
}
else
{
if(itr->type != iTokenType)
{
if(!bufOutput.write(iTokenType = itr->type))
return nullptr;
}
if(!bufOutput.write(itr->data))
return nullptr;
if(itr->buffer)
{
if(!bufOutput.write(itr->buffer, 1))
return nullptr;
if (!bufOutput.write(itr->data)) return nullptr;
if (itr->buffer) {
if (!bufOutput.write(itr->buffer, 1)) return nullptr;
}
}
}

View File

@@ -25,14 +25,13 @@ SOFTWARE.
#include "config.h"
#ifdef CORSIX_TH_USE_SDL_MIXER
uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
size_t xmi_length, size_t* midi_length);
uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data, size_t xmi_length,
size_t* midi_length);
#else // CORSIX_TH_USE_SDL_MIXER
inline uint8_t* transcode_xmi_to_midi(const unsigned char* xmi_data,
size_t xmi_length, size_t* midi_length)
{
size_t xmi_length, size_t* midi_length) {
// When SDL_mixer isn't being used, there is no need to transocde XMI to
// MIDI, so the function always fails.
return nullptr;

View File

@@ -20,30 +20,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "config.h"
#include "../Src/main.h"
#include "../Src/bootstrap.h"
#include <stack>
#include "config.h"
#include <SDL.h>
#include <stack>
#include "../Src/bootstrap.h"
#ifdef CORSIX_TH_USE_SDL_MIXER
#include <SDL_mixer.h>
#endif
// Template magic for checking type equality
template <typename T1, typename T2>
struct types_equal{ enum{
struct types_equal {
enum {
result = -1,
}; };
};
};
template <typename T1>
struct types_equal<T1, T1>{ enum{
struct types_equal<T1, T1> {
enum {
result = 1,
}; };
};
};
static void cleanup(lua_State* L)
{
static void cleanup(lua_State* L) {
#ifdef CORSIX_TH_USE_SDL_MIXER
while(Mix_QuerySpec(nullptr, nullptr, nullptr))
{
while (Mix_QuerySpec(nullptr, nullptr, nullptr)) {
Mix_CloseAudio();
}
#endif
@@ -59,10 +61,8 @@ static void cleanup(lua_State* L)
sooner, hence this function does as little as possible and leaves the rest
for lua_main().
*/
int main(int argc, char** argv)
{
struct compile_time_lua_check
{
int main(int argc, char** argv) {
struct compile_time_lua_check {
// Lua 5.1, not 5.0, is required
int lua_5_point_1_required[LUA_VERSION_NUM >= 501 ? 1 : -1];
@@ -73,14 +73,13 @@ int main(int argc, char** argv)
bool bRun = true;
while(bRun)
{
while (bRun) {
lua_State* L = NULL;
L = luaL_newstate();
if(L == NULL)
{
fprintf(stderr, "Fatal error starting CorsixTH: "
if (L == NULL) {
fprintf(stderr,
"Fatal error starting CorsixTH: "
"Cannot open Lua state.\n");
return 0;
}
@@ -92,27 +91,22 @@ int main(int argc, char** argv)
// Move command line parameters onto the Lua stack
lua_checkstack(L, argc);
for(int i = 0; i < argc; ++i)
{
for (int i = 0; i < argc; ++i) {
lua_pushstring(L, argv[i]);
}
if(lua_pcall(L, argc, 0, 1) != 0)
{
if (lua_pcall(L, argc, 0, 1) != 0) {
const char* err = lua_tostring(L, -1);
if(err != NULL)
{
if (err != NULL) {
fprintf(stderr, "%s\n", err);
}
else
{
fprintf(stderr, "An error has occurred in CorsixTH:\n"
} else {
fprintf(stderr,
"An error has occurred in CorsixTH:\n"
"Uncaught non-string Lua error\n");
}
lua_pushcfunction(L, bootstrap_lua_error_report);
lua_insert(L, -2);
if(lua_pcall(L, 1, 0, 0) != 0)
{
if (lua_pcall(L, 1, 0, 0) != 0) {
fprintf(stderr, "%s\n", lua_tostring(L, -1));
}
}
@@ -122,8 +116,7 @@ int main(int argc, char** argv)
cleanup(L);
if(bRun)
{
if (bRun) {
printf("\n\nRestarting...\n\n\n");
}
}

View File

@@ -35,12 +35,13 @@ SOFTWARE.
*/
#include "rnc.h"
#include <vector>
#include <cstdint>
#include <cstddef>
#include <cstdint>
#include <vector>
static const std::uint32_t rnc_signature = 0x524E4301; /*!< "RNC\001" */
// clang-format off
static const std::uint16_t rnc_crc_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
@@ -75,20 +76,18 @@ static const std::uint16_t rnc_crc_table[256] = {
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
};
// clang-format on
struct bit_stream
{
struct bit_stream {
std::uint32_t bitbuf; ///< holds between 16 and 32 bits.
int bitcount; ///< how many bits does bitbuf hold?
const std::uint8_t* endpos; ///< pointer past the readable data
const std::uint8_t* p; ///< pointer in data that stream is reading.
};
struct huf_table
{
struct huf_table {
int num; ///< number of nodes in the tree.
struct
{
struct {
std::uint32_t code;
int codelen;
int value;
@@ -100,12 +99,10 @@ struct huf_table
@param data data for which to calculate the CRC
@param len length of the data in bytes
*/
static std::uint16_t rnc_crc(const std::uint8_t* data, std::size_t len)
{
static std::uint16_t rnc_crc(const std::uint8_t* data, std::size_t len) {
std::uint16_t val = 0;
while(len--)
{
while (len--) {
val = static_cast<std::uint16_t>(val ^ *data++);
val = static_cast<std::uint16_t>((val >> 8) ^ rnc_crc_table[val & 0xFF]);
}
@@ -113,13 +110,11 @@ static std::uint16_t rnc_crc(const std::uint8_t* data, std::size_t len)
return val;
}
//! Return the big-endian 32 bit word at p.
/*!
@param p Pointer to data containing the word
*/
static std::uint32_t blong (const std::uint8_t *p)
{
static std::uint32_t blong(const std::uint8_t* p) {
std::uint32_t n;
n = p[0];
n = (n << 8) + p[1];
@@ -132,8 +127,7 @@ static std::uint32_t blong (const std::uint8_t *p)
/*!
@param p Pointer to data containing the word
*/
static std::uint32_t bword (const std::uint8_t *p)
{
static std::uint32_t bword(const std::uint8_t* p) {
std::uint32_t n;
n = p[0];
n = (n << 8) + p[1];
@@ -144,8 +138,7 @@ static std::uint32_t bword (const std::uint8_t *p)
/*!
@param p Pointer to data containing the word
*/
static std::uint32_t lword (const std::uint8_t *p)
{
static std::uint32_t lword(const std::uint8_t* p) {
std::uint32_t n;
n = p[1];
n = (n << 8) + p[0];
@@ -157,15 +150,12 @@ static std::uint32_t lword (const std::uint8_t *p)
@param x
@param n
*/
static std::uint32_t mirror (std::uint32_t x, int n)
{
static std::uint32_t mirror(std::uint32_t x, int n) {
std::uint32_t top = 1 << (n - 1), bottom = 1;
while (top > bottom)
{
while (top > bottom) {
std::uint32_t mask = top | bottom;
std::uint32_t masked = x & mask;
if (masked != 0 && masked != mask)
{
if (masked != 0 && masked != mask) {
x ^= mask;
}
top >>= 1;
@@ -174,7 +164,6 @@ static std::uint32_t mirror (std::uint32_t x, int n)
return x;
}
//! Initialises a bit stream with the first two bytes of the packed
//! data.
/*!
@@ -184,8 +173,8 @@ static std::uint32_t mirror (std::uint32_t x, int n)
@param endpos Pointer to byte after the last memory block the bitstream is
to traverse
*/
static void bitread_init (bit_stream *bs, const std::uint8_t *p, const std::uint8_t* endpos)
{
static void bitread_init(bit_stream* bs, const std::uint8_t* p,
const std::uint8_t* endpos) {
bs->bitbuf = lword(p);
bs->bitcount = 16;
bs->p = p;
@@ -197,16 +186,14 @@ static void bitread_init (bit_stream *bs, const std::uint8_t *p, const std::uint
/*!
@param bs Bit stream to correct
*/
static void bitread_fix (bit_stream *bs)
{
static void bitread_fix(bit_stream* bs) {
// Remove the top 16 bits
bs->bitcount -= 16;
bs->bitbuf &= (1 << bs->bitcount) - 1;
// Replace with what is in the new current location
// in the bit stream
if(bs->p < bs->endpos - 1)
{
if (bs->p < bs->endpos - 1) {
bs->bitbuf |= (lword(bs->p) << bs->bitcount);
bs->bitcount += 16;
} else if (bs->p == bs->endpos - 1) {
@@ -221,8 +208,7 @@ static void bitread_fix (bit_stream *bs)
@param bs Bit stream from which to peek
@param mask A 32 bit bit mask specifying which bits to peek
*/
static std::uint32_t bit_peek (bit_stream *bs, const std::uint32_t mask)
{
static std::uint32_t bit_peek(bit_stream* bs, const std::uint32_t mask) {
return bs->bitbuf & mask;
}
@@ -232,21 +218,18 @@ static std::uint32_t bit_peek (bit_stream *bs, const std::uint32_t mask)
@param n Number of bits to advance the stream. Must be
between 0 and 16
*/
static void bit_advance (bit_stream *bs, int n)
{
static void bit_advance(bit_stream* bs, int n) {
bs->bitbuf >>= n;
bs->bitcount -= n;
if (bs->bitcount < 16)
{
if (bs->bitcount < 16) {
// At this point it is possible for bs->p to advance past
// the end of the data. In that case we simply do not read
// anything more into the buffer. If we are on the last
// byte the lword matches what is in that byte.
bs->p += 2;
if (bs->p < (bs->endpos - 1))
{
if (bs->p < (bs->endpos - 1)) {
bs->bitbuf |= (lword(bs->p) << bs->bitcount);
bs->bitcount += 16;
} else if (bs->p < bs->endpos) {
@@ -264,8 +247,7 @@ static void bit_advance (bit_stream *bs, int n)
@param n Number of bits to advance the stream. Must be
between 0 and 16
*/
static std::uint32_t bit_read (bit_stream *bs, std::uint32_t mask, int n)
{
static std::uint32_t bit_read(bit_stream* bs, std::uint32_t mask, int n) {
std::uint32_t result = bit_peek(bs, mask);
bit_advance(bs, n);
return result;
@@ -277,8 +259,7 @@ static std::uint32_t bit_read (bit_stream *bs, std::uint32_t mask, int n)
@param bs Bit stream pointing to the start of the Huffman table
description
*/
static void read_huftable(huf_table *h, bit_stream *bs)
{
static void read_huftable(huf_table* h, bit_stream* bs) {
int i, j, k, num;
int leaflen[32];
int leafmax;
@@ -286,29 +267,23 @@ static void read_huftable(huf_table *h, bit_stream *bs)
num = bit_read(bs, 0x1F, 5);
if(num == 0)
{
if (num == 0) {
return;
}
leafmax = 1;
for(i = 0; i < num; i++)
{
for (i = 0; i < num; i++) {
leaflen[i] = bit_read(bs, 0x0F, 4);
if (leafmax < leaflen[i])
{
if (leafmax < leaflen[i]) {
leafmax = leaflen[i];
}
}
codeb = 0L;
k = 0;
for(i = 1; i <= leafmax; i++)
{
for(j = 0; j < num; j++)
{
if(leaflen[j] == i)
{
for (i = 1; i <= leafmax; i++) {
for (j = 0; j < num; j++) {
if (leaflen[j] == i) {
h->table[k].code = mirror(codeb, i);
h->table[k].codelen = i;
h->table[k].value = j;
@@ -326,48 +301,43 @@ static void read_huftable(huf_table *h, bit_stream *bs)
@param h Huffman table to transcribe from
@param bs bit stream
@param p input data
@return The value from the table with the matching bits, or -1 if none found.
@return The value from the table with the matching bits, or -1 if none
found.
*/
static std::uint32_t huf_read(huf_table *h, bit_stream *bs, const std::uint8_t **p)
{
static std::uint32_t huf_read(huf_table* h, bit_stream* bs,
const std::uint8_t** p) {
int i;
std::uint32_t val;
std::uint32_t mask;
// Find the current bits in the table
for (i = 0; i < h->num; i++)
{
for (i = 0; i < h->num; i++) {
mask = (1 << h->table[i].codelen) - 1;
if(bit_peek(bs, mask) == h->table[i].code)
{
if (bit_peek(bs, mask) == h->table[i].code) {
break;
}
}
// No match found in table (error)
if(i == h->num)
{
if (i == h->num) {
return -1;
}
bit_advance(bs, h->table[i].codelen);
val = h->table[i].value;
if (val >= 2)
{
if (val >= 2) {
val = 1 << (val - 1);
val |= bit_read(bs, val - 1, h->table[i].value - 1);
}
return val;
}
std::size_t rnc_output_size(const std::uint8_t* input)
{
std::size_t rnc_output_size(const std::uint8_t* input) {
return static_cast<std::size_t>(blong(input + 4));
}
std::size_t rnc_input_size(const std::uint8_t* input)
{
std::size_t rnc_input_size(const std::uint8_t* input) {
return static_cast<std::size_t>(blong(input + 8) + rnc_header_size);
}
@@ -379,8 +349,7 @@ std::size_t rnc_input_size(const std::uint8_t* input)
4 byte segment of the input header starting at the 4th byte
in Big-endian.
*/
rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output)
{
rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output) {
const std::uint8_t* inputend;
std::uint8_t* outputend;
bit_stream input_bs;
@@ -388,8 +357,7 @@ rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output)
std::uint32_t ch_count;
std::uint32_t ret_len;
std::uint32_t out_crc;
if(blong(input) != rnc_signature)
{
if (blong(input) != rnc_signature) {
return rnc_status::file_is_not_rnc;
}
ret_len = blong(input + 4);
@@ -401,8 +369,7 @@ rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output)
// Check the packed-data CRC. Also save the unpacked-data CRC
// for later.
if (rnc_crc(input, inputend - input) != bword(input - 4))
{
if (rnc_crc(input, inputend - input) != bword(input - 4)) {
return rnc_status::packed_crc_error;
}
out_crc = bword(input - 6);
@@ -413,56 +380,47 @@ rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output)
bit_advance(&input_bs, 2);
// process chunks
while (output < outputend)
{
while (output < outputend) {
read_huftable(&raw, &input_bs); // raw byte length table
read_huftable(&dist, &input_bs); // distance prior to copy table
read_huftable(&len, &input_bs); // length bytes to copy table
ch_count = bit_read(&input_bs, 0xFFFF, 16);
while(true)
{
while (true) {
long length, posn;
// Copy bit pattern to output based on lookup
// of bytes from input.
length = huf_read(&raw, &input_bs, &input);
if(length == -1)
{
if (length == -1) {
return rnc_status::huf_decode_error;
}
if(length)
{
while(length--)
{
if (length) {
while (length--) {
*output++ = *(input_bs.p++);
}
bitread_fix(&input_bs);
}
if(--ch_count <= 0)
{
if (--ch_count <= 0) {
break;
}
// Read position to copy output to
posn = huf_read(&dist, &input_bs, &input);
if(posn == -1)
{
if (posn == -1) {
return rnc_status::huf_decode_error;
}
posn += 1;
// Read length of output to copy back
length = huf_read(&len, &input_bs, &input);
if(length == -1)
{
if (length == -1) {
return rnc_status::huf_decode_error;
}
length += 2;
// Copy length bytes from output back posn
while (length > 0)
{
while (length > 0) {
length--;
*output = output[-posn];
output++;
@@ -470,14 +428,12 @@ rnc_status rnc_unpack(const std::uint8_t* input, std::uint8_t* output)
}
}
if(outputend != output)
{
if (outputend != output) {
return rnc_status::file_size_mismatch;
}
// Check the unpacked-data CRC.
if (rnc_crc(outputend - ret_len, ret_len) != out_crc)
{
if (rnc_crc(outputend - ret_len, ret_len) != out_crc) {
return rnc_status::unpacked_crc_error;
}

View File

@@ -27,8 +27,7 @@ SOFTWARE.
#include <cstdint>
/*! Result status values from #rnc_inpack. */
enum class rnc_status
{
enum class rnc_status {
ok, ///< Everything is fine
file_is_not_rnc, ///< The file does not begin with an RNC signature
huf_decode_error, ///< Error decoding the file