mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-12-19 04:12:40 -05:00
Removed windows.h dependency.
Added support for music in MDS format.
This commit is contained in:
parent
e0638c598d
commit
2fe6d6d33a
20 changed files with 386 additions and 910 deletions
|
@ -15,7 +15,7 @@ int Sound::Init(int voices)
|
||||||
num_channels = channelCount;
|
num_channels = channelCount;
|
||||||
enabled_flag = -1;
|
enabled_flag = -1;
|
||||||
|
|
||||||
return Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) == -1;
|
return Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Enable(int channelFrom, int channelTo, int enableFlag)
|
void Sound::Enable(int channelFrom, int channelTo, int enableFlag)
|
||||||
|
|
|
@ -38,7 +38,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
auto xx = sizeof(datFileHeader);
|
auto xx = sizeof(datFileHeader);
|
||||||
|
|
||||||
lstrcpyA(winmain::DatFileName, "PINBALL.DAT");
|
strcpy_s(winmain::DatFileName, "PINBALL.DAT");
|
||||||
pb::init();
|
pb::init();
|
||||||
auto datFile = pb::record_table;
|
auto datFile = pb::record_table;
|
||||||
|
|
||||||
|
|
|
@ -229,14 +229,14 @@ TPinballComponent* TPinballTable::find_component(LPCSTR componentName)
|
||||||
for (int index = 0; index < objCount; ++index)
|
for (int index = 0; index < objCount; ++index)
|
||||||
{
|
{
|
||||||
TPinballComponent* obj = ComponentList->Get(index);
|
TPinballComponent* obj = ComponentList->Get(index);
|
||||||
const CHAR* groupName = obj->GroupName;
|
const char* groupName = obj->GroupName;
|
||||||
if (groupName && !lstrcmpA(groupName, componentName))
|
if (groupName && !strcmp(groupName, componentName))
|
||||||
{
|
{
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageBoxA(nullptr, "Table cant find:", componentName, 0x2000u);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Table cant find:", componentName, nullptr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ TPinballComponent* TPinballTable::find_component(int groupIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_itoa_s(groupIndex, Buffer, 10);
|
_itoa_s(groupIndex, Buffer, 10);
|
||||||
MessageBoxA(nullptr, "Table cant find (lh):", Buffer, 0x2000u);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Table cant find (lh):", Buffer, nullptr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,9 +117,8 @@ int fullscrn::get_max_supported_resolution()
|
||||||
if (!pb::FullTiltMode)
|
if (!pb::FullTiltMode)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto resolutionWH = get_screen_resolution();
|
int width = 0, height = 0;
|
||||||
auto width = LOWORD(resolutionWH);
|
get_screen_resolution(&width, &height);
|
||||||
auto height = HIWORD(resolutionWH);
|
|
||||||
auto result = 0;
|
auto result = 0;
|
||||||
|
|
||||||
for (auto index = 1; index < 3; ++index)
|
for (auto index = 1; index < 3; ++index)
|
||||||
|
@ -131,10 +130,16 @@ int fullscrn::get_max_supported_resolution()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fullscrn::get_screen_resolution()
|
int fullscrn::get_screen_resolution(int* width, int* height)
|
||||||
{
|
{
|
||||||
auto height = static_cast<uint16_t>(GetSystemMetrics(SM_CYSCREEN));
|
SDL_DisplayMode dm;
|
||||||
return static_cast<uint16_t>(GetSystemMetrics(SM_CXSCREEN)) | (height << 16);
|
if (SDL_GetDesktopDisplayMode(0, &dm) == 0)
|
||||||
|
{
|
||||||
|
*width = dm.w;
|
||||||
|
*height = dm.h;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fullscrn::window_size_changed()
|
void fullscrn::window_size_changed()
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
static int GetMaxResolution();
|
static int GetMaxResolution();
|
||||||
static void SetMaxResolution(int resolution);
|
static void SetMaxResolution(int resolution);
|
||||||
static int get_max_supported_resolution();
|
static int get_max_supported_resolution();
|
||||||
static int get_screen_resolution();
|
static int get_screen_resolution(int* width, int* height);
|
||||||
static void window_size_changed();
|
static void window_size_changed();
|
||||||
private :
|
private :
|
||||||
static int resolution;
|
static int resolution;
|
||||||
|
|
|
@ -33,17 +33,6 @@ union ColorRgba
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ColorRgba) == 4, "Wrong size of RGBA color");
|
static_assert(sizeof(ColorRgba) == 4, "Wrong size of RGBA color");
|
||||||
|
|
||||||
struct LOGPALETTEx256 : LOGPALETTE
|
|
||||||
{
|
|
||||||
PALETTEENTRY palPalEntry2[256 - 1];
|
|
||||||
|
|
||||||
LOGPALETTEx256() : palPalEntry2{}
|
|
||||||
{
|
|
||||||
palVersion = 0x300;
|
|
||||||
palNumEntries = 256;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class gdrv
|
class gdrv
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,15 +54,15 @@ int high_score::read(high_score_struct* table, int* ptrToSmth)
|
||||||
{
|
{
|
||||||
auto tablePtr = &table[position];
|
auto tablePtr = &table[position];
|
||||||
_itoa_s(position, Buffer, 10);
|
_itoa_s(position, Buffer, 10);
|
||||||
lstrcatA(Buffer, ".Name");
|
strcat_s(Buffer, ".Name");
|
||||||
options::get_string(optPath, Buffer, buf1, "", 32);
|
options::get_string(optPath, Buffer, buf1, "", 32);
|
||||||
buf1[32] = 0;
|
buf1[32] = 0;
|
||||||
lstrcpyA(tablePtr->Name, buf1);
|
strcpy_s(tablePtr->Name, buf1);
|
||||||
_itoa_s(position, Buffer, 10);
|
_itoa_s(position, Buffer, 10);
|
||||||
lstrcatA(Buffer, ".Score");
|
strcat_s(Buffer, ".Score");
|
||||||
options::get_string(optPath, Buffer, buf1, "", 300);
|
options::get_string(optPath, Buffer, buf1, "", 300);
|
||||||
tablePtr->Score = atol(buf1);
|
tablePtr->Score = atol(buf1);
|
||||||
for (int i = lstrlenA(tablePtr->Name); --i >= 0; scoreSum += tablePtr->Name[i])
|
for (int i = (int)strlen(tablePtr->Name); --i >= 0; scoreSum += tablePtr->Name[i])
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
scoreSum += tablePtr->Score;
|
scoreSum += tablePtr->Score;
|
||||||
|
@ -70,7 +70,7 @@ int high_score::read(high_score_struct* table, int* ptrToSmth)
|
||||||
|
|
||||||
scramble_number_string(scoreSum, buf1);
|
scramble_number_string(scoreSum, buf1);
|
||||||
options::get_string(optPath, "Verification", buf2, "", 300);
|
options::get_string(optPath, "Verification", buf2, "", 300);
|
||||||
if (lstrcmpA(buf1, buf2))
|
if (strcmp(buf1, buf2) != 0)
|
||||||
clear_table(table);
|
clear_table(table);
|
||||||
memory::free(buf1);
|
memory::free(buf1);
|
||||||
memory::free(buf2);
|
memory::free(buf2);
|
||||||
|
@ -83,20 +83,20 @@ int high_score::write(high_score_struct* table, int* ptrToSmth)
|
||||||
|
|
||||||
high_score_struct* tablePtr = table;
|
high_score_struct* tablePtr = table;
|
||||||
int scoreSum = 0;
|
int scoreSum = 0;
|
||||||
CHAR* buf = memory::allocate(300u);
|
char* buf = memory::allocate(300u);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return 1;
|
return 1;
|
||||||
const CHAR* optPath = pinball::get_rc_string(166, 0);
|
const char* optPath = pinball::get_rc_string(166, 0);
|
||||||
for (auto position = 0; position < 5; ++position)
|
for (auto position = 0; position < 5; ++position)
|
||||||
{
|
{
|
||||||
_itoa_s(position, Buffer, 10);
|
_itoa_s(position, Buffer, 10);
|
||||||
lstrcatA(Buffer, ".Name");
|
strcat_s(Buffer, ".Name");
|
||||||
options::set_string(optPath, Buffer, tablePtr->Name);
|
options::set_string(optPath, Buffer, tablePtr->Name);
|
||||||
_itoa_s(position, Buffer, 10);
|
_itoa_s(position, Buffer, 10);
|
||||||
lstrcatA(Buffer, ".Score");
|
strcat_s(Buffer, ".Score");
|
||||||
_ltoa_s(tablePtr->Score, buf, 300, 10);
|
_ltoa_s(tablePtr->Score, buf, 300, 10);
|
||||||
options::set_string(optPath, Buffer, buf);
|
options::set_string(optPath, Buffer, buf);
|
||||||
for (int i = lstrlenA(tablePtr->Name); --i >= 0; scoreSum += tablePtr->Name[i])
|
for (int i = (int)strlen(tablePtr->Name); --i >= 0; scoreSum += tablePtr->Name[i])
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
scoreSum += tablePtr->Score;
|
scoreSum += tablePtr->Score;
|
||||||
|
@ -150,9 +150,9 @@ int high_score::place_new_score_into(high_score_struct* table, int score, LPSTR
|
||||||
}
|
}
|
||||||
high_score_struct* posTable = &table[position];
|
high_score_struct* posTable = &table[position];
|
||||||
posTable->Score = score;
|
posTable->Score = score;
|
||||||
if (lstrlenA(scoreStr) >= 31)
|
if (strlen(scoreStr) >= 31)
|
||||||
scoreStr[31] = 0;
|
scoreStr[31] = 0;
|
||||||
lstrcpyA(posTable->Name, scoreStr);
|
strcpy_s(posTable->Name, scoreStr);
|
||||||
posTable->Name[31] = 0;
|
posTable->Name[31] = 0;
|
||||||
}
|
}
|
||||||
return position;
|
return position;
|
||||||
|
|
|
@ -13,7 +13,6 @@ errorMsg loader::loader_errors[] =
|
||||||
errorMsg{0, "Bad Handle"},
|
errorMsg{0, "Bad Handle"},
|
||||||
errorMsg{1, "No Type Field"},
|
errorMsg{1, "No Type Field"},
|
||||||
errorMsg{2, "No Attributes Field"},
|
errorMsg{2, "No Attributes Field"},
|
||||||
errorMsg{0x0B, "No float Attributes Field"},
|
|
||||||
errorMsg{3, "Wrong Type: MATERIAL Expected"},
|
errorMsg{3, "Wrong Type: MATERIAL Expected"},
|
||||||
errorMsg{4, "Wrong Type: KICKER Expected"},
|
errorMsg{4, "Wrong Type: KICKER Expected"},
|
||||||
errorMsg{5, "Wrong Type: AN_OBJECT Expected"},
|
errorMsg{5, "Wrong Type: AN_OBJECT Expected"},
|
||||||
|
@ -21,6 +20,7 @@ errorMsg loader::loader_errors[] =
|
||||||
errorMsg{7, "STATES (re)defined in a state"},
|
errorMsg{7, "STATES (re)defined in a state"},
|
||||||
errorMsg{9, "Unrecognized Attribute"},
|
errorMsg{9, "Unrecognized Attribute"},
|
||||||
errorMsg{0x0A, "Unrecognized float Attribute"},
|
errorMsg{0x0A, "Unrecognized float Attribute"},
|
||||||
|
errorMsg{0x0B, "No float Attributes Field"},
|
||||||
errorMsg{0x0D, "float Attribute not found"},
|
errorMsg{0x0D, "float Attribute not found"},
|
||||||
errorMsg{0x0C, "state_index out of range"},
|
errorMsg{0x0C, "state_index out of range"},
|
||||||
errorMsg{0x0F, "loader_material() reports failure"},
|
errorMsg{0x0F, "loader_material() reports failure"},
|
||||||
|
@ -63,7 +63,7 @@ int loader::error(int errorCode, int captionCode)
|
||||||
|
|
||||||
if (!errorText)
|
if (!errorText)
|
||||||
errorText = loader_errors[index].Message;
|
errorText = loader_errors[index].Message;
|
||||||
MessageBoxA(nullptr, errorText, errorCaption, 0x2000u);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, errorCaption, errorText, nullptr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,31 @@
|
||||||
|
|
||||||
Mix_Music* midi::currentMidi;
|
Mix_Music* midi::currentMidi;
|
||||||
|
|
||||||
MCIERROR midi::play_pb_theme(int flag)
|
#define FOURCC(a,b,c,d) ( (uint32_t) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) )
|
||||||
|
|
||||||
|
int ToVariableLen(uint32_t value, uint32_t& dst)
|
||||||
|
{
|
||||||
|
auto count = 1;
|
||||||
|
dst = value & 0x7F;
|
||||||
|
|
||||||
|
while ((value >>= 7))
|
||||||
|
{
|
||||||
|
dst <<= 8;
|
||||||
|
dst |= ((value & 0x7F) | 0x80);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int midi::play_pb_theme(int flag)
|
||||||
{
|
{
|
||||||
if (pb::FullTiltMode)
|
if (pb::FullTiltMode)
|
||||||
{
|
{
|
||||||
return play_ft(track1);
|
return play_ft(track1);
|
||||||
}
|
}
|
||||||
|
|
||||||
MCIERROR result = 0;
|
int result = 0;
|
||||||
music_stop();
|
music_stop();
|
||||||
if (currentMidi)
|
if (currentMidi)
|
||||||
result = Mix_PlayMusic(currentMidi, -1);
|
result = Mix_PlayMusic(currentMidi, -1);
|
||||||
|
@ -22,7 +39,7 @@ MCIERROR midi::play_pb_theme(int flag)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCIERROR midi::music_stop()
|
int midi::music_stop()
|
||||||
{
|
{
|
||||||
if (pb::FullTiltMode)
|
if (pb::FullTiltMode)
|
||||||
{
|
{
|
||||||
|
@ -43,21 +60,6 @@ int midi::music_init()
|
||||||
return currentMidi != nullptr;
|
return currentMidi != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCIERROR midi::restart_midi_seq(LPARAM param)
|
|
||||||
{
|
|
||||||
if (pb::FullTiltMode)
|
|
||||||
{
|
|
||||||
return play_ft(active_track);
|
|
||||||
}
|
|
||||||
|
|
||||||
MCIERROR result = 0;
|
|
||||||
music_stop();
|
|
||||||
if (currentMidi)
|
|
||||||
result = Mix_PlayMusic(currentMidi, -1);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void midi::music_shutdown()
|
void midi::music_shutdown()
|
||||||
{
|
{
|
||||||
if (pb::FullTiltMode)
|
if (pb::FullTiltMode)
|
||||||
|
@ -70,14 +72,14 @@ void midi::music_shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
objlist_class<midi_struct>* midi::TrackList;
|
objlist_class<Mix_Music>* midi::TrackList;
|
||||||
midi_struct *midi::track1, *midi::track2, *midi::track3, *midi::active_track, *midi::active_track2;
|
Mix_Music *midi::track1, *midi::track2, *midi::track3, *midi::active_track, *midi::active_track2;
|
||||||
int midi::some_flag1;
|
int midi::some_flag1;
|
||||||
|
|
||||||
int midi::music_init_ft()
|
int midi::music_init_ft()
|
||||||
{
|
{
|
||||||
active_track = nullptr;
|
active_track = nullptr;
|
||||||
TrackList = new objlist_class<midi_struct>(0, 1);
|
TrackList = new objlist_class<Mix_Music>(0, 1);
|
||||||
|
|
||||||
track1 = load_track("taba1");
|
track1 = load_track("taba1");
|
||||||
track2 = load_track("taba2");
|
track2 = load_track("taba2");
|
||||||
|
@ -92,260 +94,50 @@ int midi::music_init_ft()
|
||||||
void midi::music_shutdown_ft()
|
void midi::music_shutdown_ft()
|
||||||
{
|
{
|
||||||
if (active_track)
|
if (active_track)
|
||||||
stream_close(active_track);
|
Mix_HaltMusic();
|
||||||
while (TrackList->GetCount())
|
while (TrackList->GetCount())
|
||||||
{
|
{
|
||||||
midi_struct* midi = TrackList->Get(0);
|
auto midi = TrackList->Get(0);
|
||||||
unload_track(midi);
|
Mix_FreeMusic(midi);
|
||||||
TrackList->Delete(midi);
|
TrackList->Delete(midi);
|
||||||
}
|
}
|
||||||
active_track = nullptr;
|
active_track = nullptr;
|
||||||
delete TrackList;
|
delete TrackList;
|
||||||
}
|
}
|
||||||
|
|
||||||
midi_struct* midi::load_track(LPCSTR fileName)
|
Mix_Music* midi::load_track(LPCSTR fileName)
|
||||||
{
|
{
|
||||||
midi_struct* midi;
|
|
||||||
char filePath[256];
|
char filePath[256];
|
||||||
char fileName2[256];
|
char fileName2[256];
|
||||||
|
|
||||||
lstrcpyA(fileName2, "sound\\");
|
strcpy_s(fileName2, "sound\\");
|
||||||
lstrcatA(fileName2, fileName);
|
strcat_s(fileName2, fileName);
|
||||||
pinball::make_path_name(filePath, fileName2, 254u);
|
pinball::make_path_name(filePath, fileName2, 254u);
|
||||||
lstrcatA(filePath, ".MDS");
|
strcat_s(filePath, ".MDS");
|
||||||
if (load_file(&midi, filePath, 0, 1))
|
auto midi = MdsToMidi(filePath);
|
||||||
|
if (!midi)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (midi)
|
auto rw = SDL_RWFromMem(midi->data(), static_cast<int>(midi->size()));
|
||||||
TrackList->Add(midi);
|
auto audio = Mix_LoadMUS_RW(rw, 0);
|
||||||
return midi;
|
SDL_FreeRW(rw);
|
||||||
|
delete midi;
|
||||||
|
if (!audio)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Dump converted MIDI file
|
||||||
|
/*FILE* fileHandle;
|
||||||
|
strcpy_s(fileName2, fileName);
|
||||||
|
strcat_s(fileName2, ".midi");
|
||||||
|
fopen_s(&fileHandle, fileName2, "wb");
|
||||||
|
fwrite(midi->data(), 1, midi->size(), fileHandle);
|
||||||
|
fclose(fileHandle);*/
|
||||||
|
|
||||||
|
TrackList->Add(audio);
|
||||||
|
return audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, int flags)
|
int midi::play_ft(Mix_Music* midi)
|
||||||
{
|
|
||||||
int returnCode;
|
|
||||||
unsigned int fileSize;
|
|
||||||
HANDLE mapHandle = nullptr;
|
|
||||||
midi_struct* midi = nullptr;
|
|
||||||
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
||||||
int fileFlag = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if ((flags & 3) == 0 || (flags & 3) == 3)
|
|
||||||
{
|
|
||||||
returnCode = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
midi = static_cast<midi_struct*>(LocalAlloc(0x40u, sizeof(midi_struct)));
|
|
||||||
if (!midi)
|
|
||||||
{
|
|
||||||
returnCode = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
midi->Magic = mmioFOURCC('M', 'D', 'S', 'I');
|
|
||||||
midi->StreamHandle = nullptr;
|
|
||||||
midi->PreparedBlocksCount = 0;
|
|
||||||
|
|
||||||
if ((flags & 2) != 0)
|
|
||||||
{
|
|
||||||
fileSize = fileSizeP;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileFlag = 1;
|
|
||||||
fileHandle = CreateFileA(static_cast<LPCSTR>(filePtrOrPath), GENERIC_READ, 1u, nullptr, OPEN_EXISTING,
|
|
||||||
0x80u, nullptr);
|
|
||||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
returnCode = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSize = GetFileSize(fileHandle, nullptr);
|
|
||||||
mapHandle = CreateFileMappingA(fileHandle, nullptr, 2u, 0, 0, nullptr);
|
|
||||||
if (!mapHandle)
|
|
||||||
{
|
|
||||||
returnCode = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
filePtrOrPath = MapViewOfFile(mapHandle, 4u, 0, 0, 0);
|
|
||||||
if (!filePtrOrPath)
|
|
||||||
{
|
|
||||||
returnCode = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
returnCode = read_file(midi, static_cast<riff_header*>(filePtrOrPath), fileSize);
|
|
||||||
}
|
|
||||||
while (false);
|
|
||||||
|
|
||||||
|
|
||||||
if (returnCode)
|
|
||||||
{
|
|
||||||
if (midi)
|
|
||||||
LocalFree(midi);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*midi_res = midi;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileFlag)
|
|
||||||
{
|
|
||||||
if (filePtrOrPath)
|
|
||||||
UnmapViewOfFile(filePtrOrPath);
|
|
||||||
if (mapHandle)
|
|
||||||
CloseHandle(mapHandle);
|
|
||||||
if (fileHandle != INVALID_HANDLE_VALUE)
|
|
||||||
CloseHandle(fileHandle);
|
|
||||||
}
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize)
|
|
||||||
{
|
|
||||||
auto returnCode = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
midi->DataPtr1 = nullptr;
|
|
||||||
if (fileSize < 12)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (filePtr->Riff != mmioFOURCC('R', 'I', 'F', 'F'))
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (filePtr->Mids != mmioFOURCC('M', 'I', 'D', 'S'))
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (filePtr->FileSize > fileSize - 8)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fileSize - 12 < 8)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (filePtr->Fmt != mmioFOURCC('f', 'm', 't', ' '))
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (filePtr->FmtSize > fileSize - 12)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (filePtr->FmtSize < 12)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
midi->DwTimeFormat = filePtr->dwTimeFormat;
|
|
||||||
midi->CbMaxBuffer = filePtr->cbMaxBuffer;
|
|
||||||
midi->DwFlagsFormat = filePtr->dwFlags;
|
|
||||||
auto blocksSize = fileSize - 20 - filePtr->FmtSize;
|
|
||||||
if (blocksSize < 8)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dataChunk = reinterpret_cast<riff_data*>(reinterpret_cast<char*>(&filePtr->dwTimeFormat) + filePtr->FmtSize
|
|
||||||
);
|
|
||||||
if (dataChunk->Data != mmioFOURCC('d','a','t','a'))
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dataChunk->DataSize > blocksSize || dataChunk->DataSize < 4)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
midi->BlockCount = dataChunk->BlocksPerChunk;
|
|
||||||
midi->DataPtr1 = reinterpret_cast<midihdr_tag*>(memory::allocate(
|
|
||||||
dataChunk->BlocksPerChunk * (midi->CbMaxBuffer + sizeof(midihdr_tag))));
|
|
||||||
if (!midi->DataPtr1)
|
|
||||||
{
|
|
||||||
returnCode = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!midi->BlockCount)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto blocksSizeIndex = blocksSize - 12;
|
|
||||||
auto srcPtr = dataChunk->Blocks;
|
|
||||||
auto* dstPtr = midi->DataPtr1;
|
|
||||||
for (auto blockIndex = midi->BlockCount; blockIndex; blockIndex--)
|
|
||||||
{
|
|
||||||
dstPtr->lpData = reinterpret_cast<LPSTR>(&dstPtr[1]);
|
|
||||||
dstPtr->dwBufferLength = midi->CbMaxBuffer;
|
|
||||||
dstPtr->dwFlags = 0;
|
|
||||||
dstPtr->dwUser = reinterpret_cast<DWORD_PTR>(midi);
|
|
||||||
dstPtr->lpNext = nullptr;
|
|
||||||
if (blocksSizeIndex < 8)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto blockSize = srcPtr->CbBuffer;
|
|
||||||
if (blockSize > midi->CbMaxBuffer || blockSize > blocksSizeIndex - 8)
|
|
||||||
{
|
|
||||||
returnCode = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((midi->DwFlagsFormat & 1) != 0)
|
|
||||||
{
|
|
||||||
/*Not used in FT, some kind of compression*/
|
|
||||||
assertm(false, "Unimplemented code reached");
|
|
||||||
/*int a1[16];
|
|
||||||
a1[0] = (int)blockDataPtr;
|
|
||||||
a1[2] = blockSize;
|
|
||||||
a1[1] = blockSize;
|
|
||||||
if (!sub_4031A0(a1, dataPtr))
|
|
||||||
{
|
|
||||||
returnCode = 3; break;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dstPtr->dwBytesRecorded = blockSize;
|
|
||||||
memcpy(dstPtr->lpData, srcPtr->AData, blockSize);
|
|
||||||
}
|
|
||||||
blocksSizeIndex -= blockSize + 8;
|
|
||||||
srcPtr = reinterpret_cast<riff_block*>(&srcPtr->AData[blockSize]);
|
|
||||||
dstPtr = reinterpret_cast<midihdr_tag*>(reinterpret_cast<char*>(&dstPtr[1]) + midi->CbMaxBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (false);
|
|
||||||
|
|
||||||
if (returnCode && midi->DataPtr1)
|
|
||||||
{
|
|
||||||
memory::free(midi->DataPtr1);
|
|
||||||
}
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int midi::play_ft(midi_struct* midi)
|
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -357,7 +149,7 @@ int midi::play_ft(midi_struct* midi)
|
||||||
active_track2 = midi;
|
active_track2 = midi;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (stream_open(midi, 1))
|
if (Mix_PlayMusic(midi, -1))
|
||||||
{
|
{
|
||||||
active_track = nullptr;
|
active_track = nullptr;
|
||||||
result = 0;
|
result = 0;
|
||||||
|
@ -374,114 +166,170 @@ int midi::stop_ft()
|
||||||
{
|
{
|
||||||
int returnCode = 0;
|
int returnCode = 0;
|
||||||
if (active_track)
|
if (active_track)
|
||||||
returnCode = stream_close(active_track);
|
returnCode = Mix_HaltMusic();
|
||||||
active_track = nullptr;
|
active_track = nullptr;
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int midi::unload_track(midi_struct* midi)
|
/// <summary>
|
||||||
|
/// SDL_mixed does not support MIDS. To support FT music, a conversion to MIDI is required.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">Path to .MDS file</param>
|
||||||
|
/// <returns>Vector that contains MIDI file</returns>
|
||||||
|
std::vector<uint8_t>* midi::MdsToMidi(char* file)
|
||||||
{
|
{
|
||||||
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
FILE* fileHandle;
|
||||||
return 6;
|
if (fopen_s(&fileHandle, file, "rb"))
|
||||||
if (midi->StreamHandle)
|
return nullptr;
|
||||||
stream_close(midi);
|
|
||||||
if (midi->DataPtr1)
|
|
||||||
{
|
|
||||||
memory::free(midi->DataPtr1);
|
|
||||||
}
|
|
||||||
midi->Magic = mmioFOURCC('d','a','t','a');
|
|
||||||
LocalFree(midi);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int midi::stream_open(midi_struct* midi, char flags)
|
fseek(fileHandle, 0, SEEK_END);
|
||||||
{
|
auto fileSize = static_cast<uint32_t>(ftell(fileHandle));
|
||||||
auto returnCode = 0;
|
auto filePtr = reinterpret_cast<riff_header*>(memory::allocate(fileSize));
|
||||||
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
fseek(fileHandle, 0, SEEK_SET);
|
||||||
return 6;
|
fread(filePtr, 1, fileSize, fileHandle);
|
||||||
|
fclose(fileHandle);
|
||||||
|
|
||||||
/*UINT puDeviceID = -1;
|
int returnCode = 0;
|
||||||
auto steamOpenedFg = !midi->StreamHandle;
|
std::vector<uint8_t>* midiOut = nullptr;
|
||||||
MIDIPROPTIMEDIV propdata{8, midi->DwTimeFormat};
|
do
|
||||||
if (steamOpenedFg &&
|
|
||||||
!midiStreamOpen(&midi->StreamHandle, &puDeviceID, 1u, reinterpret_cast<DWORD_PTR>(midi_callback), 0,
|
|
||||||
CALLBACK_FUNCTION) &&
|
|
||||||
!midiStreamProperty(midi->StreamHandle, reinterpret_cast<LPBYTE>(&propdata),MIDIPROP_TIMEDIV | MIDIPROP_SET))
|
|
||||||
{
|
{
|
||||||
midihdr_tag* blockPtr = midi->DataPtr1;
|
if (fileSize < 12)
|
||||||
for (auto blockIndex = midi->BlockCount; blockIndex; blockIndex--)
|
|
||||||
{
|
{
|
||||||
if (midiOutPrepareHeader(reinterpret_cast<HMIDIOUT>(midi->StreamHandle), blockPtr, sizeof(MIDIHDR)) ||
|
returnCode = 3;
|
||||||
midiStreamOut(midi->StreamHandle, blockPtr, sizeof(MIDIHDR)))
|
break;
|
||||||
|
}
|
||||||
|
if (filePtr->Riff != FOURCC('R', 'I', 'F', 'F') ||
|
||||||
|
filePtr->Mids != FOURCC('M', 'I', 'D', 'S') ||
|
||||||
|
filePtr->Fmt != FOURCC('f', 'm', 't', ' '))
|
||||||
|
{
|
||||||
|
returnCode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (filePtr->FileSize > fileSize - 8)
|
||||||
|
{
|
||||||
|
returnCode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fileSize - 12 < 8)
|
||||||
|
{
|
||||||
|
returnCode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (filePtr->FmtSize < 12 || filePtr->FmtSize > fileSize - 12)
|
||||||
|
{
|
||||||
|
returnCode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto streamIdUsed = filePtr->dwFlags == 0;
|
||||||
|
auto dataChunk = reinterpret_cast<riff_data*>(reinterpret_cast<char*>(&filePtr->dwTimeFormat) + filePtr->
|
||||||
|
FmtSize);
|
||||||
|
if (dataChunk->Data != FOURCC('d', 'a', 't', 'a'))
|
||||||
|
{
|
||||||
|
returnCode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dataChunk->DataSize < 4)
|
||||||
|
{
|
||||||
|
returnCode = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto srcPtr = dataChunk->Blocks;
|
||||||
|
std::vector<midi_event_x2> midiEvents{};
|
||||||
|
for (auto blockIndex = dataChunk->BlocksPerChunk; blockIndex; blockIndex--)
|
||||||
|
{
|
||||||
|
auto eventSizeInt = streamIdUsed ? 3 : 2;
|
||||||
|
auto eventCount = srcPtr->CbBuffer / (4 * eventSizeInt);
|
||||||
|
|
||||||
|
auto currentTicks = srcPtr->TkStart;
|
||||||
|
auto srcPtr2 = reinterpret_cast<uint32_t*>(srcPtr->AData);
|
||||||
|
for (auto i = 0u; i < eventCount; i++)
|
||||||
{
|
{
|
||||||
returnCode = 5;
|
currentTicks += srcPtr2[0];
|
||||||
break;
|
auto event = streamIdUsed ? srcPtr2[2] : srcPtr2[1];
|
||||||
|
midiEvents.push_back({currentTicks, event});
|
||||||
|
srcPtr2 += eventSizeInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
++midi->PreparedBlocksCount;
|
srcPtr = reinterpret_cast<riff_block*>(&srcPtr->AData[srcPtr->CbBuffer]);
|
||||||
blockPtr = reinterpret_cast<midihdr_tag*>(reinterpret_cast<char*>(&blockPtr[1]) + blockPtr->dwBufferLength);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!returnCode)
|
// MIDS events can be out of order in the file
|
||||||
{
|
std::sort(midiEvents.begin(), midiEvents.end(), [](const auto& lhs, const auto& rhs)
|
||||||
if (!steamOpenedFg && (midi->SomeFlag2 & 4) == 0)
|
|
||||||
return 7;
|
|
||||||
|
|
||||||
midi->SomeFlag2 &= ~2;
|
|
||||||
if ((flags & 1) != 0)
|
|
||||||
midi->SomeFlag2 |= 2;
|
|
||||||
midi->SomeFlag2 &= ~4;
|
|
||||||
if (midiStreamRestart(midi->StreamHandle))
|
|
||||||
returnCode = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnCode && steamOpenedFg)
|
|
||||||
{
|
|
||||||
if (midi->StreamHandle)
|
|
||||||
stream_close(midi);
|
|
||||||
}*/
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int midi::stream_close(midi_struct* midi)
|
|
||||||
{
|
|
||||||
int returnCode = 0;
|
|
||||||
|
|
||||||
/*if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
|
|
||||||
return 6;
|
|
||||||
if (!midi->StreamHandle)
|
|
||||||
return 7;
|
|
||||||
midi->SomeFlag2 |= 1u;
|
|
||||||
if (midiOutReset(reinterpret_cast<HMIDIOUT>(midi->StreamHandle)))
|
|
||||||
{
|
|
||||||
returnCode = 5;
|
|
||||||
midi->SomeFlag2 &= ~1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
midihdr_tag* blockPtr = midi->DataPtr1;
|
|
||||||
for (int i = midi->BlockCount; i; --i)
|
|
||||||
{
|
{
|
||||||
midiOutUnprepareHeader(reinterpret_cast<HMIDIOUT>(midi->StreamHandle), blockPtr, sizeof(MIDIHDR));
|
return lhs.iTicks < rhs.iTicks;
|
||||||
blockPtr = reinterpret_cast<midihdr_tag*>(reinterpret_cast<char*>(&blockPtr[1]) + blockPtr->dwBufferLength);
|
});
|
||||||
}
|
|
||||||
midiStreamClose(midi->StreamHandle);
|
|
||||||
returnCode = 0;
|
|
||||||
midi->StreamHandle = nullptr;
|
|
||||||
midi->SomeFlag2 = 0;
|
|
||||||
}*/
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void midi::midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
|
// MThd chunk
|
||||||
{
|
std::vector<uint8_t>& midiBytes = *new std::vector<uint8_t>();
|
||||||
if (wMsg == 969)
|
midiOut = &midiBytes;
|
||||||
{
|
midi_header header(SwapByteOrderShort(static_cast<uint16_t>(filePtr->dwTimeFormat)));
|
||||||
auto mhdr = reinterpret_cast<LPMIDIHDR>(dwParam1);
|
auto headerData = reinterpret_cast<const uint8_t*>(&header);
|
||||||
auto midi = reinterpret_cast<midi_struct*>(mhdr->dwUser);
|
midiBytes.insert(midiBytes.end(), headerData, headerData + sizeof header);
|
||||||
/*if ((midi->SomeFlag2 & 2) == 0 || (midi->SomeFlag2 & 1) != 0 || midiStreamOut(
|
|
||||||
midi->StreamHandle, mhdr, sizeof(MIDIHDR)))
|
// MTrk chunk
|
||||||
--midi->PreparedBlocksCount;*/
|
midi_track track(7);
|
||||||
|
auto trackData = reinterpret_cast<const uint8_t*>(&track);
|
||||||
|
midiBytes.insert(midiBytes.end(), trackData, trackData + sizeof track);
|
||||||
|
auto lengthPos = midiBytes.size() - 4;
|
||||||
|
|
||||||
|
auto prevTime = 0u;
|
||||||
|
for (const auto& event : midiEvents)
|
||||||
|
{
|
||||||
|
assertm(event.iTicks >= prevTime, "MIDS events: negative delta-time");
|
||||||
|
uint32_t delta = event.iTicks - prevTime;
|
||||||
|
prevTime = event.iTicks;
|
||||||
|
|
||||||
|
// Delta time is in variable quantity, Big Endian
|
||||||
|
uint32_t deltaVarLen;
|
||||||
|
auto count = ToVariableLen(delta, deltaVarLen);
|
||||||
|
deltaVarLen = SwapByteOrderInt(deltaVarLen);
|
||||||
|
auto deltaData = reinterpret_cast<const uint8_t*>(&deltaVarLen) + 4 - count;
|
||||||
|
midiBytes.insert(midiBytes.end(), deltaData, deltaData + count);
|
||||||
|
|
||||||
|
switch (event.iEvent >> 24)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
// Type 0 - MIDI short message. 3 bytes: xx p1 p2 00, where xx - message, p* - parameters
|
||||||
|
// Some of the messages have only one parameter
|
||||||
|
auto msgMask = (event.iEvent) & 0xF0;
|
||||||
|
auto shortMsg = (msgMask == 0xC0 || msgMask == 0xD0);
|
||||||
|
auto eventData = reinterpret_cast<const uint8_t*>(&event.iEvent);
|
||||||
|
midiBytes.insert(midiBytes.end(), eventData, eventData + (shortMsg ? 2 : 3));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// Type 1 - tempo change, 3 bytes: xx xx xx 01
|
||||||
|
// Meta message, set tempo, 3 bytes payload
|
||||||
|
const uint8_t metaSetTempo[] = {0xFF, 0x51, 0x03};
|
||||||
|
midiBytes.insert(midiBytes.end(), metaSetTempo, metaSetTempo + 3);
|
||||||
|
|
||||||
|
auto eventBE = SwapByteOrderInt(event.iEvent);
|
||||||
|
auto eventData = reinterpret_cast<const uint8_t*>(&eventBE) + 1;
|
||||||
|
midiBytes.insert(midiBytes.end(), eventData, eventData + 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assertm(0, "MIDS events: uknown event");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meta message, end of track, 0 bytes payload
|
||||||
|
const uint8_t metaEndTrack[] = {0x00, 0xFF, 0x2f, 0x00};
|
||||||
|
midiBytes.insert(midiBytes.end(), metaEndTrack, metaEndTrack + 4);
|
||||||
|
|
||||||
|
// Set final MTrk size
|
||||||
|
*(uint32_t*)&midiBytes[lengthPos] = SwapByteOrderInt((uint32_t)midiBytes.size() - sizeof header - sizeof track);
|
||||||
}
|
}
|
||||||
|
while (false);
|
||||||
|
|
||||||
|
if (filePtr)
|
||||||
|
memory::free(filePtr);
|
||||||
|
if (returnCode && midiOut)
|
||||||
|
delete midiOut;
|
||||||
|
return midiOut;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "objlist_class.h"
|
#include "objlist_class.h"
|
||||||
|
|
||||||
struct midi_struct
|
constexpr uint32_t SwapByteOrderInt(uint32_t val)
|
||||||
{
|
{
|
||||||
DWORD Magic;
|
return (val >> 24) |
|
||||||
DWORD DwTimeFormat;
|
((val << 8) & 0x00FF0000) |
|
||||||
DWORD CbMaxBuffer;
|
((val >> 8) & 0x0000FF00) |
|
||||||
DWORD DwFlagsFormat;
|
(val << 24);
|
||||||
midihdr_tag* DataPtr1;
|
}
|
||||||
HMIDISTRM StreamHandle;
|
|
||||||
int SomeFlag2;
|
constexpr uint16_t SwapByteOrderShort(uint16_t val)
|
||||||
int BlockCount;
|
{
|
||||||
int PreparedBlocksCount;
|
return static_cast<uint16_t>((val >> 8) | (val << 8));
|
||||||
};
|
}
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
@ -44,35 +44,71 @@ struct riff_header
|
||||||
riff_data Data;
|
riff_data Data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct midi_event_x2
|
||||||
|
{
|
||||||
|
DWORD iTicks;
|
||||||
|
DWORD iEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct midi_event_x3
|
||||||
|
{
|
||||||
|
DWORD iTicks;
|
||||||
|
DWORD iStreamID;
|
||||||
|
DWORD iEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct midi_header
|
||||||
|
{
|
||||||
|
explicit midi_header(uint16_t tickdiv)
|
||||||
|
: tickdiv(tickdiv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char MThd[4]{ 'M','T','h','d' };
|
||||||
|
const uint32_t chunklen = SwapByteOrderInt(6);
|
||||||
|
const int16_t format = SwapByteOrderShort(0);
|
||||||
|
const uint16_t ntracks = SwapByteOrderShort(1);
|
||||||
|
uint16_t tickdiv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct midi_track
|
||||||
|
{
|
||||||
|
explicit midi_track(uint32_t chunklen)
|
||||||
|
: chunklen(chunklen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char MTrk[4]{ 'M','T','r','k' };
|
||||||
|
uint32_t chunklen;
|
||||||
|
};
|
||||||
|
|
||||||
static_assert(sizeof(riff_block) == 0xC, "Wrong size of riff_block");
|
static_assert(sizeof(riff_block) == 0xC, "Wrong size of riff_block");
|
||||||
static_assert(sizeof(riff_data) == 0x18, "Wrong size of riff_data");
|
static_assert(sizeof(riff_data) == 0x18, "Wrong size of riff_data");
|
||||||
static_assert(sizeof(riff_header) == 0x38, "Wrong size of riff_header");
|
static_assert(sizeof(riff_header) == 0x38, "Wrong size of riff_header");
|
||||||
|
static_assert(sizeof(midi_event_x3) == 12, "Wrong size of midi_event3");
|
||||||
|
static_assert(sizeof(midi_event_x2) == 8, "Wrong size of midi_event2");
|
||||||
|
static_assert(sizeof(midi_header) == 14, "Wrong size of midi_header");
|
||||||
|
static_assert(sizeof(midi_track) == 8, "Wrong size of midi_track");
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
class midi
|
class midi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static MCIERROR play_pb_theme(int flag);
|
static int play_pb_theme(int flag);
|
||||||
static MCIERROR music_stop();
|
static int music_stop();
|
||||||
static int music_init();
|
static int music_init();
|
||||||
static MCIERROR restart_midi_seq(LPARAM param);
|
|
||||||
static void music_shutdown();
|
static void music_shutdown();
|
||||||
private:
|
private:
|
||||||
static Mix_Music* currentMidi;
|
static Mix_Music* currentMidi;
|
||||||
|
|
||||||
static objlist_class<midi_struct>* TrackList;
|
static objlist_class<Mix_Music>* TrackList;
|
||||||
static midi_struct *track1, *track2, *track3, *active_track, *active_track2;
|
static Mix_Music *track1, *track2, *track3, *active_track, *active_track2;
|
||||||
static int some_flag1;
|
static int some_flag1;
|
||||||
static int music_init_ft();
|
static int music_init_ft();
|
||||||
static void music_shutdown_ft();
|
static void music_shutdown_ft();
|
||||||
static midi_struct* load_track(LPCSTR fileName);
|
static Mix_Music* load_track(LPCSTR fileName);
|
||||||
static int load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, int flags);
|
static int play_ft(Mix_Music* midi);
|
||||||
static int read_file(midi_struct* midi, riff_header* filePtr, unsigned int fileSize);
|
|
||||||
static int play_ft(midi_struct* midi);
|
|
||||||
static int stop_ft();
|
static int stop_ft();
|
||||||
static int unload_track(midi_struct* midi);
|
static std::vector<uint8_t>* MdsToMidi(char* file);
|
||||||
static int stream_open(midi_struct* midi, char flags);
|
|
||||||
static int stream_close(midi_struct* midi);
|
|
||||||
static void CALLBACK midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1,
|
|
||||||
DWORD_PTR dwParam2);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
LPCSTR options::OptionsRegPath;
|
LPCSTR options::OptionsRegPath;
|
||||||
LPSTR options::OptionsRegPathCur;
|
LPSTR options::OptionsRegPathCur;
|
||||||
HMENU options::MenuHandle;
|
|
||||||
optionsStruct options::Options{};
|
optionsStruct options::Options{};
|
||||||
|
|
||||||
winhelp_entry options::keymap_help[18]
|
winhelp_entry options::keymap_help[18]
|
||||||
|
@ -68,14 +67,12 @@ short options::vk_list[28]
|
||||||
-1
|
-1
|
||||||
};
|
};
|
||||||
|
|
||||||
void options::init(HMENU menuHandle)
|
void options::init()
|
||||||
{
|
{
|
||||||
MenuHandle = menuHandle;
|
|
||||||
Options.Sounds = 1;
|
Options.Sounds = 1;
|
||||||
Options.Music = 0;
|
Options.Music = 0;
|
||||||
Options.FullScreen = 0;
|
Options.FullScreen = 0;
|
||||||
Options.Average = 5;
|
Options.Average = 5;
|
||||||
Options.PriorityAdj = 2;
|
|
||||||
Options.LeftFlipperKeyDft = SDLK_z;
|
Options.LeftFlipperKeyDft = SDLK_z;
|
||||||
Options.RightFlipperKeyDft = SDLK_SLASH;
|
Options.RightFlipperKeyDft = SDLK_SLASH;
|
||||||
Options.PlungerKeyDft = SDLK_SPACE;
|
Options.PlungerKeyDft = SDLK_SPACE;
|
||||||
|
@ -109,29 +106,7 @@ void options::init(HMENU menuHandle)
|
||||||
Options.RightTableBumpKey = get_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
|
Options.RightTableBumpKey = get_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
|
||||||
Options.BottomTableBumpKey = get_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
|
Options.BottomTableBumpKey = get_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
|
||||||
Options.UniformScaling = get_int(nullptr, "Uniform scaling", true);*/
|
Options.UniformScaling = get_int(nullptr, "Uniform scaling", true);*/
|
||||||
menu_check(Menu1_Sounds, Options.Sounds);
|
|
||||||
Sound::Enable(0, 7, Options.Sounds);
|
Sound::Enable(0, 7, Options.Sounds);
|
||||||
menu_check(Menu1_Music, Options.Music);
|
|
||||||
menu_check(Menu1_Full_Screen, Options.FullScreen);
|
|
||||||
menu_check(Menu1_1Player, Options.Players == 1);
|
|
||||||
menu_check(Menu1_2Players, Options.Players == 2);
|
|
||||||
menu_check(Menu1_3Players, Options.Players == 3);
|
|
||||||
menu_check(Menu1_4Players, Options.Players == 4);
|
|
||||||
menu_check(Menu1_WindowUniformScale, Options.UniformScaling);
|
|
||||||
auto tmpBuf = memory::allocate(0x1F4u);
|
|
||||||
if (tmpBuf)
|
|
||||||
{
|
|
||||||
get_string(nullptr, "Shell Exe", tmpBuf, "", 500);
|
|
||||||
if (!*tmpBuf)
|
|
||||||
{
|
|
||||||
if (MenuHandle)
|
|
||||||
{
|
|
||||||
DeleteMenu(MenuHandle, Menu1_Select_Table, 0);
|
|
||||||
DrawMenuBar(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memory::free(tmpBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_resolution_menu();
|
update_resolution_menu();
|
||||||
}
|
}
|
||||||
|
@ -154,10 +129,10 @@ void options::uninit()
|
||||||
|
|
||||||
void options::path_init(LPCSTR regPath)
|
void options::path_init(LPCSTR regPath)
|
||||||
{
|
{
|
||||||
char* buf = memory::allocate(lstrlenA(regPath) + 1);
|
char* buf = memory::allocate(strlen(regPath) + 1);
|
||||||
OptionsRegPath = buf;
|
OptionsRegPath = buf;
|
||||||
if (buf)
|
if (buf)
|
||||||
lstrcpyA(buf, regPath);
|
strcpy_s(buf, strlen(regPath) + 1, regPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::path_uninit()
|
void options::path_uninit()
|
||||||
|
@ -172,16 +147,16 @@ LPCSTR options::path(LPCSTR regPath)
|
||||||
char* buf = OptionsRegPathCur;
|
char* buf = OptionsRegPathCur;
|
||||||
if (!OptionsRegPathCur)
|
if (!OptionsRegPathCur)
|
||||||
{
|
{
|
||||||
buf = memory::allocate(0x7D0u);
|
buf = memory::allocate(2000);
|
||||||
OptionsRegPathCur = buf;
|
OptionsRegPathCur = buf;
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return OptionsRegPath;
|
return OptionsRegPath;
|
||||||
}
|
}
|
||||||
lstrcpyA(buf, OptionsRegPath);
|
strcpy_s(buf, 2000, OptionsRegPath);
|
||||||
if (!regPath)
|
if (!regPath)
|
||||||
return OptionsRegPathCur;
|
return OptionsRegPathCur;
|
||||||
lstrcatA(OptionsRegPathCur, "\\");
|
strcat_s(OptionsRegPathCur, 2000, "\\");
|
||||||
lstrcatA(OptionsRegPathCur, regPath);
|
strcat_s(OptionsRegPathCur, 2000, regPath);
|
||||||
return OptionsRegPathCur;
|
return OptionsRegPathCur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,92 +170,45 @@ void options::path_free()
|
||||||
|
|
||||||
int options::get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue)
|
int options::get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue)
|
||||||
{
|
{
|
||||||
DWORD dwDisposition;
|
|
||||||
HKEY hKey;
|
|
||||||
|
|
||||||
auto result = defaultValue;
|
auto result = defaultValue;
|
||||||
if (!OptionsRegPath)
|
if (!OptionsRegPath)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
auto regPath = path(optPath);
|
auto regPath = path(optPath);
|
||||||
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
|
|
||||||
{
|
|
||||||
DWORD bufferSize = 4;
|
|
||||||
RegQueryValueExA(hKey, lpValueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(&result), &bufferSize);
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
path_free();
|
path_free();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::set_int(LPCSTR optPath, LPCSTR lpValueName, int data)
|
void options::set_int(LPCSTR optPath, LPCSTR lpValueName, int data)
|
||||||
{
|
{
|
||||||
DWORD dwDisposition;
|
|
||||||
HKEY hKey;
|
|
||||||
|
|
||||||
if (!OptionsRegPath)
|
if (!OptionsRegPath)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto regPath = path(optPath);
|
auto regPath = path(optPath);
|
||||||
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
|
|
||||||
{
|
|
||||||
RegSetValueExA(hKey, lpValueName, 0, 4u, reinterpret_cast<LPBYTE>(&data), 4u);
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
path_free();
|
path_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR dst, LPCSTR defaultValue, int iMaxLength)
|
void options::get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR dst, LPCSTR defaultValue, int iMaxLength)
|
||||||
{
|
{
|
||||||
DWORD dwDisposition;
|
strncpy_s(dst, iMaxLength, defaultValue, iMaxLength);
|
||||||
HKEY hKey;
|
|
||||||
|
|
||||||
lstrcpynA(dst, defaultValue, iMaxLength);
|
|
||||||
if (!OptionsRegPath)
|
if (!OptionsRegPath)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto regPath = path(optPath);
|
auto regPath = path(optPath);
|
||||||
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
|
|
||||||
{
|
|
||||||
DWORD bufferSize = iMaxLength;
|
|
||||||
RegQueryValueExA(hKey, lpValueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(dst), &bufferSize);
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
path_free();
|
path_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value)
|
void options::set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value)
|
||||||
{
|
{
|
||||||
DWORD dwDisposition;
|
|
||||||
HKEY hKey;
|
|
||||||
|
|
||||||
if (!OptionsRegPath)
|
if (!OptionsRegPath)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto regPath = path(optPath);
|
auto regPath = path(optPath);
|
||||||
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
|
|
||||||
{
|
|
||||||
RegSetValueExA(hKey, lpValueName, 0, 1u, LPBYTE(value), lstrlenA(value) + 1);
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
path_free();
|
path_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void options::menu_check(UINT uIDCheckItem, int check)
|
void options::toggle(uint32_t uIDCheckItem)
|
||||||
{
|
|
||||||
if (MenuHandle)
|
|
||||||
CheckMenuItem(MenuHandle, uIDCheckItem, check != 0 ? 8 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void options::menu_set(UINT uIDEnableItem, int enable)
|
|
||||||
{
|
|
||||||
if (MenuHandle)
|
|
||||||
EnableMenuItem(MenuHandle, uIDEnableItem, enable == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void options::toggle(UINT uIDCheckItem)
|
|
||||||
{
|
{
|
||||||
int newValue;
|
int newValue;
|
||||||
switch (uIDCheckItem)
|
switch (uIDCheckItem)
|
||||||
|
@ -289,7 +217,6 @@ void options::toggle(UINT uIDCheckItem)
|
||||||
newValue = Options.Sounds == 0;
|
newValue = Options.Sounds == 0;
|
||||||
Options.Sounds = Options.Sounds == 0;
|
Options.Sounds = Options.Sounds == 0;
|
||||||
Sound::Enable(0, 7, newValue);
|
Sound::Enable(0, 7, newValue);
|
||||||
menu_check(uIDCheckItem, newValue);
|
|
||||||
return;
|
return;
|
||||||
case Menu1_Music:
|
case Menu1_Music:
|
||||||
newValue = Options.Music == 0;
|
newValue = Options.Music == 0;
|
||||||
|
@ -298,31 +225,25 @@ void options::toggle(UINT uIDCheckItem)
|
||||||
midi::music_stop();
|
midi::music_stop();
|
||||||
else
|
else
|
||||||
midi::play_pb_theme(0);
|
midi::play_pb_theme(0);
|
||||||
menu_check(uIDCheckItem, newValue);
|
|
||||||
return;
|
return;
|
||||||
case Menu1_Full_Screen:
|
case Menu1_Full_Screen:
|
||||||
newValue = Options.FullScreen == 0;
|
newValue = Options.FullScreen == 0;
|
||||||
Options.FullScreen = Options.FullScreen == 0;
|
Options.FullScreen = Options.FullScreen == 0;
|
||||||
fullscrn::set_screen_mode(newValue);
|
fullscrn::set_screen_mode(newValue);
|
||||||
menu_check(uIDCheckItem, newValue);
|
|
||||||
return;
|
return;
|
||||||
case Menu1_1Player:
|
case Menu1_1Player:
|
||||||
case Menu1_2Players:
|
case Menu1_2Players:
|
||||||
case Menu1_3Players:
|
case Menu1_3Players:
|
||||||
case Menu1_4Players:
|
case Menu1_4Players:
|
||||||
Options.Players = uIDCheckItem - Menu1_1Player + 1;
|
Options.Players = uIDCheckItem - Menu1_1Player + 1;
|
||||||
menu_check(Menu1_1Player, Options.Players == 1);
|
|
||||||
menu_check(Menu1_2Players, Options.Players == 2);
|
|
||||||
menu_check(Menu1_3Players, Options.Players == 3);
|
|
||||||
menu_check(Menu1_4Players, Options.Players == 4);
|
|
||||||
break;
|
break;
|
||||||
case Menu1_MaximumResolution:
|
case Menu1_MaximumResolution:
|
||||||
case Menu1_640x480:
|
case Menu1_640x480:
|
||||||
case Menu1_800x600:
|
case Menu1_800x600:
|
||||||
case Menu1_1024x768:
|
case Menu1_1024x768:
|
||||||
{
|
{
|
||||||
for (unsigned i = Menu1_MaximumResolution; i <= Menu1_1024x768; ++i)
|
/*for (unsigned i = Menu1_MaximumResolution; i <= Menu1_1024x768; ++i)
|
||||||
menu_check(i, i == uIDCheckItem);
|
menu_check(i, i == uIDCheckItem);*/
|
||||||
|
|
||||||
int newResolution = uIDCheckItem - Menu1_640x480;
|
int newResolution = uIDCheckItem - Menu1_640x480;
|
||||||
if (uIDCheckItem == Menu1_MaximumResolution)
|
if (uIDCheckItem == Menu1_MaximumResolution)
|
||||||
|
@ -340,7 +261,6 @@ void options::toggle(UINT uIDCheckItem)
|
||||||
}
|
}
|
||||||
case Menu1_WindowUniformScale:
|
case Menu1_WindowUniformScale:
|
||||||
Options.UniformScaling ^= true;
|
Options.UniformScaling ^= true;
|
||||||
menu_check(Menu1_WindowUniformScale, Options.UniformScaling);
|
|
||||||
fullscrn::window_size_changed();
|
fullscrn::window_size_changed();
|
||||||
pb::paint();
|
pb::paint();
|
||||||
break;
|
break;
|
||||||
|
@ -353,8 +273,8 @@ void options::update_resolution_menu()
|
||||||
{
|
{
|
||||||
auto maxResolution = fullscrn::get_max_supported_resolution();
|
auto maxResolution = fullscrn::get_max_supported_resolution();
|
||||||
fullscrn::SetMaxResolution(maxResolution);
|
fullscrn::SetMaxResolution(maxResolution);
|
||||||
const CHAR* maxResText = pinball::get_rc_string(maxResolution + 2030, 0);
|
const char* maxResText = pinball::get_rc_string(maxResolution + 2030, 0);
|
||||||
if (MenuHandle)
|
/*if (MenuHandle)
|
||||||
ModifyMenuA(MenuHandle, Menu1_MaximumResolution, 0, Menu1_MaximumResolution, maxResText);
|
ModifyMenuA(MenuHandle, Menu1_MaximumResolution, 0, Menu1_MaximumResolution, maxResText);
|
||||||
|
|
||||||
for (auto resIndex = 0; resIndex < 3; resIndex++)
|
for (auto resIndex = 0; resIndex < 3; resIndex++)
|
||||||
|
@ -368,7 +288,7 @@ void options::update_resolution_menu()
|
||||||
if (Options.Resolution >= 0)
|
if (Options.Resolution >= 0)
|
||||||
menu_check(fullscrn::resolution_array[fullscrn::GetResolution()].ResolutionMenuId, 1);
|
menu_check(fullscrn::resolution_array[fullscrn::GetResolution()].ResolutionMenuId, 1);
|
||||||
else
|
else
|
||||||
menu_check(Menu1_MaximumResolution, 1);
|
menu_check(Menu1_MaximumResolution, 1);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::init_resolution()
|
void options::init_resolution()
|
||||||
|
@ -390,192 +310,3 @@ void options::keyboard()
|
||||||
{
|
{
|
||||||
//DialogBoxParamA(nullptr, "KEYMAPPER", nullptr, KeyMapDlgProc, 0);
|
//DialogBoxParamA(nullptr, "KEYMAPPER", nullptr, KeyMapDlgProc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
INT_PTR _stdcall options::KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
char keyName[20];
|
|
||||||
int keyBindings[6];
|
|
||||||
char rcString[256];
|
|
||||||
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
case WM_HELP:
|
|
||||||
WinHelpA(static_cast<HWND>(reinterpret_cast<HELPINFO*>(lParam)->hItemHandle), "pinball.hlp", HELP_WM_HELP,
|
|
||||||
(ULONG_PTR)keymap_help);
|
|
||||||
return 1;
|
|
||||||
case WM_CONTEXTMENU:
|
|
||||||
WinHelpA((HWND)wParam, "pinball.hlp", HELP_CONTEXTMENU, (ULONG_PTR)keymap_help);
|
|
||||||
return 1;
|
|
||||||
case WM_INITDIALOG:
|
|
||||||
for (auto vkPtr = vk_list; *vkPtr != -1; vkPtr++)
|
|
||||||
{
|
|
||||||
short vk = *vkPtr;
|
|
||||||
auto vk2And = vk & 0x4000;
|
|
||||||
auto vkChar = static_cast<uint8_t>(vk);
|
|
||||||
unsigned short maxVk;
|
|
||||||
|
|
||||||
if (vk2And)
|
|
||||||
{
|
|
||||||
auto index = 128;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (vkChar == MapVirtualKeyA(index, MAPVK_VK_TO_CHAR))
|
|
||||||
break;
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
while (index < 256);
|
|
||||||
|
|
||||||
if (index == 256)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
keyName[0] = static_cast<char>(vkChar);
|
|
||||||
keyName[1] = 0;
|
|
||||||
vkChar = index;
|
|
||||||
maxVk = index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (vk >= 0)
|
|
||||||
{
|
|
||||||
maxVk = vkChar;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++vkPtr;
|
|
||||||
maxVk = *vkPtr;
|
|
||||||
}
|
|
||||||
if (vkChar > maxVk)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int curVK = vkChar; curVK <= maxVk; curVK++)
|
|
||||||
{
|
|
||||||
if (vk2And || get_vk_key_name(curVK, keyName))
|
|
||||||
{
|
|
||||||
auto ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL,CB_INSERTSTRING, -1, (LPARAM)keyName);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_SETITEMDATA, ind, curVK);
|
|
||||||
if (curVK == Options.LeftFlipperKey)
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_SETCURSEL, ind, 0);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_INSERTSTRING, -1, (LPARAM)keyName);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_SETITEMDATA, ind, curVK);
|
|
||||||
if (curVK == Options.RightFlipperKey)
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_SETCURSEL, ind, 0);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_INSERTSTRING, -1, (LPARAM)keyName);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_SETITEMDATA, ind, curVK);
|
|
||||||
if (curVK == Options.PlungerKey)
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_SETCURSEL, ind, 0);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_INSERTSTRING, -1, (LPARAM)keyName);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_SETITEMDATA, ind, curVK);
|
|
||||||
if (curVK == Options.LeftTableBumpKey)
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_SETCURSEL, ind, 0);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_INSERTSTRING, -1, (LPARAM)keyName);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_SETITEMDATA, ind, curVK);
|
|
||||||
if (curVK == Options.RightTableBumpKey)
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_SETCURSEL, ind, 0);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_INSERTSTRING, -1, (LPARAM)keyName);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_SETITEMDATA, ind, curVK);
|
|
||||||
if (curVK == Options.BottomTableBumpKey)
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_SETCURSEL, ind, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
case WM_COMMAND:
|
|
||||||
switch (wParam)
|
|
||||||
{
|
|
||||||
case KEYMAPPER_Ok:
|
|
||||||
{
|
|
||||||
auto ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_GETCURSEL, 0, 0);
|
|
||||||
keyBindings[0] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_GETITEMDATA, ind, 0));
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_GETCURSEL, 0, 0);
|
|
||||||
keyBindings[1] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_GETITEMDATA, ind, 0));
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_GETCURSEL, 0, 0);
|
|
||||||
keyBindings[2] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_GETITEMDATA, ind, 0));
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_GETCURSEL, 0, 0);
|
|
||||||
keyBindings[3] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_GETITEMDATA, ind, 0));
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_GETCURSEL, 0, 0);
|
|
||||||
keyBindings[4] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_GETITEMDATA, ind, 0));
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_GETCURSEL, 0, 0);
|
|
||||||
keyBindings[5] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_GETITEMDATA, ind, 0));
|
|
||||||
|
|
||||||
auto sameKeyBound = 0;
|
|
||||||
auto index = 1;
|
|
||||||
auto optPtr = keyBindings;
|
|
||||||
while (!sameKeyBound)
|
|
||||||
{
|
|
||||||
for (auto keyInd = index; keyInd < 6; keyInd++)
|
|
||||||
{
|
|
||||||
if (sameKeyBound)
|
|
||||||
break;
|
|
||||||
if (*optPtr == keyBindings[keyInd])
|
|
||||||
{
|
|
||||||
lstrcpyA(rcString, pinball::get_rc_string(43, 0));
|
|
||||||
MessageBoxA(hDlg, pinball::get_rc_string(39, 0), rcString, 0x2000u);
|
|
||||||
sameKeyBound = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
++optPtr;
|
|
||||||
if (index - 1 >= 5)
|
|
||||||
{
|
|
||||||
if (sameKeyBound)
|
|
||||||
return 1;
|
|
||||||
Options.LeftFlipperKey = keyBindings[0];
|
|
||||||
Options.RightFlipperKey = keyBindings[1];
|
|
||||||
Options.PlungerKey = keyBindings[2];
|
|
||||||
Options.LeftTableBumpKey = keyBindings[3];
|
|
||||||
Options.RightTableBumpKey = keyBindings[4];
|
|
||||||
Options.BottomTableBumpKey = keyBindings[5];
|
|
||||||
EndDialog(hDlg, wParam);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case KEYMAPPER_Cancel:
|
|
||||||
EndDialog(hDlg, wParam);
|
|
||||||
return 1;
|
|
||||||
case KEYMAPPER_Default:
|
|
||||||
{
|
|
||||||
auto name = (LPARAM)get_vk_key_name(Options.LeftFlipperKeyDft, keyName);
|
|
||||||
auto ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_FINDSTRINGEXACT, 0, name);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_SETCURSEL, ind, 0);
|
|
||||||
name = (LPARAM)get_vk_key_name(Options.RightFlipperKeyDft, keyName);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_FINDSTRINGEXACT, 0, name);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_SETCURSEL, ind, 0);
|
|
||||||
name = (LPARAM)get_vk_key_name(Options.PlungerKeyDft, keyName);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_FINDSTRINGEXACT, 0, name);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_SETCURSEL, ind, 0);
|
|
||||||
name = (LPARAM)get_vk_key_name(Options.LeftTableBumpKeyDft, keyName);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_FINDSTRINGEXACT, 0, name);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_SETCURSEL, ind, 0);
|
|
||||||
name = (LPARAM)get_vk_key_name(Options.RightTableBumpKeyDft, keyName);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_FINDSTRINGEXACT, 0, name);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_SETCURSEL, ind, 0);
|
|
||||||
name = (LPARAM)get_vk_key_name(Options.BottomTableBumpKeyDft, keyName);
|
|
||||||
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_FINDSTRINGEXACT, 0, name);
|
|
||||||
SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_SETCURSEL, ind, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LPSTR options::get_vk_key_name(uint16_t vk, LPSTR keyName)
|
|
||||||
{
|
|
||||||
LONG scanCode = MapVirtualKeyA(vk, MAPVK_VK_TO_VSC) << 16;
|
|
||||||
if (vk >= 0x21u && vk <= 0x2Eu)
|
|
||||||
scanCode |= 0x1000000u;
|
|
||||||
return GetKeyNameTextA(scanCode, keyName, 19) != 0 ? keyName : nullptr;
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ struct optionsStruct
|
||||||
int Music;
|
int Music;
|
||||||
int Average;
|
int Average;
|
||||||
int FullScreen;
|
int FullScreen;
|
||||||
int PriorityAdj;
|
|
||||||
int Players;
|
int Players;
|
||||||
int LeftFlipperKey;
|
int LeftFlipperKey;
|
||||||
int RightFlipperKey;
|
int RightFlipperKey;
|
||||||
|
@ -29,7 +28,7 @@ struct optionsStruct
|
||||||
class options
|
class options
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void init(HMENU menuHandle);
|
static void init();
|
||||||
static void uninit();
|
static void uninit();
|
||||||
static void path_init(LPCSTR regPath);
|
static void path_init(LPCSTR regPath);
|
||||||
static void path_uninit();
|
static void path_uninit();
|
||||||
|
@ -37,15 +36,11 @@ public:
|
||||||
static void set_int(LPCSTR optPath, LPCSTR lpValueName, int data);
|
static void set_int(LPCSTR optPath, LPCSTR lpValueName, int data);
|
||||||
static void get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR dst, LPCSTR defaultValue, int iMaxLength);
|
static void get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR dst, LPCSTR defaultValue, int iMaxLength);
|
||||||
static void set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value);
|
static void set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value);
|
||||||
static void menu_check(UINT uIDCheckItem, int check);
|
static void toggle(uint32_t uIDCheckItem);
|
||||||
static void menu_set(UINT uIDEnableItem, int enable);
|
|
||||||
static void toggle(UINT uIDCheckItem);
|
|
||||||
static void update_resolution_menu();
|
static void update_resolution_menu();
|
||||||
static void init_resolution();
|
static void init_resolution();
|
||||||
|
|
||||||
static void keyboard();
|
static void keyboard();
|
||||||
static INT_PTR _stdcall KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
||||||
static LPSTR get_vk_key_name(uint16_t vk, LPSTR keyName);
|
|
||||||
|
|
||||||
static optionsStruct Options;
|
static optionsStruct Options;
|
||||||
private:
|
private:
|
||||||
|
@ -53,7 +48,6 @@ private:
|
||||||
static LPSTR OptionsRegPathCur;
|
static LPSTR OptionsRegPathCur;
|
||||||
static LPCSTR path(LPCSTR regPath);
|
static LPCSTR path(LPCSTR regPath);
|
||||||
static void path_free();
|
static void path_free();
|
||||||
static HMENU MenuHandle;
|
|
||||||
static winhelp_entry keymap_help[18];
|
static winhelp_entry keymap_help[18];
|
||||||
static short vk_list[28];
|
static short vk_list[28];
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool ful
|
||||||
if (fileHandle == nullptr)
|
if (fileHandle == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
fread(&header, 1, sizeof datFileHeader, fileHandle);
|
fread(&header, 1, sizeof datFileHeader, fileHandle);
|
||||||
if (lstrcmpA("PARTOUT(4.0)RESOURCE", header.FileSignature))
|
if (strcmp("PARTOUT(4.0)RESOURCE", header.FileSignature) != 0)
|
||||||
{
|
{
|
||||||
fclose(fileHandle);
|
fclose(fileHandle);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -31,13 +31,13 @@ datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool ful
|
||||||
fclose(fileHandle);
|
fclose(fileHandle);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (lstrlenA(header.Description) <= 0)
|
if (strlen(header.Description) <= 0)
|
||||||
{
|
{
|
||||||
datFile->Description = nullptr;
|
datFile->Description = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int lenOfStr = lstrlenA(header.Description);
|
auto lenOfStr = strlen(header.Description);
|
||||||
auto descriptionBuf = memory::allocate(lenOfStr + 1);
|
auto descriptionBuf = memory::allocate(lenOfStr + 1);
|
||||||
datFile->Description = descriptionBuf;
|
datFile->Description = descriptionBuf;
|
||||||
if (!descriptionBuf)
|
if (!descriptionBuf)
|
||||||
|
@ -46,7 +46,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool ful
|
||||||
memory::free(datFile);
|
memory::free(datFile);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
lstrcpyA(descriptionBuf, header.Description);
|
strcpy_s(descriptionBuf, lenOfStr + 1, header.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.Unknown)
|
if (header.Unknown)
|
||||||
|
@ -256,7 +256,7 @@ int partman::field_size(datFileStruct* datFile, int groupIndex, datFieldTypes ta
|
||||||
|
|
||||||
int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName)
|
int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName)
|
||||||
{
|
{
|
||||||
auto targetLength = lstrlenA(targetGroupName);
|
auto targetLength = strlen(targetGroupName);
|
||||||
for (int groupIndex = datFile->NumberOfGroups - 1; groupIndex >= 0; --groupIndex)
|
for (int groupIndex = datFile->NumberOfGroups - 1; groupIndex >= 0; --groupIndex)
|
||||||
{
|
{
|
||||||
auto groupName = field(datFile, groupIndex, datFieldTypes::GroupName);
|
auto groupName = field(datFile, groupIndex, datFieldTypes::GroupName);
|
||||||
|
|
|
@ -36,11 +36,11 @@ bool pb::FullTiltMode = false;
|
||||||
int pb::init()
|
int pb::init()
|
||||||
{
|
{
|
||||||
float projMat[12], zMin = 0, zScaler = 0;
|
float projMat[12], zMin = 0, zScaler = 0;
|
||||||
CHAR datFileName[300];
|
char datFileName[300];
|
||||||
CHAR dataFilePath[300];
|
char dataFilePath[300];
|
||||||
|
|
||||||
++memory::critical_allocation;
|
++memory::critical_allocation;
|
||||||
lstrcpyA(datFileName, winmain::DatFileName);
|
strcpy_s(datFileName, winmain::DatFileName);
|
||||||
pinball::make_path_name(dataFilePath, datFileName, 300);
|
pinball::make_path_name(dataFilePath, datFileName, 300);
|
||||||
record_table = partman::load_records(dataFilePath, fullscrn::GetResolution(), FullTiltMode);
|
record_table = partman::load_records(dataFilePath, fullscrn::GetResolution(), FullTiltMode);
|
||||||
|
|
||||||
|
@ -148,9 +148,9 @@ void pb::mode_change(int mode)
|
||||||
case 1:
|
case 1:
|
||||||
if (demo_mode)
|
if (demo_mode)
|
||||||
{
|
{
|
||||||
options::menu_set(Menu1_Launch_Ball, 0);
|
winmain::LaunchBallEnabled = false;
|
||||||
options::menu_set(Menu1_High_Scores, 0);
|
winmain::HighScoresEnabled = false;
|
||||||
options::menu_check(Menu1_Demo, 1);
|
winmain::DemoActive = true;
|
||||||
if (MainTable)
|
if (MainTable)
|
||||||
{
|
{
|
||||||
if (MainTable->Demo)
|
if (MainTable->Demo)
|
||||||
|
@ -159,9 +159,9 @@ void pb::mode_change(int mode)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
options::menu_set(Menu1_High_Scores, 1);
|
winmain::LaunchBallEnabled = true;
|
||||||
options::menu_set(Menu1_Launch_Ball, 1);
|
winmain::HighScoresEnabled = true;
|
||||||
options::menu_check(Menu1_Demo, 0);
|
winmain::DemoActive = false;
|
||||||
if (MainTable)
|
if (MainTable)
|
||||||
{
|
{
|
||||||
if (MainTable->Demo)
|
if (MainTable->Demo)
|
||||||
|
@ -170,19 +170,19 @@ void pb::mode_change(int mode)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
options::menu_set(Menu1_Launch_Ball, 0);
|
winmain::LaunchBallEnabled = false;
|
||||||
if (!demo_mode)
|
if (!demo_mode)
|
||||||
{
|
{
|
||||||
options::menu_set(Menu1_High_Scores, 1);
|
winmain::HighScoresEnabled = true;
|
||||||
options::menu_check(Menu1_Demo, 0);
|
winmain::DemoActive = false;
|
||||||
}
|
}
|
||||||
if (MainTable && MainTable->LightGroup)
|
if (MainTable && MainTable->LightGroup)
|
||||||
MainTable->LightGroup->Message(29, 1.4f);
|
MainTable->LightGroup->Message(29, 1.4f);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
options::menu_set(Menu1_Launch_Ball, 0);
|
winmain::LaunchBallEnabled = false;
|
||||||
options::menu_set(Menu1_High_Scores, 0);
|
winmain::HighScoresEnabled = false;
|
||||||
mode_countdown_ = 5000;
|
mode_countdown_ = 5000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -479,7 +479,7 @@ void pb::keydown(int key)
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
char String1[200];
|
char String1[200];
|
||||||
lstrcpyA(String1, pinball::get_rc_string(26, 0));
|
strcpy_s(String1, pinball::get_rc_string(26, 0));
|
||||||
high_score::show_and_set_high_score_dialog(highscore_table, 1000000000, 1, String1);
|
high_score::show_and_set_high_score_dialog(highscore_table, 1000000000, 1, String1);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
|
@ -490,10 +490,10 @@ void pb::keydown(int key)
|
||||||
case 'r':
|
case 'r':
|
||||||
control::cheat_bump_rank();
|
control::cheat_bump_rank();
|
||||||
break;
|
break;
|
||||||
case VK_F11:
|
case SDLK_F11:
|
||||||
gdrv::get_focus();
|
gdrv::get_focus();
|
||||||
break;
|
break;
|
||||||
case VK_F12:
|
case SDLK_F12:
|
||||||
MainTable->port_draw();
|
MainTable->port_draw();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -569,7 +569,7 @@ void pb::end_game()
|
||||||
int position = high_score::get_score_position(highscore_table, scores[i]);
|
int position = high_score::get_score_position(highscore_table, scores[i]);
|
||||||
if (position >= 0)
|
if (position >= 0)
|
||||||
{
|
{
|
||||||
lstrcpyA(String1, pinball::get_rc_string(scoreIndex[i] + 26, 0));
|
strcpy_s(String1, pinball::get_rc_string(scoreIndex[i] + 26, 0));
|
||||||
high_score::show_and_set_high_score_dialog(highscore_table, scores[i], position, String1);
|
high_score::show_and_set_high_score_dialog(highscore_table, scores[i], position, String1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,17 @@
|
||||||
#define PCH_H
|
#define PCH_H
|
||||||
|
|
||||||
// TODO: add headers that you want to pre-compile here
|
// TODO: add headers that you want to pre-compile here
|
||||||
#include <Windows.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <CommCtrl.h>
|
|
||||||
#include <htmlhelp.h>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits> /*For control template*/
|
#include <type_traits> /*For control template*/
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
//#include <iostream>
|
//#include <iostream>
|
||||||
#include <iomanip>
|
//#include <iomanip>
|
||||||
//#include <cstdlib>
|
//#include <cstdlib>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#define SDL_MAIN_HANDLED
|
#define SDL_MAIN_HANDLED
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
|
@ -33,9 +32,12 @@
|
||||||
//https://github.com/Tyyppi77/imgui_sdl 01deb04b102b6a1c15c7fdec1977a2c96a885e6f
|
//https://github.com/Tyyppi77/imgui_sdl 01deb04b102b6a1c15c7fdec1977a2c96a885e6f
|
||||||
#include "imgui_sdl.h"
|
#include "imgui_sdl.h"
|
||||||
|
|
||||||
//typedef const char* LPCSTR;
|
typedef unsigned long DWORD;
|
||||||
//typedef int HINSTANCE;
|
typedef char* LPSTR;
|
||||||
//typedef int HWND;
|
typedef const char* LPCSTR;
|
||||||
|
|
||||||
|
#define min(a,b) ((a)<(b)?(a):(b))
|
||||||
|
#define max(a,b) ((a)>(b)?(a):(b))
|
||||||
|
|
||||||
/*Use (void) to silent unused warnings.*/
|
/*Use (void) to silent unused warnings.*/
|
||||||
#define assertm(exp, msg) assert(((void)msg, exp))
|
#define assertm(exp, msg) assert(((void)msg, exp))
|
||||||
|
|
|
@ -206,7 +206,7 @@ std::map<uint32_t, LPCSTR> rc_strings
|
||||||
{2032, "Use &Maximum Resolution (1024 x 768)"}
|
{2032, "Use &Maximum Resolution (1024 x 768)"}
|
||||||
};
|
};
|
||||||
|
|
||||||
int LoadStringAlt(UINT uID, LPSTR lpBuffer, int cchBufferMax)
|
int LoadStringAlt(uint32_t uID, LPSTR lpBuffer, int cchBufferMax)
|
||||||
{
|
{
|
||||||
auto str = rc_strings.find(uID);
|
auto str = rc_strings.find(uID);
|
||||||
if (str == rc_strings.end())
|
if (str == rc_strings.end())
|
||||||
|
@ -246,100 +246,15 @@ int pinball::get_rc_int(int uID, int* dst)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pinball::FindShiftKeys()
|
|
||||||
{
|
|
||||||
signed int i;
|
|
||||||
int rightShift;
|
|
||||||
CHAR stringBuf[20];
|
|
||||||
|
|
||||||
RightShift = -1;
|
|
||||||
LeftShift = -1;
|
|
||||||
for (i = 0; i < 256; ++i)
|
|
||||||
{
|
|
||||||
if (MapVirtualKeyA(i, 1u) == 16)
|
|
||||||
{
|
|
||||||
LeftShift = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (++i < 256)
|
|
||||||
{
|
|
||||||
if (MapVirtualKeyA(i, 1u) == 16)
|
|
||||||
{
|
|
||||||
RightShift = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!GetKeyNameTextA(LeftShift << 16, stringBuf, 19) || !_strnicmp(stringBuf, "right", 5u))
|
|
||||||
{
|
|
||||||
rightShift = RightShift;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rightShift = LeftShift;
|
|
||||||
LeftShift = RightShift;
|
|
||||||
RightShift = rightShift;
|
|
||||||
}
|
|
||||||
if (GetKeyNameTextA(rightShift << 16, stringBuf, 19))
|
|
||||||
{
|
|
||||||
if (_strnicmp(stringBuf, "left", 4u) != 0)
|
|
||||||
{
|
|
||||||
auto tmp = LeftShift;
|
|
||||||
LeftShift = RightShift;
|
|
||||||
RightShift = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void pinball::adjust_priority(int priority)
|
|
||||||
{
|
|
||||||
auto thread = GetCurrentThread();
|
|
||||||
switch (priority)
|
|
||||||
{
|
|
||||||
case -2:
|
|
||||||
SetThreadPriority(thread, -2);
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
SetThreadPriority(thread, -1);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
SetThreadPriority(thread, 0);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
SetThreadPriority(thread, 1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
SetThreadPriority(thread, 2);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
SetThreadPriority(thread, 15);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int pinball::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize)
|
int pinball::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize)
|
||||||
{
|
{
|
||||||
int nameSize = GetModuleFileNameA(nullptr, lpFilename, nSize);
|
auto base_path = SDL_GetBasePath();
|
||||||
if (!nameSize || nameSize == nSize)
|
if (!base_path)
|
||||||
|
{
|
||||||
|
strcat_s(lpFilename, nSize, "?");
|
||||||
return 1;
|
return 1;
|
||||||
for (CHAR* i = &lpFilename[nameSize]; i > lpFilename; --i)
|
|
||||||
{
|
|
||||||
if (*i == '\\' || *i == ':')
|
|
||||||
{
|
|
||||||
i[1] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
--nameSize;
|
|
||||||
}
|
}
|
||||||
if (nameSize + 13 < nSize)
|
strcpy_s(lpFilename, nSize, base_path);
|
||||||
{
|
strcat_s(lpFilename, nSize, lpString2);
|
||||||
lstrcatA(lpFilename, lpString2);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lstrcatA(lpFilename, "?");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ public:
|
||||||
|
|
||||||
static char* get_rc_string(int uID, int a2);
|
static char* get_rc_string(int uID, int a2);
|
||||||
static int get_rc_int(int uID, int* dst);
|
static int get_rc_int(int uID, int* dst);
|
||||||
static void FindShiftKeys();
|
|
||||||
static void adjust_priority(int priority);
|
|
||||||
static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu);
|
static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu);
|
||||||
private:
|
private:
|
||||||
static char getRcBuffer[256 * 6];
|
static char getRcBuffer[256 * 6];
|
||||||
|
|
|
@ -273,7 +273,7 @@ void score::update(scoreStruct* score)
|
||||||
|
|
||||||
void score::string_format(int score, char* str)
|
void score::string_format(int score, char* str)
|
||||||
{
|
{
|
||||||
CHAR separator[12];
|
char separator[12];
|
||||||
|
|
||||||
if (score == -999)
|
if (score == -999)
|
||||||
{
|
{
|
||||||
|
@ -281,25 +281,7 @@ void score::string_format(int score, char* str)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lstrcpyA(separator, ",");
|
strcpy_s(separator, ",");
|
||||||
|
|
||||||
HKEY phkResult;
|
|
||||||
DWORD dwDisposition;
|
|
||||||
if (!RegCreateKeyExA(
|
|
||||||
HKEY_CURRENT_USER,
|
|
||||||
"Control Panel\\International",
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
0,
|
|
||||||
KEY_ALL_ACCESS,
|
|
||||||
nullptr,
|
|
||||||
&phkResult,
|
|
||||||
&dwDisposition))
|
|
||||||
{
|
|
||||||
DWORD cbData = 10;
|
|
||||||
RegQueryValueExA(phkResult, "sThousand", nullptr, nullptr, (LPBYTE)separator, &cbData);
|
|
||||||
RegCloseKey(phkResult);
|
|
||||||
}
|
|
||||||
int scoreMillions = score % 1000000000 / 1000000;
|
int scoreMillions = score % 1000000000 / 1000000;
|
||||||
if (score / 1000000000 <= 0)
|
if (score / 1000000000 <= 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
const double TargetFps = 60, TargetFrameTime = 1000 / TargetFps;
|
const double TargetFps = 60, TargetFrameTime = 1000 / TargetFps;
|
||||||
|
|
||||||
HCURSOR winmain::mouse_hsave;
|
|
||||||
SDL_Window* winmain::MainWindow = nullptr;
|
SDL_Window* winmain::MainWindow = nullptr;
|
||||||
SDL_Renderer* winmain::Renderer = nullptr;
|
SDL_Renderer* winmain::Renderer = nullptr;
|
||||||
ImGuiIO* winmain::ImIO = nullptr;
|
ImGuiIO* winmain::ImIO = nullptr;
|
||||||
|
@ -31,13 +30,15 @@ int winmain::no_time_loss;
|
||||||
|
|
||||||
DWORD winmain::then;
|
DWORD winmain::then;
|
||||||
DWORD winmain::now;
|
DWORD winmain::now;
|
||||||
UINT winmain::iFrostUniqueMsg;
|
|
||||||
bool winmain::restart = false;
|
bool winmain::restart = false;
|
||||||
|
|
||||||
gdrv_bitmap8 winmain::gfr_display{};
|
gdrv_bitmap8 winmain::gfr_display{};
|
||||||
char winmain::DatFileName[300]{};
|
char winmain::DatFileName[300]{};
|
||||||
bool winmain::ShowAboutDialog = false;
|
bool winmain::ShowAboutDialog = false;
|
||||||
bool winmain::ShowImGuiDemo = false;
|
bool winmain::ShowImGuiDemo = false;
|
||||||
|
bool winmain::LaunchBallEnabled = true;
|
||||||
|
bool winmain::HighScoresEnabled = true;
|
||||||
|
bool winmain::DemoActive = false;
|
||||||
|
|
||||||
|
|
||||||
uint32_t timeGetTimeAlt()
|
uint32_t timeGetTimeAlt()
|
||||||
|
@ -80,7 +81,6 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
pb::FullTiltMode = true;
|
pb::FullTiltMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pinball::FindShiftKeys();
|
|
||||||
options::init_resolution();
|
options::init_resolution();
|
||||||
|
|
||||||
// SDL window
|
// SDL window
|
||||||
|
@ -125,18 +125,19 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
{
|
{
|
||||||
++memory::critical_allocation;
|
++memory::critical_allocation;
|
||||||
|
|
||||||
options::init(nullptr);
|
options::init();
|
||||||
auto voiceCount = options::get_int(nullptr, "Voices", 8);
|
auto voiceCount = options::get_int(nullptr, "Voices", 8);
|
||||||
if (!Sound::Init(voiceCount))
|
if (Sound::Init(voiceCount))
|
||||||
options::menu_set(Menu1_Sounds, 0);
|
options::Options.Sounds = 0;
|
||||||
Sound::Activate();
|
Sound::Activate();
|
||||||
|
|
||||||
if (!pinball::quickFlag && !midi::music_init())
|
if (!pinball::quickFlag && !midi::music_init())
|
||||||
options::menu_set(Menu1_Music, 0);
|
options::Options.Music = 0;
|
||||||
|
|
||||||
if (pb::init())
|
if (pb::init())
|
||||||
{
|
{
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not load game data", "The .dat file is missing", window);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not load game data",
|
||||||
|
"The .dat file is missing", window);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,14 +152,11 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
if (strstr(lpCmdLine, "-fullscreen"))
|
if (strstr(lpCmdLine, "-fullscreen"))
|
||||||
{
|
{
|
||||||
options::Options.FullScreen = 1;
|
options::Options.FullScreen = 1;
|
||||||
options::menu_check(Menu1_Full_Screen, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_ShowWindow(window);
|
SDL_ShowWindow(window);
|
||||||
fullscrn::set_screen_mode(options::Options.FullScreen);
|
fullscrn::set_screen_mode(options::Options.FullScreen);
|
||||||
|
|
||||||
pinball::adjust_priority(options::Options.PriorityAdj);
|
|
||||||
|
|
||||||
if (strstr(lpCmdLine, "-demo"))
|
if (strstr(lpCmdLine, "-demo"))
|
||||||
pb::toggle_demo();
|
pb::toggle_demo();
|
||||||
else
|
else
|
||||||
|
@ -249,7 +247,7 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
|
|
||||||
if (curTime == then)
|
if (curTime == then)
|
||||||
{
|
{
|
||||||
Sleep(8u);
|
SDL_Delay(8);
|
||||||
}
|
}
|
||||||
else if (pb::frame(curTime - then))
|
else if (pb::frame(curTime - then))
|
||||||
{
|
{
|
||||||
|
@ -308,7 +306,8 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
|
|
||||||
if (restart)
|
if (restart)
|
||||||
{
|
{
|
||||||
char restartPath[300]{};
|
// Todo: get rid of restart to change resolution.
|
||||||
|
/*char restartPath[300]{};
|
||||||
if (GetModuleFileNameA(nullptr, restartPath, 300))
|
if (GetModuleFileNameA(nullptr, restartPath, 300))
|
||||||
{
|
{
|
||||||
STARTUPINFO si{};
|
STARTUPINFO si{};
|
||||||
|
@ -320,7 +319,7 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -342,7 +341,7 @@ void winmain::RenderUi()
|
||||||
{
|
{
|
||||||
new_game();
|
new_game();
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Launch Ball"))
|
if (ImGui::MenuItem("Launch Ball", nullptr, false, LaunchBallEnabled))
|
||||||
{
|
{
|
||||||
end_pause();
|
end_pause();
|
||||||
pb::launch_ball();
|
pb::launch_ball();
|
||||||
|
@ -353,13 +352,13 @@ void winmain::RenderUi()
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::MenuItem("High Scores..."))
|
if (ImGui::MenuItem("High Scores...", nullptr, false, HighScoresEnabled))
|
||||||
{
|
{
|
||||||
if (!single_step)
|
if (!single_step)
|
||||||
pause();
|
pause();
|
||||||
pb::high_scores();
|
pb::high_scores();
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Demo"))
|
if (ImGui::MenuItem("Demo", nullptr, DemoActive))
|
||||||
{
|
{
|
||||||
end_pause();
|
end_pause();
|
||||||
pb::toggle_demo();
|
pb::toggle_demo();
|
||||||
|
@ -450,7 +449,7 @@ void winmain::RenderUi()
|
||||||
{
|
{
|
||||||
if (!single_step)
|
if (!single_step)
|
||||||
pause();
|
pause();
|
||||||
help_introduction(nullptr, (HWND)MainWindow);
|
help_introduction();
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
|
@ -507,7 +506,6 @@ int winmain::event_handler(const SDL_Event* event)
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
end_pause();
|
end_pause();
|
||||||
bQuit = 1;
|
bQuit = 1;
|
||||||
PostQuitMessage(0);
|
|
||||||
fullscrn::shutdown();
|
fullscrn::shutdown();
|
||||||
return_value = 0;
|
return_value = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -525,7 +523,7 @@ int winmain::event_handler(const SDL_Event* event)
|
||||||
SDL_MinimizeWindow(MainWindow);
|
SDL_MinimizeWindow(MainWindow);
|
||||||
break;
|
break;
|
||||||
case SDLK_F1:
|
case SDLK_F1:
|
||||||
help_introduction(nullptr, (HWND)MainWindow);
|
help_introduction();
|
||||||
break;
|
break;
|
||||||
case SDLK_F2:
|
case SDLK_F2:
|
||||||
new_game();
|
new_game();
|
||||||
|
@ -637,7 +635,6 @@ int winmain::event_handler(const SDL_Event* event)
|
||||||
if (options::Options.Music && !single_step)
|
if (options::Options.Music && !single_step)
|
||||||
midi::play_pb_theme(0);
|
midi::play_pb_theme(0);
|
||||||
no_time_loss = 1;
|
no_time_loss = 1;
|
||||||
pinball::adjust_priority(options::Options.PriorityAdj);
|
|
||||||
has_focus = 1;
|
has_focus = 1;
|
||||||
gdrv::get_focus();
|
gdrv::get_focus();
|
||||||
pb::paint();
|
pb::paint();
|
||||||
|
@ -646,9 +643,7 @@ int winmain::event_handler(const SDL_Event* event)
|
||||||
case SDL_WINDOWEVENT_HIDDEN:
|
case SDL_WINDOWEVENT_HIDDEN:
|
||||||
activated = 0;
|
activated = 0;
|
||||||
fullscrn::activate(0);
|
fullscrn::activate(0);
|
||||||
options::menu_check(Menu1_Full_Screen, 0);
|
|
||||||
options::Options.FullScreen = 0;
|
options::Options.FullScreen = 0;
|
||||||
SetThreadPriority(GetCurrentThread(), 0);
|
|
||||||
Sound::Deactivate();
|
Sound::Deactivate();
|
||||||
midi::music_stop();
|
midi::music_stop();
|
||||||
has_focus = 0;
|
has_focus = 0;
|
||||||
|
@ -693,7 +688,7 @@ void winmain::memalloc_failure()
|
||||||
gdrv::uninit();
|
gdrv::uninit();
|
||||||
char* caption = pinball::get_rc_string(170, 0);
|
char* caption = pinball::get_rc_string(170, 0);
|
||||||
char* text = pinball::get_rc_string(179, 0);
|
char* text = pinball::get_rc_string(179, 0);
|
||||||
MessageBoxA(nullptr, text, caption, 0x2030u);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, caption, text, MainWindow);
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,9 +727,7 @@ void winmain::end_pause()
|
||||||
void winmain::new_game()
|
void winmain::new_game()
|
||||||
{
|
{
|
||||||
end_pause();
|
end_pause();
|
||||||
HCURSOR prevCursor = SetCursor(LoadCursorA(nullptr, IDC_WAIT));
|
|
||||||
pb::replay_level(0);
|
pb::replay_level(0);
|
||||||
SetCursor(prevCursor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void winmain::pause()
|
void winmain::pause()
|
||||||
|
@ -743,26 +736,8 @@ void winmain::pause()
|
||||||
no_time_loss = 1;
|
no_time_loss = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void winmain::help_introduction(HINSTANCE a1, HWND a2)
|
void winmain::help_introduction()
|
||||||
{
|
{
|
||||||
char* buf1 = memory::allocate(0x1F4u);
|
|
||||||
if (buf1)
|
|
||||||
{
|
|
||||||
char* buf2 = memory::allocate(0x1F4u);
|
|
||||||
if (buf2)
|
|
||||||
{
|
|
||||||
options::get_string(nullptr, "HelpFile", buf1, pinball::get_rc_string(178, 0), 500);
|
|
||||||
options::get_string(pinball::get_rc_string(166, 0), "HelpFile", buf1, buf1, 500);
|
|
||||||
lstrcpyA(buf2, buf1);
|
|
||||||
memory::free(buf1);
|
|
||||||
//HtmlHelpA(GetDesktopWindow(), buf2, 0, 0);
|
|
||||||
memory::free(buf2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memory::free(buf1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void winmain::Restart()
|
void winmain::Restart()
|
||||||
|
|
|
@ -9,6 +9,9 @@ public:
|
||||||
static SDL_Window* MainWindow;
|
static SDL_Window* MainWindow;
|
||||||
static SDL_Renderer* Renderer;
|
static SDL_Renderer* Renderer;
|
||||||
static ImGuiIO* ImIO;
|
static ImGuiIO* ImIO;
|
||||||
|
static bool LaunchBallEnabled;
|
||||||
|
static bool HighScoresEnabled;
|
||||||
|
static bool DemoActive;
|
||||||
|
|
||||||
static int WinMain(LPCSTR lpCmdLine);
|
static int WinMain(LPCSTR lpCmdLine);
|
||||||
static int event_handler(const SDL_Event* event);
|
static int event_handler(const SDL_Event* event);
|
||||||
|
@ -18,15 +21,13 @@ public:
|
||||||
static void end_pause();
|
static void end_pause();
|
||||||
static void new_game();
|
static void new_game();
|
||||||
static void pause();
|
static void pause();
|
||||||
static void help_introduction(HINSTANCE a1, HWND a2);
|
static void help_introduction();
|
||||||
static void Restart();
|
static void Restart();
|
||||||
private:
|
private:
|
||||||
static int return_value, bQuit, DispFrameRate, DispGRhistory, activated;
|
static int return_value, bQuit, DispFrameRate, DispGRhistory, activated;
|
||||||
static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss;
|
static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss;
|
||||||
static DWORD then, now;
|
static DWORD then, now;
|
||||||
static UINT iFrostUniqueMsg;
|
|
||||||
static gdrv_bitmap8 gfr_display;
|
static gdrv_bitmap8 gfr_display;
|
||||||
static HCURSOR mouse_hsave;
|
|
||||||
static bool restart;
|
static bool restart;
|
||||||
static bool ShowAboutDialog;
|
static bool ShowAboutDialog;
|
||||||
static bool ShowImGuiDemo;
|
static bool ShowImGuiDemo;
|
||||||
|
|
Loading…
Reference in a new issue