├── .gitignore ├── .gitmodules ├── .vscode ├── c_cpp_properties.json ├── launch.json └── tasks.json ├── ECLC ├── Calc.cpp ├── Calc.h ├── Eclc.cpp ├── Eclcdef.h └── converter.cpp ├── GIAN07 ├── BOMBEFC.CPP ├── BOMBEFC.H ├── BOSS.CPP ├── BOSS.H ├── CONFIG.CPP ├── CONFIG.H ├── DEMOPLAY.CPP ├── DEMOPLAY.H ├── ECL.H ├── ECL_LEN.H ├── EFFECT.CPP ├── EFFECT.H ├── EFFECT3D.CPP ├── EFFECT3D.H ├── ENDING.CPP ├── ENDING.H ├── ENEMY.CPP ├── ENEMY.H ├── ENTRY.CPP ├── ENTRY.H ├── EXDEF.H ├── EnemyExCtrl.cpp ├── EnemyExCtrl.h ├── FONTUTY.CPP ├── FONTUTY.H ├── FRAGMENT.CPP ├── FRAGMENT.H ├── GAMEMAIN.CPP ├── GAMEMAIN.H ├── GEOMETRY.CPP ├── GEOMETRY.H ├── GIAN.CPP ├── GIAN.H ├── GIAN07.desktop.in ├── GIAN07.rc ├── HOMINGL.CPP ├── HOMINGL.H ├── ITEM.CPP ├── ITEM.H ├── LASER.CPP ├── LASER.H ├── LENS.CPP ├── LENS.H ├── LEVEL.H ├── LLASER.CPP ├── LLASER.H ├── LOADER.CPP ├── LOADER.H ├── LZ_UTY.CPP ├── LZ_UTY.H ├── MAID.CPP ├── MAID.H ├── MAIDTAMA.CPP ├── MAIDTAMA.H ├── MUSIC.CPP ├── MUSIC.H ├── PRankCtrl.cpp ├── PRankCtrl.h ├── SCL.H ├── SCORE.CPP ├── SCORE.H ├── SCROLL.CPP ├── SCROLL.H ├── TAMA.CPP ├── TAMA.H ├── WindowCtrl.cpp ├── WindowCtrl.h ├── WindowSys.cpp ├── WindowSys.h ├── constants.h ├── entity.h └── net.nmlgc.rec98.sh01.metainfo.xml ├── LICENSE ├── MAIN ├── MAIN.CPP └── main_sdl.cpp ├── MapEdit2 ├── GrpUty.cpp ├── GrpUty.h ├── Main.cpp ├── MapEdit.cpp └── MapEdit.h ├── README.md ├── SCLC ├── Calc.cpp ├── Calc.h └── converter.cpp ├── Tupfile.ini ├── Tupfile.linux.lua ├── Tupfile.lua ├── Tupfile.win32.lua ├── art ├── 016_alpha.png ├── 016_box.png ├── 032_alpha.png ├── 032_box.png ├── 032_text.png ├── 048_alpha.png ├── 048_box.png ├── 048_text.png ├── 128_alpha.png ├── 128_box.png ├── 128_text.png └── sh01.ico ├── bin └── bgm │ └── Folder structure.png ├── build_linux.sh ├── build_windows.bat ├── game ├── README.md ├── bgm.cpp ├── bgm.h ├── bgm_track.cpp ├── bgm_track.h ├── cast.h ├── codecs │ ├── flac.cpp │ └── vorbis.cpp ├── coords.h ├── debug.cpp ├── debug.h ├── defer.h ├── endian.h ├── enum_array.h ├── enum_flags.h ├── format_bmp.cpp ├── format_bmp.h ├── frame.h ├── graphics.cpp ├── graphics.h ├── hash.h ├── input.cpp ├── input.h ├── midi.cpp ├── midi.h ├── narrow.h ├── pcm.h ├── pixelformat.h ├── snd.cpp ├── snd.h ├── string_format.h ├── surface.h ├── text.h ├── text_packed.cpp ├── text_packed.h ├── ut_math.cpp ├── ut_math.h └── volume.h ├── install_linux.sh ├── libs ├── 9xcompat.lua ├── BLAKE3.lua ├── BLAKE3.sparse-checkout ├── SDL.lua ├── SDL2.sparse-checkout ├── SDL3.sparse-checkout ├── dr_libs.sparse-checkout ├── libogg.sparse-checkout ├── libvorbis.sparse-checkout ├── libwebp_lossless.lua ├── libwebp_lossless.sparse-checkout ├── miniaudio.sparse-checkout └── xiph.lua ├── obj └── dinput.lib ├── platform ├── README.md ├── buffer.h ├── c │ ├── README.md │ ├── buffer.h │ ├── file.cpp │ ├── thread.h │ ├── time.cpp │ └── unicode.h ├── file.h ├── graphics_backend.h ├── input.h ├── midi_backend.h ├── miniaudio │ ├── flags.h │ ├── miniaudio.c │ └── snd_miniaudio.cpp ├── pangocairo │ ├── text_pangocairo.cpp │ └── text_pangocairo.h ├── path.h ├── sdl │ ├── graphics_sdl.cpp │ ├── graphics_sdl.h │ ├── input_sdl.cpp │ ├── log_sdl.cpp │ ├── log_sdl.h │ ├── path_sdl.cpp │ ├── sdl2_wrap.h │ ├── thread_sdl.cpp │ ├── thread_sdl.h │ ├── urlopen_sdl.cpp │ ├── window_sdl.cpp │ └── window_sdl.h ├── snd_backend.h ├── text_backend.h ├── thread.h ├── time.h ├── unicode.h ├── urlopen.h ├── window_backend.h ├── windows │ ├── file.cpp │ ├── midi_backend_winmm.cpp │ ├── surface_gdi.cpp │ ├── surface_gdi.h │ ├── text_gdi.cpp │ ├── text_gdi.h │ ├── time.cpp │ ├── unicode.h │ └── utf.h └── windows_vintage │ ├── D2_Polygon.CPP │ ├── DD_CLIP2D.CPP │ ├── DD_CLIP2D.H │ ├── DD_GRP2D.CPP │ ├── DD_GRP2D.H │ ├── DD_GRP3D.CPP │ ├── DD_GRP3D.H │ ├── DD_UTY.CPP │ ├── DD_UTY.H │ ├── DI_UTY.CPP │ ├── DS_UTY.CPP │ ├── README.md │ ├── path_vintage.cpp │ └── window_vintage.cpp ├── strings └── title.h ├── submodules_check.sh ├── unused ├── D3_TEX.CPP ├── D3_TEX.H ├── DD_GRP2D.CPP ├── DD_GRP2D.H ├── DD_GRP3D.CPP ├── DD_UTY.CPP ├── DD_UTY.H ├── DX_TYPE.H ├── EFFECT.CPP ├── EFFECT.H ├── EFFECT3D.CPP ├── EFFECT3D.H ├── ENDING.CPP ├── ENEMY.CPP ├── FONTUTY.CPP ├── FONTUTY.H ├── GAMEMAIN.CPP ├── GIAN.H ├── LASER.CPP ├── LOADER.CPP ├── MAID.CPP ├── MAID.H ├── PBGMIDI.CPP ├── PBGMIDI.H ├── PaletteEX.cpp ├── PaletteEx.h ├── SCORE.CPP └── debug.cpp └── version_from_git.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .tup/ 2 | .vscode/settings.json 3 | bin/ 4 | obj/ 5 | tup.config 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libs/SDL2"] 2 | path = libs/SDL2 3 | url = https://github.com/nmlgc/SDL 4 | branch = SDL2_win9x 5 | shallow = true 6 | [submodule "libs/SDL3"] 7 | path = libs/SDL3 8 | url = https://github.com/nmlgc/SDL 9 | shallow = true 10 | [submodule "libs/miniaudio"] 11 | path = libs/miniaudio 12 | url = https://github.com/mackron/miniaudio 13 | branch = dev 14 | shallow = true 15 | [submodule "libs/tupblocks"] 16 | path = libs/tupblocks 17 | url = https://github.com/nmlgc/tupblocks 18 | shallow = true 19 | [submodule "libs/BLAKE3"] 20 | path = libs/BLAKE3 21 | url = https://github.com/BLAKE3-team/BLAKE3 22 | shallow = true 23 | [submodule "libs/dr_libs"] 24 | path = libs/dr_libs 25 | url = https://github.com/mackron/dr_libs 26 | shallow = true 27 | [submodule "libs/libogg"] 28 | path = libs/libogg 29 | url = https://github.com/xiph/ogg 30 | shallow = true 31 | [submodule "libs/libvorbis"] 32 | path = libs/libvorbis 33 | url = https://github.com/xiph/vorbis 34 | shallow = true 35 | [submodule "libs/libwebp_lossless"] 36 | path = libs/libwebp_lossless 37 | url = https://github.com/nmlgc/libwebp_lossless 38 | shallow = true 39 | [submodule "libs/9xcompat"] 40 | path = libs/9xcompat 41 | url = https://github.com/nmlgc/9xcompat 42 | shallow = true 43 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "MSVC 2022, 32-bit", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "cppStandard": "c++23", 9 | "intelliSenseMode": "windows-msvc-x86", 10 | "defines": [ 11 | "WIN32" 12 | ], 13 | "compilerArgs": [ 14 | "/reference", "std=${workspaceFolder}\\obj\\stdd.ifc", 15 | "/reference", "std.compat=${workspaceFolder}\\obj\\std.compatd.ifc" 16 | ] 17 | } 18 | ], 19 | "version": 4 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug", 9 | "type": "cppvsdbg", 10 | "request": "launch", 11 | "preLaunchTask": "Build regular binary (Debug)", 12 | "program": "${workspaceFolder}/bin/GIAN07d.exe", 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/bin/", 15 | "console": "internalConsole" 16 | }, 17 | { 18 | "name": "Release", 19 | "type": "cppvsdbg", 20 | "request": "launch", 21 | "preLaunchTask": "Build regular binary (Release)", 22 | "program": "${workspaceFolder}/bin/GIAN07.exe", 23 | "stopAtEntry": false, 24 | "cwd": "${workspaceFolder}/bin/", 25 | "console": "internalConsole" 26 | }, 27 | { 28 | "name": "Attach", 29 | "type": "cppvsdbg", 30 | "request": "attach", 31 | "processId": "${command:pickProcess}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build (everything)", 8 | "type": "shell", 9 | "command": "build_windows.bat", 10 | "group": "build", 11 | "problemMatcher": "$msCompile", 12 | "options": { 13 | // CMD most likely starts up much faster than PowerShell. 14 | "shell": { 15 | "executable": "cmd", 16 | "args": ["/d", "/c"] 17 | } 18 | } 19 | }, 20 | { 21 | "label": "Build regular binary (Debug)", 22 | "type": "shell", 23 | "command": "build_windows.bat bin/GIAN07d.exe", 24 | "group": "build", 25 | "problemMatcher": "$msCompile", 26 | "options": { 27 | "shell": { 28 | "executable": "cmd", 29 | "args": ["/d", "/c"] 30 | } 31 | } 32 | }, 33 | { 34 | "label": "Build regular binary (Release)", 35 | "type": "shell", 36 | "command": "build_windows.bat bin/GIAN07.exe", 37 | "group": "build", 38 | "problemMatcher": "$msCompile", 39 | "options": { 40 | "shell": { 41 | "executable": "cmd", 42 | "args": ["/d", "/c"] 43 | } 44 | } 45 | }, 46 | { 47 | "label": "Build Windows 98 binary (Debug)", 48 | "type": "shell", 49 | "command": "build_windows.bat bin/GIAN07_win98d.exe", 50 | "group": "build", 51 | "problemMatcher": "$msCompile", 52 | "options": { 53 | "shell": { 54 | "executable": "cmd", 55 | "args": ["/d", "/c"] 56 | } 57 | } 58 | }, 59 | { 60 | "label": "Build Windows 98 binary (Release)", 61 | "type": "shell", 62 | "command": "build_windows.bat bin/GIAN07_win98.exe", 63 | "group": "build", 64 | "problemMatcher": "$msCompile", 65 | "options": { 66 | "shell": { 67 | "executable": "cmd", 68 | "args": ["/d", "/c"] 69 | } 70 | } 71 | } 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /ECLC/Calc.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* CALC.h 式の解析 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_CALC_H 7 | #define PBGWIN_CALC_H "CALC : Version 0.02 : Update 2000/02/03" 8 | #pragma message(PBGWIN_CALC_H) 9 | 10 | #include 11 | 12 | 13 | 14 | ///// [ 定数 ] ///// 15 | #define CALC_DATA_MAX 100 // スタック領域の大きさ 16 | #define OPE1_MINUS '@' // 単項演算子 - に対する記号 17 | 18 | 19 | 20 | ///// [ 関数 ] ///// 21 | extern void CalcSetup(void (*func)(char *s)); // 計算の準備をする 22 | extern int Calc(char *factor); // 引数:空白の無い式 23 | 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /GIAN07/BOMBEFC.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * BombEfc.cpp : 爆発系エフェクト 3 | * 4 | */ 5 | 6 | #include "BOMBEFC.H" 7 | #include "LOADER.H" 8 | #include "game/ut_math.h" 9 | #include "platform/graphics_backend.h" 10 | 11 | 12 | BombEfcCtrl BombEfc[EXBOMB_MAX]; 13 | 14 | // 秘密の関数 // 15 | void _ExBombSTDInit(BombEfcCtrl *p); 16 | void _ExBombSTDDraw(BombEfcCtrl *p); 17 | void _ExBombSTDMove(BombEfcCtrl *p); 18 | 19 | 20 | 21 | // 爆発系エフェクトの初期化 // 22 | void ExBombEfcInit(void) 23 | { 24 | for(auto& it : BombEfc) { 25 | it.bIsUsed = false; 26 | } 27 | } 28 | 29 | 30 | // 爆発系エフェクトをセットする // 31 | void ExBombEfcSet(int x, int y, uint8_t type) 32 | { 33 | auto p = std::ranges::find_if(BombEfc, [](const auto& p) { 34 | return !p.bIsUsed; 35 | }); 36 | 37 | // 空いているオブジェクトが存在しない // 38 | if(p == std::end(BombEfc)) { 39 | return; 40 | } 41 | 42 | // ターゲット捕捉 // 43 | p->x = x; 44 | p->y = y; 45 | p->type = type; 46 | p->count = 0; 47 | 48 | switch(type){ 49 | case EXBOMB_STD: _ExBombSTDInit(p); break; 50 | 51 | default: 52 | return; 53 | } 54 | 55 | // ここまできたら、無事にエフェクトがセットされた事になる // 56 | p->bIsUsed = true; 57 | } 58 | 59 | 60 | // 爆発系エフェクトを描画する 61 | void ExBombEfcDraw(void) 62 | { 63 | for(auto& it : BombEfc) { 64 | if(!it.bIsUsed) { 65 | continue; 66 | } 67 | switch(it.type) { 68 | case EXBOMB_STD: 69 | _ExBombSTDDraw(&it); 70 | break; 71 | 72 | default: 73 | return; 74 | } 75 | } 76 | } 77 | 78 | 79 | // 爆発系エフェクトを動作させる 80 | void ExBombEfcMove(void) 81 | { 82 | for(auto& it : BombEfc) { 83 | if(!it.bIsUsed) { 84 | continue; 85 | } 86 | it.count++; 87 | switch(it.type) { 88 | case EXBOMB_STD: 89 | _ExBombSTDMove(&it); 90 | if(it.count > ((64 * 3) + 32)) { 91 | it.bIsUsed = false; 92 | } 93 | break; 94 | 95 | default: 96 | return; 97 | } 98 | } 99 | } 100 | 101 | 102 | void _ExBombSTDInit(BombEfcCtrl *p) 103 | { 104 | int i, x, y; 105 | SpObj *target; 106 | 107 | x = p->x; 108 | y = p->y; 109 | 110 | target = p->Obj; 111 | for(i=0; ix = x; 113 | target->y = y; 114 | target->d = i % (7*2); 115 | } 116 | } 117 | 118 | 119 | void _ExBombSTDDraw(BombEfcCtrl *p) 120 | { 121 | int x, y, dx; 122 | 123 | // Graphic 48 * 48 // 124 | for(const auto& it : p->Obj) { 125 | const auto *target = ⁢ 126 | if(target->d <= 7*2){ 127 | x = (target->x >> 6) - 24; 128 | y = (target->y >> 6) - 24; 129 | dx = (target->d>>1) * 48; 130 | const PIXEL_LTRB src = PIXEL_LTWH{ dx, 296, 48, 48 }; 131 | GrpSurface_Blit({ x, y }, SURFACE_ID::SYSTEM, src); 132 | } 133 | } 134 | } 135 | 136 | 137 | void _ExBombSTDMove(BombEfcCtrl *p) 138 | { 139 | int j = 0; 140 | int x, y, v, rv; 141 | 142 | x = p->x; 143 | y = p->y; 144 | const auto t = p->count; 145 | v = sinl(t/2-64, 200*64)+(200*64); 146 | 147 | for(auto& it : p->Obj) { 148 | auto *target = ⁢ 149 | if(target->d > 7*2){ 150 | if(t > 64*3) continue; 151 | const uint8_t rd = rnd(); 152 | rv = rnd()%256+128; 153 | target->vx = cosl(rd, rv); 154 | target->vy = sinl(rd, rv); 155 | 156 | const uint8_t d = ((t * 2) + ((j % 8) << 5)); // + (rnd() % 8) - 4; 157 | //v = sinl(degx,64*90)+64*90; 158 | 159 | rv = v - rnd()%(v>>2); 160 | target->x = cosl(d,rv) + x; 161 | target->y = sinl(d,rv) + y; 162 | target->d = 0; 163 | 164 | j++; 165 | } 166 | else{ 167 | target->d = target->d + 1; 168 | target->x += target->vx; 169 | target->y += target->vy; 170 | target->vx -= (target->vx>>3); 171 | target->vy -= (target->vy>>3); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /GIAN07/BOMBEFC.H: -------------------------------------------------------------------------------- 1 | /* 2 | * BombEfc.h : 爆発系エフェクト 3 | * 4 | */ 5 | 6 | #ifndef PBG_BOMBEFC_VERSION 7 | #define PBG_BOMBEFC_VERSION "爆発系エフェクト : Version 0.01 : Update 2000/11/21" 8 | 9 | import std.compat; 10 | 11 | 12 | 13 | /***** [ 定数 ] *****/ 14 | #define EXBOMB_MAX 3 // エフェクトの同時発生数 15 | #define EXBOMB_STD 0 // よくあるタイプの爆発(??) 16 | #define EXBOMB_OBJMAX 200 // エフェクト補助用オブジェクトの個数 17 | 18 | 19 | 20 | /***** [構造体] *****/ 21 | typedef struct tagSpObj { 22 | int x,y; 23 | int vx,vy; 24 | uint8_t d; 25 | } SpObj; 26 | 27 | typedef struct tagBombEfcCtrl { 28 | int x,y; // エフェクトの中心座標 29 | bool bIsUsed; // この構造体は使用中か 30 | uint32_t count; // フレームカウンタ 31 | 32 | SpObj Obj[EXBOMB_OBJMAX]; // エフェクト補助用オブジェクト 33 | 34 | uint8_t type; // エフェクトの種類 35 | } BombEfcCtrl; 36 | 37 | 38 | 39 | /***** [関数プロトタイプ] *****/ 40 | void ExBombEfcInit(void); // 爆発系エフェクトの初期化 41 | void ExBombEfcSet(int x, int y, uint8_t type); // 爆発系エフェクトをセットする 42 | void ExBombEfcDraw(void); // 爆発系エフェクトを描画する 43 | void ExBombEfcMove(void); // 爆発系エフェクトを動作させる 44 | 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /GIAN07/BOSS.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* Boss.h ボスの処理(中ボス含む) */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_BOSS_H 7 | #define PBGWIN_BOSS_H "BOSS : Version 0.01 : Update 2000/02/27" 8 | //#pragma message(PBGWIN_BOSS_H) 9 | 10 | #include "ENEMY.H" 11 | 12 | 13 | ///// [構造体] ///// 14 | 15 | // 特殊当たり判定 // 16 | typedef struct tagEXHITCHK{ 17 | uint8_t flags[60][60]; 18 | } EXHITCHK; 19 | 20 | // ボスデータ // 21 | typedef struct tagBOSS_DATA{ 22 | ENEMY_DATA Edat; // 標準の敵データ(実体であることに注意) 23 | EXHITCHK *Hit; // 特殊当たり判定(NULL なら使用しない) 24 | 25 | void(*ExMove)(tagBOSS_DATA *); // 特殊移動用関数 26 | 27 | uint32_t ExCount; // ある状態におけるカウンタ(推移時にゼロ初期化) 28 | uint8_t ExState; // 特殊状態 29 | uint8_t IsUsed; // このデータは使用されているか(非ゼロなら使用されている) 30 | } BOSS_DATA; 31 | 32 | 33 | 34 | ///// [ 関数 ] ///// 35 | void BossDataInit(void); // ボスデータ配列を初期化する(中断、ステージクリア時に使用) 36 | void BossSet(int x, int y, uint32_t BossID); // ボスをセットする(For SCL) 37 | void BossSetEx(int x, int y, uint32_t BossID); // ボスをセットする(For ECL) 38 | void BossMove(void); // ボスを動かす 39 | void BossDraw(void); // ボスを描画する 40 | 41 | void BossClearCmd(void); // ボス用・敵弾クリアの前処理関数 42 | int BossGetBitLeft(void); // 残りビット数を返す 43 | 44 | void BossKillAll(void); // 現在出現しているボス全てのHPを0にする 45 | bool BossDamage(int x, int y, int damage); // ボスにダメージを与える 46 | bool BossDamage2(int x, int y, int damage); // ボスにダメージを与える(y上方向無限Ver) 47 | void BossDamage3(int x, int y, uint8_t d); // ボスにダメージを与える(ナナメレーザー) 48 | void BossDamage4(int damage); // ボスにダメージを与える(すべての敵) 49 | 50 | void BossHPG_Draw(void); // ボスの体力ゲージを描画する 51 | 52 | uint32_t GetBossHPSum(void); // ボスの体力の総和を求める 53 | 54 | void BossINT(ENEMY_DATA *e, uint8_t IntID); // ボス用割り込み処理 55 | void BossBitAttack(ENEMY_DATA *e, uint32_t AtkID); // ビット攻撃アドレス指定 56 | void BossBitLaser(ENEMY_DATA *e, uint8_t LaserCmd); // ビットにレーザーコマンドセット 57 | void BossBitCommand(ENEMY_DATA *e, uint8_t Cmd, int Param); // ビット命令送信 58 | 59 | 60 | ///// [ 変数 ] ///// 61 | extern uint16_t BossNow; // 現在のボスの数 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /GIAN07/DEMOPLAY.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DemoPlay.h デモプレイ処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DEMOPLAY_H 7 | #define PBGWIN_DEMOPLAY_H "DEMOPLAY : Version 0.02 : Update 2000/04/01" 8 | //#pragma message(PBGWIN_DEMOPLAY_H) 9 | 10 | #include "game/input.h" 11 | 12 | struct CONFIG_DATA; 13 | 14 | 15 | ///// [ 定数 ] ///// 16 | #define DEMOBUF_MAX (60*60*30) // 20分のデータ格納OK 17 | 18 | 19 | 20 | ///// Replay-specific config option subset ///// 21 | // The original code simply reused CONFIG_DATA, which we can't do in this fork 22 | // due to the additional fields we add to the structure. 23 | struct DEMOPLAY_CONFIG_DATA { 24 | uint8_t GameLevel; 25 | uint8_t PlayerStock; 26 | uint8_t BombStock; 27 | uint8_t Padding1[5] = { 0 }; 28 | uint8_t InputFlags; 29 | uint8_t Padding2[15] = { 0 }; 30 | }; 31 | static_assert(sizeof(DEMOPLAY_CONFIG_DATA) == 24); 32 | 33 | 34 | ///// [構造体] ///// 35 | typedef struct tagDEMOPLAY_INFO{ 36 | uint32_t RndSeed; // 乱数のたね 37 | uint32_t FrameCount; // Not data size! Including the terminating ESC. 38 | DEMOPLAY_CONFIG_DATA CfgDat; // コンフィグの情報(Load時に一部を参照する) 39 | uint8_t Exp; // 初期パワーアップ 40 | uint8_t Weapon; // 初期装備 41 | } DEMOPLAY_INFO; 42 | 43 | 44 | ///// [ 関数 ] ///// 45 | void DemoplayInit(void); // デモプレイデータの準備 46 | 47 | // デモプレイデータを保存する 48 | // Returns `true` if the replay is over and should be saved via either 49 | // DemoplaySave() or ReplaySave(). 50 | bool DemoplayRecord(INPUT_BITS key); 51 | 52 | void DemoplaySaveDemo(void); // デモプレイデータをファイルに書き込む 53 | void DemoplaySaveReplay(void); // リプレイデータをファイルに書き込む 54 | 55 | bool DemoplayLoadDemo(int stage); // デモプレイデータをロードする 56 | bool DemoplayLoadReplay(int stage); // リプレイデータをロードする 57 | INPUT_BITS DemoplayMove(void); // Key_Data を返す 58 | void DemoplayCleanup(void); // デモプレイロードの事後処理 59 | 60 | 61 | 62 | ///// [ 変数 ] ///// 63 | extern bool DemoplaySaveEnable; // デモプレイのセーブが動作しているか 64 | extern bool DemoplayLoadEnable; // デモプレイのロードが動作しているか 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /GIAN07/EFFECT3D.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* Effect3D.h 3Dエフェクトの処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_EFFECT3D_H 7 | #define PBGWIN_EFFECT3D_H "EFFECT3D : Ver 0.01 : Update 2000/05/31" 8 | //#pragma message(PBGWIN_EFFECT3D_H) 9 | 10 | 11 | 12 | ///// [更新履歴] ///// 13 | // 2000/05/31 : 開発開始 14 | 15 | 16 | 17 | ///// [ヘッダファイル] ///// 18 | import std.compat; 19 | #include "game/coords.h" 20 | 21 | 22 | 23 | ///// [ 定数 ] ///// 24 | #define STG4ROCK_STDMOVE 0 // 普通のスクロールね 25 | #define STG4ROCK_ACCMOVE1 1 // 加速有りスクロール(1) 26 | #define STG4ROCK_ACCMOVE2 2 // 加速有りスクロール(2) 27 | #define STG4ROCK_3DMOVE 3 // 3D回転 28 | #define STG4ROCK_LEAVE 4 // 一時的に岩を消去する 29 | #define STG4ROCK_END 5 // エフェクト終了 30 | 31 | 32 | 33 | ///// [ 構造体 ] ///// 34 | typedef struct tagPoint3D{ 35 | WORLD_COORD x, y, z; 36 | } Point3D; 37 | 38 | typedef struct tagLineList3D{ 39 | PIXEL_POINT center; /* 頂点の座標の補正用 */ 40 | std::span p; /* 頂点の座標 */ 41 | 42 | uint8_t DegX, DegY, DegZ; /* 各軸に対する回転角 */ 43 | } LineList3D; 44 | 45 | typedef struct tagCircle3D{ 46 | int ox,oy; 47 | int r; 48 | uint8_t deg; 49 | uint8_t n; 50 | } Circle3D; 51 | 52 | typedef struct tagDeg3D{ 53 | int dx; 54 | int dy; 55 | int dz; 56 | } Deg3D; 57 | 58 | typedef struct tagCube3D{ 59 | Point3D p; 60 | Deg3D d; 61 | int l; 62 | } Cube3D; 63 | 64 | typedef struct tagStar2D { 65 | int x,y; 66 | int vy; 67 | } Star2D; 68 | 69 | // 雲管理用構造体 // 70 | typedef struct tagCloud2D { 71 | int x, y; // x64座標 72 | int vy; // 速度のy成分(yしかないけど) 73 | uint8_t type; // 雲の種類 74 | } Cloud2D; 75 | 76 | // 非・汎用2D正方形ワイヤーフレーム // 77 | typedef struct tagWFLine2D { 78 | int ox,oy; // 中心座標 79 | int w; // 正方形の一辺の長さ 80 | uint8_t d; // 正方形の傾き角度 81 | } WFLine2D; 82 | 83 | // 偽ECL羅列管理用構造体 // 84 | typedef struct tagFakeECLString { 85 | int SrcX, SrcY; // 元画像の基準となるX&Y座標 86 | int x,y; // 現在の座標x64 87 | int vx,vy; // 現在の速度成分x64 88 | } FakeECLString; 89 | 90 | // 岩管理用構造体 // 91 | typedef struct tagRock3D { 92 | int x, y, z; // 現在の座標 93 | int vx, vy; // 速度XY成分(2D-平面上) 94 | 95 | uint32_t count; // カウンタ 96 | int v; // 速度 97 | 98 | char a; // 加速度 99 | uint8_t d; // 角度(2D-平面上) 100 | uint8_t GrpID; // グラフィックID 101 | uint8_t State; // 現在の状態 102 | } Rock3D; 103 | 104 | 105 | ///// [ 関数 ] ///// 106 | void InitLineList3D(std::span w); 107 | void DrawLineList3D(std::span w); 108 | 109 | void InitWarning(void); 110 | void DrawWarning(void); 111 | void MoveWarning(uint8_t count); 112 | void MoveWarningR(char count); 113 | 114 | void Init3DCube(void); 115 | void Draw3DCube(void); 116 | void Move3DCube(void); 117 | /* 118 | void InitStg3Cloud(void); // 3面の雲の初期化を行う 119 | void MoveStg3Cloud(void); // 3面の雲を動作させる 120 | void DrawStg3Cloud(void); // 3面の雲を描画する 121 | */ 122 | void InitEffectFakeECL(void); 123 | void MoveEffectFakeECL(void); 124 | void DrawEffectFakeECL(void); 125 | 126 | void InitStg4Rock(void); // ステージ4の背景となる岩の集団 127 | void MoveStg4Rock(void); // 128 | void DrawStg4Rock(void); // 129 | void SendCmdStg4Rock(uint8_t Cmd, uint8_t Param); // コマンド送信 130 | 131 | void InitStg6Raster(); // 6面ラスター初期化 132 | void MoveStg6Raster(); // 6面ラスター動作 133 | void DrawStg6Raster(); // 6面ラスター描画 134 | 135 | void InitStg3Star(); // 3面高速星初期化 136 | void MoveStg3Star(); // 3面高速星動作 137 | void DrawStg3Star(); // 3面高速星描画 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /GIAN07/ENDING.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Ending.h : エンディングの処理 3 | * 4 | */ 5 | 6 | #ifndef PBG_ENDING_VERSION 7 | #define PBG_ENDING_VERSION "エンディングの処理 : Version 0.01 : Update 2000/12/20" 8 | 9 | /* [更新履歴] 10 | * Version 0.01 : 2000/12/20 : 11 | */ 12 | 13 | 14 | 15 | /***** [クラス定義] *****/ 16 | 17 | 18 | 19 | /***** [関数プロトタイプ] *****/ 20 | bool EndingInit(void); // エンディングまわりの初期化 21 | void EndingProc(bool&); // エンディング状態推移用プロシージャ 22 | void EndingDraw(void); // エンディング時の描画処理 23 | 24 | 25 | 26 | /***** [グローバル変数] *****/ 27 | 28 | 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /GIAN07/ENTRY.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic, cross-platform subsystem initialization and cleanup 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "CONFIG.H" 9 | 10 | bool XInit(void); 11 | void XCleanup(void); 12 | 13 | void XGrpTry(const GRAPHICS_PARAMS& prev, GRAPHICS_PARAMS& params); 14 | 15 | // Tries the graphics configuration that results from applying the given 16 | // [patch_func] onto the current configuration, and updates all subsystems 17 | // accordingly. 18 | void XGrpTry(std::invocable auto&& patch_func) { 19 | const auto prev = ConfigDat.GraphicsParams(); 20 | auto params = prev; 21 | patch_func(params); 22 | XGrpTry(prev, params); 23 | } 24 | 25 | void XGrpTryCycleScale(int_fast8_t delta, bool include_max); 26 | void XGrpTryCycleDisp(void); 27 | void XGrpTryCycleScMode(void); 28 | -------------------------------------------------------------------------------- /GIAN07/EXDEF.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* ExDef.h いろんなものの定義とか */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_EXDEF_H 7 | #define PBGWIN_EXDEF_H "EXDEF : Version 0.01 : Update 2000/09/04" 8 | //#pragma message(PBGWIN_EXDEF_H) 9 | 10 | 11 | import std.compat; 12 | 13 | 14 | // 角度付き座標の管理用構造体 // 15 | typedef struct tagDegPoint{ 16 | int x,y; // 座標 17 | uint8_t d; // 角度 18 | } DegPoint; 19 | 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /GIAN07/EnemyExCtrl.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* EnemyExCtrl.h 敵用の特殊処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_ENEMYEXCTRL_H 7 | #define PBGWIN_ENEMYEXCTRL_H "ENEMYEXCTRL : Version 0.01 : Update 2000/02/27" 8 | //#pragma message(PBGWIN_ENEMYEXCTRL_H) 9 | 10 | #include "EXDEF.H" 11 | #include "ENEMY.H" 12 | #include "BOSS.H" 13 | 14 | 15 | ///// [更新履歴] ///// 16 | 17 | // 2000/12/13 : ビット用の関数の動作が安定する(時間を使いすぎね...) 18 | // 2000/12/09 : ビット用の関数を追加する 19 | // 2000/04/06 : 開発を始める 20 | 21 | 22 | 23 | ///// [ 定数 ] ///// 24 | #define SNAKE_MAX 4 // 蛇型の敵の最大数 25 | constexpr auto SNAKEYMOVE_POINTS_PER_ENEMY = 8; 26 | 27 | #define BIT_MAX 6 // ビットの最大数 28 | #define BITCMD_STDMOVE 0x00 // 通常の移動を行う 29 | #define BITCMD_CHGSPD 0x01 // 回転速度を変更する 30 | #define BITCMD_SELECTATK 0x02 // 攻撃コマンドを変更する 31 | #define BITCMD_CHGRADIUS 0x03 // 半径を変更する 32 | #define BITCMD_MOVTARGET 0x04 // 目標(びびっと)に向けてブーメラン移動 33 | #define BITCMD_DISABLE 0xff // ビットを使用していない 34 | 35 | #define BLASERCMD_OPEN 0x00 // レーザーをオープンする 36 | #define BLASERCMD_CLOSE 0x01 // ビットの放っているレーザーをクローズする 37 | #define BLASERCMD_CLOSEL 0x02 // ライン状態に推移させる 38 | 39 | #define BLASERCMD_TYPE_A 0x03 // 一方向・角度固定レーザーを放射 40 | #define BLASERCMD_TYPE_B 0x04 // 両方向角度同期変化レーザーを放射 41 | #define BLASERCMD_TYPE_C 0x05 // 角度同期n芒星レーザー 42 | #define BLASERCMD_DISABLE 0xff // 何も発動していない 43 | 44 | 45 | 46 | 47 | ///// [構造体] ///// 48 | 49 | // 蛇型の敵を管理する構造体 // 50 | template struct SNAKYMOVE_DATA { 51 | // 頂点バッファ(ExDef.h) 52 | DegPoint PointBuffer[Len * SNAKEYMOVE_POINTS_PER_ENEMY]; 53 | 54 | ENEMY_DATA *EnemyPtr[Len]; // 尾となるデータ配列 55 | BOSS_DATA *Parent; // 親(頭となるデータ) 56 | size_t Head; // 頭を格納している地点のポインタ 57 | bool bIsUse; // この構造体を使用しているか 58 | 59 | constexpr static size_t Length() { 60 | return Len; 61 | } 62 | }; 63 | 64 | 65 | typedef struct tagBIT_PARAM { 66 | ENEMY_DATA *pEnemy; // 対象となる敵へのポインタ 67 | 68 | uint32_t BitHP; // ビットの耐久力 69 | uint8_t BitID; // 基準角から何番目(0~)に相当するビットか 70 | uint8_t Angle; // 現在の角度 71 | char Force; // 現在力の加えられている方向 72 | } BIT_PARAM; 73 | 74 | typedef struct tagBIT_DATA { 75 | BIT_PARAM Bit[BIT_MAX]; // ビットデータへのポインタ 76 | BOSS_DATA *Parent; // 親データへのポインタ 77 | 78 | int x, y; // 回転の中心(基本的には、Parent->x, Parent->y) 79 | int v; // 加速度付き移動時の速度 80 | int a; // 加速度付き移動時の加速度 81 | 82 | uint8_t d; // 加速度付き移動時の進行角度 83 | uint8_t NumBits; // 初期ビット数 84 | 85 | //uint16_t DeltaAngle; // ビット間の差分角 86 | 87 | int Length; // ビットの回転半径 88 | int FinalLength; // 最終目標とする回転半径 89 | 90 | char BitSpeed; // ビットの基本回転速度 91 | uint8_t State; // このビット集合の状態 92 | uint8_t LaserState; // レーザーの状態 93 | //uint16_t ForceCount; // 反動の残り時間 94 | 95 | uint16_t BaseAngle; // ビットの回転基本角 96 | 97 | bool bIsLaserEnable; // レーザーが動作中かどうか 98 | } BIT_DATA; 99 | 100 | 101 | 102 | ///// [ 関数 ] ///// 103 | void SnakyInit(void); // 蛇型の敵配列の初期化 104 | void SnakySet(BOSS_DATA *b, int len, uint32_t TailID); // 蛇型の敵をセットする 105 | void SnakyMove(void); // 蛇型の敵の移動処理 106 | void SnakyDelete(const BOSS_DATA *b); // 蛇型の敵を殺す 107 | 108 | void BitInit(void); // ビット配列の初期化 109 | void BitSet(BOSS_DATA *b, uint8_t NumBits, uint32_t BitID); // ビットをセットする 110 | void BitMove(void); // ビットを動作させる 111 | void BitDelete(void); // ビットを消滅させる 112 | void BitLineDraw(void); // ビット間のラインを描画する 113 | void BitSelectAttack(uint32_t BitID); // 攻撃パターンをセットor変更 114 | void BitLaserCommand(uint8_t Command); // レーザー系命令を発行 115 | void BitSendCommand(uint8_t Command, int Param); // ビット命令を送信 116 | int BitGetNum(void); // 現在のビット数を取得する 117 | 118 | 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /GIAN07/FONTUTY.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* FontUty.h フォントの処理いろいろ */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_FONTUTY_H 7 | #define PBGWIN_FONTUTY_H "FONTUTY : Version 0.02 : Update 2000/07/22" 8 | //#pragma message(PBGWIN_FONTUTY_H) 9 | 10 | 11 | 12 | ///// [更新履歴] ///// 13 | 14 | // 2000/07/22 : フォント追加に伴い、プログラムの一部を変更 15 | // 2000/02/19 : フォントに関する処理の開発を始める 16 | 17 | 18 | 19 | #include "game/text.h" 20 | 21 | 22 | 23 | ///// [ 関数 ] ///// 24 | extern void GrpPut16(int x, int y, const char *s); // 16x16 透過フォントで文字列出力(高速) 25 | extern void GrpPut16c2(int x, int y, const char *s); // 上と同じだが、x移動幅が16 26 | extern void GrpPutc(int x, int y, char c); // 16x16 透過フォントで文字出力(クリッピング有) 27 | extern void GrpPut57(int x, int y, const char *s); // 05x07 べた貼りフォント 28 | extern void GrpPut7B(int x, int y, const char *s); // 07x11 音楽室用フォント 29 | extern void GrpPutScore(int x, int y, const char *s); // 得点アイテムのスコアを描画 30 | 31 | extern void GrpPutMidNum(int x, int y, int n); // MIDI 用フォントを描画する 32 | 33 | // 5-pixel variable-width font in [SURFACE_ID::SYSTEM]. Supports A-Z. 34 | // ------------------------------------------------------------------ 35 | 36 | constexpr PIXEL_COORD GrpExtent5(const char c) 37 | { 38 | switch(c) { 39 | if(!((c >= 'A') && (c <= 'Z'))) { 40 | assert(!"Character not supported in 5-pixel system font"); 41 | return 0; 42 | } 43 | case 'I': return 3; break; 44 | case 'M': 45 | case 'T': 46 | case 'V': 47 | case 'W': 48 | case 'Y': return 5; break; 49 | default: return 4; break; 50 | } 51 | } 52 | 53 | constexpr PIXEL_SIZE GrpExtent5(const std::string_view s) 54 | { 55 | PIXEL_SIZE ret = { 0, 5 }; 56 | for(const char c : s) { 57 | ret.w += (GrpExtent5(c) + 1); 58 | } 59 | ret.w = (std::max)(0, (ret.w - 1)); 60 | return ret; 61 | } 62 | 63 | void GrpPut55(WINDOW_POINT topleft, const std::string_view s); 64 | // ------------------------------------------------------------------ 65 | 66 | // グラデーション付きフォントを描画する 67 | PIXEL_SIZE DrawGrdFont( 68 | TEXTRENDER_SESSION& s, 69 | std::span strs, 70 | FONT_ID font, 71 | bool shadow, 72 | uint8_t (*gradient_func)(PIXEL_COORD y) 73 | ); 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /GIAN07/FRAGMENT.H: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************/ 2 | /* FRAGMENT.H 破片処理関数群 */ 3 | /* */ 4 | /*************************************************************************************************/ 5 | 6 | #ifndef PBGWIN_FRAGMETN_H 7 | #define PBGWIN_FRAGMENT_H "FRAGMENT : Ver 0.10 : Update 99/10/31" 8 | //#pragma message(PBGWIN_FRAGMENT_H) 9 | 10 | import std.compat; 11 | 12 | //// 破片定数 //// 13 | #define FRAGMENT_MAX 1000 // 破片の最大数 14 | #define FRG_EVADE 0x00 // かすり(開発中) 15 | #define FRG_SMOKE 0x01 // 煙その1 16 | #define FRG_FATCIRCLE 0x02 // 赤丸... 17 | #define FRG_STAR1 0x03 // お星様1 18 | #define FRG_STAR2 0x04 // お星様2 19 | #define FRG_HIT 0x05 // ショットがヒットした 20 | #define FRG_STAR3 0x06 21 | #define FRG_HEART 0x07 // ハート型 22 | 23 | #define FRG_ESCAPE 0x10 // 指定座標から逃げる 24 | #define FRG_APPROACH 0x20 // 指定座標に近づく 25 | 26 | 27 | //// 破片構造体 //// 28 | typedef struct{ 29 | int x,y; // 現在の座標 30 | int vx,vy; // 速度成分 (x64) 31 | uint8_t count; // フレームカウンタ(0の時は使用していないとする) 32 | uint8_t cmd; // どんな破片? 33 | } FRAGMENT_DATA; 34 | 35 | 36 | //// 破片用変数 //// 37 | extern FRAGMENT_DATA Fragment[FRAGMENT_MAX]; 38 | 39 | 40 | //// 破片関数 //// 41 | void fragment_set(int x, int y, uint8_t cmd); 42 | void fragment_move(void); 43 | void fragment_draw(void); 44 | void fragment_setup(void); 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /GIAN07/GAMEMAIN.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* GameMain.h ウィンドウシステム切り替えなどの処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_GAMEMAIN_H 7 | #define PBGWIN_GAMEMAIN_H "GAMEMAIN : Version 0.01 : Update 2000/02/23" 8 | //#pragma message(PBGWIN_GAMEMAIN_H) 9 | 10 | 11 | 12 | ///// [更新履歴] ///// 13 | 14 | // 2000/02/03 : 製作開始 15 | 16 | 17 | 18 | ///// [Include Files] ///// 19 | #include "ENDING.H" 20 | 21 | 22 | 23 | ///// [ 定数 ] ///// 24 | ///// [マクロ] ///// 25 | ///// [構造体] ///// 26 | 27 | ///// [グローバル変数] ///// 28 | extern bool IsDemoplay; 29 | 30 | 31 | 32 | ///// [関数] ///// 33 | // ゲーム進行用関数ポインタ(WinMainからコールする) 34 | extern void(*GameMain)(bool& quit); 35 | 36 | bool WeaponSelectInit(bool ExStg); 37 | bool GameInit(void(*NextProc)(bool& quit)); // ゲームの初期化をする 38 | extern void GameRestart(void); // ゲームを再開する(ESC 抜けから) 39 | extern bool GameExit(bool bNeedChgMusic = true); // ゲームから抜ける 40 | extern void GameOverInit(void); // ゲームオーバーの前処理 41 | extern void GameContinue(void); // コンティニューを行う場合 42 | 43 | extern bool GameReplayInit(int Stage); // リプレイ用の初期化を行う 44 | 45 | extern bool SProjectInit(void); // 西方Project表示の初期化 46 | 47 | extern bool GameExstgInit(void); // エキストラステージを始める 48 | 49 | extern bool NameRegistInit(bool bNeedChgMusic); // お名前入力の初期化 50 | extern bool ScoreNameInit(void); // お名前表示画面 51 | 52 | extern bool GameNextStage(void); // 次のステージに移行する 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /GIAN07/GEOMETRY.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Backend-independent geometry rendering functions 3 | * 4 | */ 5 | 6 | #include "GEOMETRY.H" 7 | #include "game/ut_math.h" 8 | 9 | namespace Geometry { 10 | 11 | constexpr uint8_t CIRCLE_STEP = (0x100 / (CIRCLE_POINTS - 1)); 12 | 13 | void ApproximateCircle( 14 | std::span ret, 15 | WINDOW_POINT center, 16 | PIXEL_COORD radius 17 | ) 18 | { 19 | auto i = 0; 20 | for(auto& v : ret) { 21 | const uint8_t angle = (i++ * CIRCLE_STEP); 22 | v.x = (center.x + cosl(angle, radius)); 23 | v.y = (center.y + sinl(angle, radius)); 24 | } 25 | } 26 | 27 | void ApproximateFatCircle( 28 | std::span ret, 29 | WINDOW_POINT center, 30 | PIXEL_COORD r, 31 | PIXEL_COORD w 32 | ) 33 | { 34 | auto v = ret.begin(); 35 | for(const auto i : std::views::iota(0u, CIRCLE_POINTS)) { 36 | const uint8_t angle = (i * CIRCLE_STEP); 37 | const auto [lx, ly] = std::pair(cosl(angle, r), sinl(angle, r)); 38 | const auto [wx, wy] = std::pair(cosl(angle, w), sinl(angle, w)); 39 | v[0] = { 40 | static_cast(center.x + lx - wx), 41 | static_cast(center.y + ly - wy), 42 | }; 43 | v[1] = { 44 | static_cast(center.x + lx + wx), 45 | static_cast(center.y + ly + wy), 46 | }; 47 | v += 2; 48 | } 49 | } 50 | 51 | } // namespace Geometry 52 | 53 | void GeomCircle(WINDOW_POINT center, PIXEL_COORD radius) 54 | { 55 | if(auto *gp = GrpGeom_Poly()) { 56 | Geometry::Circle_Approximated(*gp, center, radius); 57 | } else if(auto* gf = GrpGeom_FB()) { 58 | Geometry::Circle_Exact(*gf, center, radius); 59 | } 60 | } 61 | 62 | void GeomCircleF(WINDOW_POINT center, PIXEL_COORD radius) 63 | { 64 | if(auto *gp = GrpGeom_Poly()) { 65 | Geometry::CircleF_Approximated(*gp, center, radius, false); 66 | } else if(auto* gf = GrpGeom_FB()) { 67 | Geometry::CircleF_Exact(*gf, center, radius); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /GIAN07/GIAN.CPP: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* GIAN.cpp ゲーム全体の管理 */ 3 | /* */ 4 | /* */ 5 | 6 | #include "GIAN.H" 7 | #include "FONTUTY.H" 8 | #include "LEVEL.H" 9 | #include "CONFIG.H" 10 | #include "platform/time.h" 11 | 12 | 13 | ///// [グローバル変数] ///// 14 | //HIGH_SCORE *HighScore; 15 | //char ScoreTable[8][80]; 16 | uint32_t GameCount; 17 | uint8_t GameStage; 18 | uint8_t GameLevel; 19 | 20 | 21 | 22 | ///// [ 関数(非公開) ] ///// 23 | extern void StdStatusOutput(void) 24 | { 25 | const WINDOW_COORD column2_left = (GRP_RES.w - 128); 26 | 27 | static uint32_t prev; 28 | static uint32_t fps, count; 29 | //extern InputConfig IConfig; 30 | const char *const DItem[4] = { "Easy", "Norm", "Hard", "Luna" }; 31 | char buf[100]; 32 | 33 | #ifdef PBG_DEBUG 34 | if(!DebugDat.MsgDisplay) return; 35 | #endif 36 | 37 | const auto now = Time_SteadyTicksMS(); 38 | if((now - prev) <= 1000) { 39 | count++; 40 | } else { 41 | fps = count; 42 | count = 0; 43 | prev = now; 44 | } 45 | 46 | sprintf(buf, "%03u FPS", fps); 47 | GrpPut16(0,0,buf); 48 | 49 | #ifdef PBG_DEBUG 50 | #ifdef SUPPORT_GRP_BITDEPTH 51 | sprintf(buf, "%2dBppMode", ConfigDat.BitDepth.v.value()); 52 | GrpPut16(0, 32, buf); 53 | #endif 54 | //sprintf(buf,"%s",DItem[ConfigDat.GameLevel.v]); 55 | //GrpPut16(0,50,buf); 56 | 57 | sprintf(buf,"%s",DItem[PlayRank.GameLevel]); 58 | GrpPut16(0,50,buf); 59 | sprintf(buf,"%s",DItem[GameLevel]); 60 | GrpPut16(0,68,buf); 61 | sprintf(buf,"Pr %d",PlayRank.Rank); 62 | GrpPut16(0,86,buf); 63 | 64 | 65 | sprintf(buf,"Enemy %3d",EnemyNow); 66 | GrpPut16(0,96+40,buf); 67 | 68 | sprintf(buf,"Tama1 %3d",Tama1Now); 69 | GrpPut16(0,128+40,buf); 70 | sprintf(buf,"Tama2 %3d",Tama2Now); 71 | GrpPut16(0,148+40,buf); 72 | sprintf(buf,"Laser %3d",LaserNow); 73 | GrpPut16(0,176+40,buf); 74 | sprintf(buf,"HLaser %2d",HLaserNow); 75 | GrpPut16(0,196+40,buf); 76 | 77 | sprintf(buf,"MTama %3d",MaidTamaNow); 78 | GrpPut16(0,224+40,buf); 79 | 80 | sprintf(buf,"Item %3d",ItemNow); 81 | GrpPut16(0,252+40,buf); 82 | 83 | sprintf(buf,"Pow %3d",Viv.exp); 84 | GrpPut16(0,290+40,buf); 85 | 86 | sprintf(buf,"SSPD %3d",ScrollInfo.ScrollSpeed); 87 | GrpPut16(0,320+40,buf); 88 | 89 | GrpPut16(0,440,"Gian07"); 90 | GrpPut16(0,460,"DebugMode"); 91 | 92 | GrpPut16(column2_left, 100, "SCL Count"); 93 | sprintf(buf," %5d",GameCount); 94 | GrpPut16(column2_left, 120, buf); 95 | #else 96 | // GrpPut16(0,440,"G07"); 97 | // GrpPut16(0,460,"12/5 Ver"); 98 | #endif 99 | 100 | const auto tm = Time_NowLocal(); 101 | 102 | sprintf(buf, "%02u/%02u/%02u", tm.month, tm.day, (tm.year % 100u)); 103 | GrpPut16(column2_left, 0, "Date"); 104 | GrpPut16(column2_left, 20, buf); 105 | 106 | sprintf(buf, "%02u:%02u:%02u", tm.hour, tm.minute, tm.second); 107 | GrpPut16(column2_left, 50, "Time"); 108 | GrpPut16(column2_left, 70, buf); 109 | 110 | #ifndef PBG_DEBUG // pbg quirk 111 | sprintf(buf,"Bomb %d",Viv.bomb); 112 | GrpPut16(column2_left, 400, buf); 113 | #endif 114 | 115 | sprintf(buf,"Left %d",Viv.left); 116 | GrpPut16(column2_left, 440, buf); 117 | sprintf(buf,"Credit %d",Viv.credit); // -1 に注意だ!! 118 | GrpPut16(column2_left, 460, buf); 119 | } 120 | -------------------------------------------------------------------------------- /GIAN07/GIAN07.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Version=1.5 4 | Name=Shuusou Gyoku 5 | Name[ja]=秋霜玉 6 | Name[zh]=秋霜玉 7 | GenericName=Seihou 1 8 | GenericName[ja]=西方Project第1作 9 | GenericName[zh]=西方系列第一作 10 | Exec=GIAN07 11 | Icon= 12 | Categories=Game;Shooter; 13 | 14 | # Allow these romaji keywords in Japanese and Chinese locales 15 | Keywords=seihou;shuusou;gyoku; 16 | -------------------------------------------------------------------------------- /GIAN07/GIAN07.rc: -------------------------------------------------------------------------------- 1 | 0 ICON "art\sh01.ico" 2 | -------------------------------------------------------------------------------- /GIAN07/HOMINGL.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* HomingL.h 長いレーザーの処理 */ 3 | /* */ 4 | /* */ 5 | 6 | 7 | #ifndef PBGWIN_HOMINGL_H 8 | #define PBGWIN_HOMINGL_H "HOMINGL : Ver 0.01 : Updata 2000/09/04" 9 | //#pragma message(PBGWIN_HOMINGL_H) 10 | 11 | #include "EXDEF.H" 12 | 13 | 14 | 15 | ///// [ 定数 ] ///// 16 | #define HLASER_MAX 162 17 | #define HLASER_LEN 7 // 描画枚数.. 18 | #define HLASER_SECTION 4 // 読み込み幅 19 | 20 | 21 | #define HL_NONE 0 // ただ進むだけ 22 | #define HL_TYPE1 1 // その1 23 | 24 | #define HLS_NORM 0x00 // ホーミングレーザー通常 25 | #define HLS_CLEAR 0x01 // ホーミングレーザー消去中 26 | #define HLS_DEAD 0xff // ホーミングレーザー削除要請 27 | 28 | 29 | 30 | ///// [構造体] ///// 31 | 32 | // ホーミングレーザー // 33 | typedef struct tagHLaserData { 34 | int Current; // 現在の先頭 35 | int v; // 速度 36 | int a; // 加速度 37 | 38 | uint32_t Count; // フレームカウンタ 39 | 40 | uint8_t Type; // 種類(加速&ホーミングタイプ) 41 | uint8_t State; // 状態 42 | uint8_t c; // 色 43 | uint8_t Left; // 残りホーミング回数 44 | 45 | struct tagHLaserData *Next; // 次のレーザーへのポインタ 46 | DegPoint p[HLASER_LEN*HLASER_SECTION]; // 頂点キュー(ExDef.h) 47 | } HLaserData; 48 | 49 | // ホーミングレーザーセット情報 // 50 | typedef struct tagHLaserInfo { 51 | int x,y; // 中心座標 52 | 53 | uint8_t d; // 角度 54 | uint8_t dw; // 角度の開き 55 | uint8_t n; // 本数 56 | 57 | uint8_t c; // 色 58 | uint8_t type; // 種類 59 | } HLaserInfo; 60 | 61 | 62 | 63 | ///// [グローバル変数] ///// 64 | extern uint16_t HLaserNow; // ホーミングレーザーの本数 65 | extern HLaserInfo HLaserCmd; // ホーミングレーザーセット用データ 66 | 67 | 68 | ///// [関数プロトタイプ] ///// 69 | void HLaserInit(void); // ホーミングレーザーの初期化を行う 70 | void HLaserSet(const HLaserInfo *hinfo); // ホーミングレーザーをセットする 71 | void HLaserMove(void); // ホーミングレーザーを動作させる 72 | void HLaserDraw(void); // ホーミングレーザーを描画する 73 | void HLaserClear(void); // ホーミングレーザーに消去エフェクトをセット 74 | 75 | 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /GIAN07/ITEM.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* Item.h アイテムの処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_ITEM_H 7 | #define PBGWIN_ITEM_H "ITEM : Version 0.01 : Update 2000/03/11" 8 | //#pragma message(PBGWIN_ITEM_H) 9 | 10 | import std.compat; 11 | 12 | 13 | ///// [ 定数 ] ///// 14 | 15 | // 最大数 // 16 | #define ITEM_MAX 100 17 | 18 | // 種類もしくは状態 // 19 | #define ITEM_DELETE 0x00 // 消去要請 20 | #define ITEM_SCORE 0x01 // 得点アイテム 21 | #define ITEM_EXTEND 0x02 // 残りメイド数UP 22 | #define ITEM_BOMB 0x03 // ボム 23 | 24 | // その他 // 25 | #define ITEM_GRAVITY 3 // アイテムに対するy加速度 26 | #define ITEM_HITX (( 8+8)*64) // アイテムのX当たり判定 27 | #define ITEM_HITY ((16+8)*64) // アイテムのY当たり判定 28 | 29 | 30 | ///// [構造体] ///// 31 | typedef struct tagITEM_DATA{ 32 | int x,y; 33 | int vx,vy; 34 | uint32_t count; 35 | uint8_t type; 36 | } ITEM_DATA; 37 | 38 | 39 | 40 | ///// [ 関数 ] ///// 41 | void ItemSet(int x, int y, uint8_t type); // アイテムを発生させる 42 | void ItemMove(void); // アイテムを動かす 43 | void ItemDraw(void); // アイテムを描画する 44 | 45 | void ItemIndSet(void); // アイテム配列の初期化 46 | 47 | 48 | 49 | ///// [ 変数 ] ///// 50 | extern std::array Item; 51 | extern std::array ItemInd; 52 | extern uint16_t ItemNow; 53 | 54 | 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /GIAN07/LASER.H: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************/ 2 | /* LASER.H レーザーに関する処理(反射,ショート) */ 3 | /* */ 4 | /*************************************************************************************************/ 5 | 6 | #ifndef PBGWIN_LASER_H 7 | #define PBGWIN_LASER_H "LASEER : Ver 0.51 : Update 2000/02/17" 8 | //#pragma message(PBGWIN_LASER_H) 9 | 10 | import std.compat; 11 | #include "game/coords.h" 12 | 13 | ///// [更新履歴] ///// 14 | 15 | // 2000/02/17 : 新しいシステムに移行開始。無限遠レーザーと完全に分離 16 | 17 | /*-> ここからはちょっと古いよ(1999..) 18 | * (4/3) 10:36 開発開始 19 | * (4/6) 12:00 ついにポリゴン&クリッピング関数が完成。描画はいつ出来るのか? 20 | * (4/7) 12:02 全てのレーザーを同じ構造体で扱う事にした 21 | * (4/8) 7:23 無限遠レーザーの制作 22 | * (4/9) 2:01 反射レーザーを一応打ち込み終わる 23 | * (4/9) 2:59 反射レーザー完成 24 | * (4/11) 14:05 ショート&反射レーザーの当たり判定完成 25 | * (4/11) 15:17 リフレクターのヒットチェックを強化(バグは消えたが遅くなった) 26 | * 27 | * (9/23) 16:18 ライン描画、ECL対応などが完了 28 | */ 29 | 30 | 31 | ////レーザー定数//// 32 | #define LASER_MAX 1000 // レーザーの最大発生本数 33 | 34 | 35 | ////レーザー発動コマンド構造体//// 36 | typedef struct{ 37 | int x,y; // 始点の座標 38 | int v; // レーザーの初速度 39 | 40 | int w; // レーザーの太さ (x64座標を使用する) 41 | int l; // レーザーの長さ最終値 (x64座標を使用する) 42 | int l2; // レーザーの発射位置補正(x64...) 43 | 44 | uint8_t d; // 発射角 45 | uint8_t dw; // 発射幅 46 | 47 | uint8_t n; // レーザーの本数 48 | uint8_t c; // レーザーの色 49 | 50 | char a; // 加速度(つかうのかな???) 51 | uint8_t cmd; // レーザー発動コマンド(ほとんど弾と同じかも) 52 | uint8_t type; // ショート、無限遠など 53 | uint8_t notr; // 反射しないリフレクターの番号 54 | } LASER_CMD; 55 | 56 | 57 | /* 58 | ////反射物(鏡?) 構造体//// 59 | typedef struct{ 60 | int x,y; // 反射物の中心座標 61 | 62 | uint32_t l; // リフレクターの長さ(中心から先端まで,つまり全体でl*2) 63 | uint8_t d; // 反射物の角度(0 <= d < 128) 64 | } REFLECTOR; 65 | */ 66 | 67 | ////レーザー関数//// 68 | extern void laser_set(void); // レーザーをセットする(難易度変更"有り") 69 | extern void laser_setEX(void); // レーザーをセットする(難易度変更"無し") 70 | extern int llaser_set(uint16_t *ind); // 無限遠レーザーをセットする(セットできた数を返すのだ) 71 | extern void laser_move(void); // レーザーを動かす 72 | extern void laser_draw(void); // レーザーを描画する 73 | extern void laser_clear(void); // レーザー全てに消去エフェクトをかける 74 | extern void laserind_set(void); // レーザー順序用配列の初期化 75 | 76 | 77 | ////レーザーの各種変数たち//// 78 | extern LASER_CMD LaserCmd; // 標準レーザーコマンド構造体 79 | extern uint16_t LaserNow; // レーザーの本数 80 | //extern REFLECTOR Reflector[RT_MAX]; // 反射物構造体 81 | //extern uint16_t ReflectorNow; // 反射物の個数 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /GIAN07/LENS.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* Lens.h レンズエフェクト */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_LENS_H 7 | #define PBGWIN_LENS_H "LENS_EFC : Version 0.01 : Update 2000/09/18" 8 | #pragma message(PBGWIN_LENS_H) 9 | 10 | import std.compat; 11 | #include "game/coords.h" 12 | 13 | 14 | ///// [構造体] ///// 15 | 16 | // レンズデータ定義用構造体 // 17 | struct LensInfo { 18 | uint16_t r; // レンズの半径 19 | uint16_t Height; // レンズの直径 20 | std::unique_ptr Data; // レンズ置換テーブル 21 | 22 | // Per-frame capture of the original back-buffer pixels under the lens. 23 | std::unique_ptr FOV; 24 | 25 | // GrpLock() 系関数 : レンズボールを描画する // 26 | void Draw(WINDOW_POINT center); 27 | }; 28 | 29 | 30 | 31 | ///// [ 関数 ] ///// 32 | 33 | // 半径:r 出っ張り:m のレンズを作成 // 34 | std::optional GrpCreateLensBall(uint16_t r, uint16_t m); 35 | 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /GIAN07/LEVEL.H: -------------------------------------------------------------------------------- 1 | /* 2 | * 難易度 & オプション設定 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #define GAME_EASY 0 // 難易度:Easy 9 | #define GAME_NORMAL 1 // 難易度:Normal 10 | #define GAME_HARD 2 // 難易度:Hard 11 | #define GAME_LUNATIC 3 // 難易度:Lunatic 12 | #define GAME_EXTRA 4 // Extra時... 13 | 14 | // Extra Stage starts at Hard. 15 | static constexpr auto EXTRA_LEVEL = GAME_HARD; 16 | static constexpr auto EXTRA_LIVES = 2; 17 | -------------------------------------------------------------------------------- /GIAN07/LLASER.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* LLaser.h 長いレーザーの処理 */ 3 | /* */ 4 | /* */ 5 | 6 | 7 | #ifndef PBGWIN_LLASER_H 8 | #define PBGWIN_LLASER_H "LLASER : Ver 0.03 : Updata 2000/02/07" 9 | //#pragma message(PBGWIN_LLASER_H) 10 | 11 | // 更新履歴 // 12 | // 2000/05/29 : 8ビットモード描画関連のBugFix 13 | // 2000/03/22 : レーザー関数のIDの意味がレーザー配列のIDからその敵が 14 | // : 発射しているレーザーの何番目か、に変更された 15 | 16 | 17 | #include "ENEMY.H" 18 | #include "platform/graphics_backend.h" 19 | 20 | 21 | 22 | //// レーザー用定数2 //// 23 | #define LLASER_MAX 20 24 | #define LLASER_EVADE 1 // レーザーのかすり値 25 | 26 | 27 | //// レーザーの種類定数2 28 | #define LLS_LONG 0x00 29 | #define LLS_LONGY 0x01 30 | #define LLS_SETDEG 0x02 31 | #define LLS_LONGZ 0x03 // 自機セット 32 | 33 | 34 | //// レーザーフラグ2 //// 35 | #define LLF_DISABLE 0x00 // レーザーが使用されていない 36 | #define LLF_NORM 0x01 // レーザーが完全に開ききった 37 | #define LLF_OPEN 0x02 // レーザを開いている 38 | #define LLF_CLOSE 0x04 // レーザーを閉じている 39 | #define LLF_CLOSEL 0x08 // レーザーをライン状態にする 40 | #define LLF_LINE 0x10 // レーザーはライン状態 41 | 42 | 43 | 44 | //// レーザー発動コマンド構造体2 //// 45 | typedef struct{ 46 | ENEMY_DATA *e; // 敵データへのポインタ 47 | 48 | int dx,dy; // レーザーの発射座標ずらし値 49 | int v; // レーザーの速度 50 | 51 | int w; // レーザーの太さ最終値 52 | 53 | uint8_t d; // レーザー発射角 54 | 55 | uint8_t c; // レーザーの色 56 | uint8_t type; // レーザーの種類 57 | } LLASER_CMD; 58 | 59 | 60 | //// レーザー用構造体2 //// 61 | typedef struct{ 62 | ENEMY_DATA *e; // 敵データへのポインタ(ここら辺でボスでも雑魚でも発射できるように) 63 | 64 | int x,y; // 現在の表示座標 65 | int dx,dy; // 敵データからのずらし値(x64) 66 | int lx,ly; // レーザー円の中心座標までのベクトル(Grp) 67 | int infx,infy; // 仮の無限遠へのベクトル(Grp) 68 | int wx,wy; // レーザー幅(Grp) 69 | 70 | int w,wmax; // 幅、最大幅(x64) 71 | int v; 72 | 73 | uint32_t count; // フレームカウンタ 74 | 75 | VERTEX_XY p[4]; // 座標保持用のポインタ(Grp) 76 | 77 | uint8_t d; // レーザーの発射角 78 | uint8_t c; // レーザーの色 79 | 80 | uint8_t flag; // レーザーの状態 81 | uint8_t type; // レーザーの種類 82 | uint8_t EnemyID; // 敵から見た番号 83 | } LLASER_DATA; 84 | 85 | 86 | 87 | //// レーザー関数2 //// 88 | bool LLaserSet(uint8_t id); // レーザーをセットする 89 | void LLaserOpen(const ENEMY_DATA *e, uint8_t id); // レーザーを開く 90 | void LLaserClose(const ENEMY_DATA *e, uint8_t id); // レーザーを閉じる 91 | void LLaserLine(const ENEMY_DATA *e, uint8_t id); // レーザーをライン状態にする 92 | void LLaserDegA(const ENEMY_DATA *e, uint8_t d, uint8_t id); // レーザーを角度絶対で回転 93 | void LLaserDegR(const ENEMY_DATA *e, char d, uint8_t id); // レーザーを角度相対で回転 94 | 95 | extern void LLaserForceClose(const ENEMY_DATA *e); // 敵に関連づけられたレーザーを強制クローズ 96 | 97 | extern void LLaserMove(void); // レーザーを動かす 98 | extern void LLaserDraw(void); // レーザーを描画する 99 | extern void LLaserClear(void); // 無限遠レーザーを全クローズ 100 | 101 | extern void LLaserSetup(void); // レーザー配列の初期化をする 102 | 103 | 104 | 105 | //// レーザー変数2 //// 106 | extern LLASER_DATA LLaser[LLASER_MAX]; 107 | extern LLASER_CMD LLaserCmd; 108 | 109 | 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /GIAN07/LZ_UTY.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Packfiles and compression 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "platform/buffer.h" 9 | #include "platform/file.h" 10 | #include "platform/unicode.h" 11 | #include "game/endian.h" 12 | 13 | struct FILE_STREAM_READ; 14 | 15 | // Format 16 | // ------ 17 | 18 | using fil_checksum_t = uint32_t; 19 | using fil_size_t = uint32_t; 20 | using fil_no_t = uint32_t; 21 | constexpr const std::array PBG_HEADNAME = { 'P', 'B', 'G', 0x1A }; 22 | 23 | struct PBG_FILEHEAD { 24 | std::array name = PBG_HEADNAME; 25 | ENDIAN_LITTLE sum = 0; 26 | ENDIAN_LITTLE n = 0; 27 | }; 28 | 29 | struct PBG_FILEINFO { 30 | ENDIAN_LITTLE size_uncompressed; 31 | ENDIAN_LITTLE offset; 32 | ENDIAN_LITTLE checksum_compressed; 33 | }; 34 | // ------ 35 | 36 | class BIT_DEVICE_READ { 37 | struct { 38 | size_t byte = 0; 39 | uint8_t bit = 0; 40 | 41 | void operator +=(unsigned int bitcount) { 42 | bit += bitcount; 43 | byte += (bit / 8); 44 | bit %= 8; 45 | } 46 | } cursor; 47 | 48 | public: 49 | const BYTE_BUFFER_BORROWED buffer; 50 | 51 | BIT_DEVICE_READ(const BYTE_BUFFER_BORROWED buffer) : 52 | buffer(buffer) { 53 | } 54 | 55 | BIT_DEVICE_READ(const void* mem,size_t size) : 56 | buffer({ static_cast(mem), size }) { 57 | } 58 | 59 | // Returns 0xFF if we're at the end of the stream. 60 | uint8_t GetBit(); 61 | 62 | // Returns 0xFFFFFFFF if we're at the end of the stream. Supports a maximum 63 | // of 24 bits. 64 | uint32_t GetBits(size_t bitcount); 65 | }; 66 | 67 | struct BIT_DEVICE_WRITE { 68 | BYTE_BUFFER_GROWABLE buffer; 69 | uint8_t bit_cursor:3 = 0; 70 | 71 | void PutBit(uint8_t bit); 72 | void PutBits(uint32_t bits,unsigned int bitcount); 73 | bool Write(const PATH_LITERAL s) const; 74 | }; 75 | 76 | struct BIT_FILE_READ : public BIT_DEVICE_READ { 77 | const BYTE_BUFFER_OWNED file; 78 | 79 | BIT_FILE_READ(BYTE_BUFFER_OWNED &&file) : 80 | BIT_DEVICE_READ(file.get(),file.size()), 81 | file(std::move(file)) { 82 | } 83 | }; 84 | 85 | struct PACKFILE_READ { 86 | BYTE_BUFFER_OWNED packfile; 87 | std::span info; 88 | 89 | PACKFILE_READ(std::nullptr_t null = nullptr) noexcept { 90 | } 91 | 92 | PACKFILE_READ( 93 | BYTE_BUFFER_OWNED &&packfile, const std::span info 94 | ) : 95 | packfile(std::move(packfile)), 96 | info(info) { 97 | } 98 | 99 | BYTE_BUFFER_OWNED MemExpand(fil_no_t filno) const; 100 | 101 | explicit operator bool() const { 102 | return packfile.get(); 103 | } 104 | }; 105 | 106 | struct PACKFILE_WRITE { 107 | std::vector files; 108 | 109 | bool Write(const PATH_LITERAL s, FILE_FLAGS flags = FILE_FLAGS::NONE) const; 110 | }; 111 | 112 | BIT_FILE_READ BitFilCreateR(const PATH_LITERAL s); 113 | PACKFILE_READ FilStartR(BYTE_BUFFER_OWNED packfile); 114 | PACKFILE_READ FilStartR(std::unique_ptr stream); 115 | PACKFILE_READ FilStartR(const PATH_LITERAL s); 116 | -------------------------------------------------------------------------------- /GIAN07/MAIDTAMA.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* MaidTama.h メイドさんなショットの処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_MAIDTAMA_H 7 | #define PBGWIN_MAIDTAMA_H "めいどたま : Version 0.01 : Update 2000/02/25" 8 | //#pragma message(PBGWIN_MAIDTAMA_H) 9 | 10 | #include "TAMA.H" 11 | 12 | 13 | 14 | ///// [ 定数 ] ///// 15 | 16 | // 最大値 // 17 | #define MAIDTAMA_MAX 200 // 自機ショットの最大数 18 | 19 | #define TID_WIDE_MAIN 0x00 // ワイド・メインショットのID 20 | #define TID_WIDE_SUB 0x01 // ワイド・サブショットのID 21 | #define TID_HOMING_MAIN 0x02 // ホーミング・メインショットのID 22 | #define TID_HOMING_SUB 0x03 // ホーミング・サブショットのID 23 | #define TID_LASER_MAIN 0x04 // レーザー・メインショット??のID 24 | #define TID_LASER_SUB 0x05 // レーザー・サブショットのID 25 | 26 | #define TID_HOMING_BOMB_A 0x06 // ホーミング用ボム(移動中) 27 | #define TID_HOMING_BOMB_B 0x07 // ホーミング用ボム(誘爆中) 28 | 29 | #define TDM_WIDE_MAIN 6 // ワイド・メインショットのダメージ 30 | #define TDM_WIDE_SUB 4 // ワイド・サブショットのダメージ 31 | #define TDM_HOMING_MAIN 6 // ホーミング・メインショットのダメージ 32 | #define TDM_HOMING_SUB 7 // ホーミング・サブショットのダメージ 33 | #define TDM_LASER_MAIN 2 // レーザー・メインショットのダメージ 34 | #define TDM_LASER_SUB 5 // レーザー・サブショットのダメージ 35 | 36 | 37 | 38 | ///// [ 関数 ] ///// 39 | void MaidTamaSet(void); // たま発射!! 40 | void MaidTamaMove(void); // 弾移動&ヒットチェック 41 | void MaidTamaDraw(void); // ナニな弾描画 42 | void MaidTamaIndSet(void); // 弾ハッシュテーブル初期化 43 | 44 | 45 | 46 | ///// [ 変数 ] ///// 47 | extern std::array MaidTama; // 自機ショットの格納用構造体 48 | extern std::array MaidTamaInd; // 弾の順番を維持するための配列(TAMA.CPP互換) 49 | extern uint16_t MaidTamaNow; // 現在の数 50 | 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /GIAN07/MUSIC.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Music Room 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | // 音楽室の初期化をする 9 | bool MusicRoomInit(void); 10 | 11 | // 音楽室 12 | void MusicRoomProc(bool&); 13 | -------------------------------------------------------------------------------- /GIAN07/PRankCtrl.cpp: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* PRankCtrl.cpp プレイランク管理 */ 3 | /* */ 4 | /* */ 5 | 6 | #include "PRankCtrl.h" 7 | #include "LEVEL.H" 8 | #include "GIAN.H" 9 | 10 | PlayRankInfo PlayRank; 11 | 12 | 13 | 14 | // 難易度の許容範囲内でプレイランクを増減する 15 | void PlayRankAdd(int n) 16 | { 17 | // イージー    0 ~ 24 18 | // ノーマル   16 ~ 40 19 | // ハード     32 ~ 48 20 | // ルナティック 40 ~ 64 21 | 22 | // 難易度を変化させる // 23 | if(GameStage == GRAPH_ID_EXSTAGE){ 24 | if(n > 0) { 25 | PlayRank.Rank += (std::max)(+1, (n / 4)); 26 | } else if(n < 0) { 27 | PlayRank.Rank += (std::min)(-1, (n / 10)); 28 | } 29 | } 30 | else{ 31 | PlayRank.Rank += n; 32 | } 33 | 34 | // この分岐に関しては、基本的にコンフィグの値に基づく // 35 | switch(GameLevel) { 36 | case(GAME_EASY): 37 | if (PlayRank.Rank < 0) PlayRank.Rank = 0; 38 | else if(PlayRank.Rank > 24*256) PlayRank.Rank = 24*256; 39 | 40 | if(PlayRank.Rank < 20*256) PlayRank.GameLevel = GAME_EASY; 41 | else PlayRank.GameLevel = GAME_NORMAL; 42 | break; 43 | 44 | case(GAME_NORMAL): 45 | if (PlayRank.Rank < 16*256) PlayRank.Rank = 16*256; 46 | else if(PlayRank.Rank > 40*256) PlayRank.Rank = 40*256; 47 | 48 | if (PlayRank.Rank < 20*256) PlayRank.GameLevel = GAME_EASY; 49 | else if(PlayRank.Rank < 36*256) PlayRank.GameLevel = GAME_NORMAL; 50 | else PlayRank.GameLevel = GAME_HARD; 51 | break; 52 | 53 | case(GAME_HARD): 54 | if (PlayRank.Rank < 32*256) PlayRank.Rank = 32*256; 55 | else if(PlayRank.Rank > 48*256) PlayRank.Rank = 48*256; 56 | 57 | if (PlayRank.Rank < 36*256) PlayRank.GameLevel = GAME_NORMAL; 58 | else if(PlayRank.Rank < 44*256) PlayRank.GameLevel = GAME_HARD; 59 | else PlayRank.GameLevel = GAME_LUNATIC; 60 | break; 61 | 62 | case(GAME_LUNATIC): 63 | if (PlayRank.Rank < 40*256) PlayRank.Rank = 40*256; 64 | else if(PlayRank.Rank > 64*256) PlayRank.Rank = 64*256; 65 | 66 | if(PlayRank.Rank < 44*256) PlayRank.GameLevel = GAME_HARD; 67 | else PlayRank.GameLevel = GAME_LUNATIC; 68 | break; 69 | 70 | //case(GAME_EXTRA): 71 | //break; 72 | } 73 | } 74 | 75 | 76 | // 現在の難易度に応じてプレイランクを初期化 77 | void PlayRankReset(void) 78 | { 79 | PlayRank.GameLevel = GameLevel; 80 | 81 | switch(GameLevel) { 82 | case(GAME_EASY): PlayRank.Rank = 12*256; break; 83 | case(GAME_NORMAL): PlayRank.Rank = 28*256; break; 84 | case(GAME_HARD): PlayRank.Rank = 40*256; break; 85 | case(GAME_LUNATIC): PlayRank.Rank = 52*256; break; 86 | //case(GAME_EXTRA): break; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /GIAN07/PRankCtrl.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* PRankCtrl.h プレイランク管理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_PRANKCTRL_H 7 | #define PBGWIN_PRANKCTRL_H "PRANKCTRL : Version 0.01 : Update 2000/09/13" 8 | 9 | import std.compat; 10 | 11 | 12 | 13 | ///// [構造体] ///// 14 | typedef struct tagPlayRankInfo{ 15 | uint8_t GameLevel; // 方向数も関係する難易度変化 16 | int Rank; // 弾の速度変化に関する値 17 | } PlayRankInfo; 18 | 19 | 20 | 21 | ///// [グローバル変数] ///// 22 | extern PlayRankInfo PlayRank; 23 | 24 | 25 | 26 | ///// [ 関数 ] ///// 27 | void PlayRankAdd(int n); // 難易度の許容範囲内でプレイランクを増減する 28 | void PlayRankReset(void); // 現在の難易度に応じてプレイランクを初期化 29 | 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /GIAN07/SCL.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* SCL.h SCL用定義ファイル */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_SCL_H 7 | #define PBGWIN_SCL_H "SCL : Ver 0.11 : Update 2000/02/28" 8 | //#pragma message(PBGWIN_SCL_H) 9 | 10 | 11 | 12 | ///// [更新履歴] ///// 13 | 14 | // 2000/03/14 : WAITEX,STAGECLEAR 命令を追加 15 | // 2000/02/28 : BOSS命令を変更 16 | // 2000/02/24 : ミディ関連の関数を追加 17 | // 2000/02/18 : システムのアップデート開始 18 | 19 | 20 | ///// 特殊な命令の仕様について ///// 21 | 22 | // WAITEX <待ち条件(BYTE)>,<オプション(DWORD)> 23 | // 待ち条件の BOSSHP は、主に背景エフェクトチェンジ等に用いること(状態推移には使用しない) 24 | 25 | 26 | ///// [ 定数 ] ///// 27 | 28 | // SCL 命令 // 29 | #define SCL_TIME 0x00 // 次のイベントの発動時間 30 | #define SCL_ENEMY 0x01 // 敵イベント 31 | #define SCL_SSP 0x02 // スクロールスピードチェンジ 32 | #define SCL_EFC 0x03 // エフェクトセット 33 | #define SCL_END 0x04 // SCL終了 34 | #define SCL_BOSS 0x05 // ボス発生(引数は X(16),Y(16),BossID(8)) 35 | 36 | 37 | // SCL レベル2命令 // 38 | #define SCL_MWOPEN 0x06 // メッセージウィンドウを開く 39 | #define SCL_MWCLOSE 0x07 // メッセージウィンドウを閉じる 40 | #define SCL_MSG 0x08 // メッセージを出力する 41 | #define SCL_KEY 0x09 // キー入力待ち 42 | #define SCL_NPG 0x0a // 新しいページに変更する 43 | #define SCL_FACE 0x0b // 顔を表示する 44 | #define SCL_MUSIC 0x0c // 曲データをロードする 45 | #define SCL_BOSSDEAD 0x0d // ボス強制破壊(すなわち時間切れ) 46 | #define SCL_LOADFACE 0x0e // 顔グラをロードする(引数は、SurfaceID(BYTE),FileNo(BYTE)) 47 | #define SCL_WAITEX 0x0f // ある条件が起こるまでSCLをストップする 48 | #define SCL_STAGECLEAR 0x10 // そのステージが終了することを意味する。次のステージへGO! 49 | #define SCL_MAPPALETTE 0x11 // パレットをマップパーツ用のもので初期化する(For 8BitMode) 50 | #define SCL_GAMECLEAR 0x12 // タイトルに戻る(ネームレジスト有) 51 | #define SCL_DELENEMY 0x13 // 敵を強制消去(インデックス配列そのものを)する 52 | #define SCL_ENEMYPALETTE 0x14 // 敵のパレットにする 53 | #define SCL_STAFF 0x15 // スタッフIDセット 54 | #define SCL_EXTRACLEAR 0x16 // エキストラステージクリア 55 | 56 | 57 | // EFC 命令の引数 // 58 | #define SEFC_WARN 0x00 // ワーニング音・開始 59 | #define SEFC_WARNSTOP 0x01 // ワーニング音・停止 60 | #define SEFC_MUSICFADE 0x02 // 曲フェードアウト実行(Level2) 61 | #define SEFC_STG2BOSS 0x03 // ステージ2ボスのスクロール発動!! 62 | #define SEFC_RASTERON 0x04 // ラスタースクロール開始(砂漠とか海底都市とかに使えるかも) 63 | #define SEFC_RASTEROFF 0x05 // ラスタースクロール終了 64 | #define SEFC_CFADEIN 0x06 // 円形フェードイン 65 | #define SEFC_CFADEOUT 0x07 // 円形フェードアウト 66 | #define SEFC_STG3BOSS 0x08 // 3面ボス雲 67 | #define SEFC_STG3RESET 0x09 // 3面ボス雲リセット 68 | #define SEFC_STG6CUBE 0x0a // 6面ボス3Dキューヴ 69 | #define SEFC_STG6RNDECL 0x0b // 6面ボス偽ECL羅列 70 | #define SEFC_STG4ROCK 0x0c // 4面岩 71 | #define SEFC_STG4LEAVE 0x0d // 4面岩を画面外に吐き出す 72 | #define SEFC_WHITEIN 0x0e // ホワイトイン 73 | #define SEFC_WHITEOUT 0x0f // ホワイトアウト 74 | #define SEFC_LOADEX01 0x10 // エキストラボス1用画像をロード 75 | #define SEFC_LOADEX02 0x11 // エキストラボス2用画像をロード 76 | #define SEFC_STG6RASTER 0x12 // 6面ラスター 77 | 78 | 79 | // WAITEX 命令の引数(Level2) // 80 | #define SWAIT_BOSSLEFT 0x00 // ボスの残り数(OPT:ボスの数) 81 | #define SWAIT_BOSSHP 0x01 // ボスのHP総和が指定値より小さい(OPT:残りHP) 82 | 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /GIAN07/SCORE.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* Score.h スコア入出力関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_SCORE_H 7 | #define PBGWIN_SCORE_H "SCORE : Version 0.01 : Update 2000/07/29" 8 | //#pragma message(PBGWIN_SCORE_H) 9 | 10 | import std.compat; 11 | #include "game/string_format.h" 12 | 13 | 14 | 15 | ///// [ 定数 ] ///// 16 | #define NR_NAME_LEN 9 // ネームレジストの名前の長さ('\0' 含む) 17 | #define NR_RANK_MAX 5 // 順位付け(Save)される最大数 18 | 19 | 20 | 21 | ///// [構造体] ///// 22 | 23 | typedef struct tagNR_NAME_DATA{ 24 | char Name[NR_NAME_LEN]; // 名前 25 | int64_t Score; // スコア 26 | uint32_t Evade; // かすり回数 27 | uint8_t Stage; // ステージ 28 | uint8_t Weapon; // 装備品 29 | } NR_NAME_DATA; 30 | 31 | typedef struct tagNR_SCORE_DATA{ 32 | NR_NAME_DATA Easy[NR_RANK_MAX]; // 難易度:Easy 33 | NR_NAME_DATA Normal[NR_RANK_MAX]; // 難易度:Normal 34 | NR_NAME_DATA Hard[NR_RANK_MAX]; // 難易度:Hard 35 | NR_NAME_DATA Lunatic[NR_RANK_MAX]; // 難易度:Lunatic 36 | NR_NAME_DATA Extra[NR_RANK_MAX]; // 難易度:Extra 37 | } NR_SCORE_DATA; 38 | 39 | typedef struct tagNR_SCORE_STRING{ 40 | uint8_t Rank; // 実際の順位(ある順位が複数ある場合の対策) 41 | int x,y; // 描画用座標 42 | bool bMoveEnable; // 移動可能か? 43 | 44 | char Name[NR_NAME_LEN]; // 名前 45 | char Score[STRING_NUM_CAP + 1]; // 得点 46 | char Evade[STRING_NUM_CAP + 1]; // かすり 47 | char Stage[1+1]; // ステージ 48 | uint8_t Weapon; // 装備 49 | } NR_SCORE_STRING; 50 | 51 | 52 | 53 | ///// [ 関数 ] ///// 54 | 55 | // 現在のスコア列を取得する(Ret:下と同じ) 56 | uint8_t SetScoreString(NR_NAME_DATA *NData, uint8_t Dif); 57 | 58 | // 0:ハイスコアでない それ以外:順位 59 | uint8_t IsHighScore(const NR_NAME_DATA *NData, uint8_t Dif); 60 | 61 | bool SaveScoreData(NR_NAME_DATA *NData, uint8_t Dif); // スコアデータを書き出す 62 | 63 | 64 | 65 | ///// [グローバル変数] ///// 66 | extern NR_SCORE_STRING ScoreString[NR_RANK_MAX]; // スコアデータ文字列格納先 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /GIAN07/SCROLL.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* SCROLL.h スクロール処理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_SCROLL_H 7 | #define PBGWIN_SCROLL_H "SCROLL : Version 0.11 : Update 2000/02/28" 8 | //#pragma message(PBGWIN_SCROLL_H) 9 | 10 | #include "platform/buffer.h" 11 | 12 | 13 | ///// [更新履歴] ///// 14 | // 2000/04/01 : スクロールコマンドを追加(STAGE2_BOSS) 15 | // 2000/02/28 : BOSS命令を Level2 に変更 16 | // 2000/02/24 : みぢ命令を追加 17 | // 2000/02/18 : 敵配置処理と結合する 18 | // 2000/02/01 : 開発開始 19 | // 20 | 21 | 22 | 23 | ///// [ 定数 ] ///// 24 | 25 | // マップエディタと共有する定数 // 26 | #define LAYER_MAX 5 // レイヤーの深さ 27 | #define TIME_PER_FRAME 20 // 1フレームでどれだけ時間が進むか 28 | #define MAP_WIDTH 24 // マップの横幅 29 | #define MAPDATA_NONE 0xffff // マップ上に何も置かれていない状態 30 | 31 | // スクロールステータス // 32 | #define SST_NORMAL 0x00 // 通常時 33 | #define SST_STOP 0x01 // 停止中 34 | 35 | // スクロールコマンド // 36 | #define SCMD_QUAKE 0x01 // 画面を振動させる 37 | #define SCMD_STG2BOSS 0x02 // 2面ボスの反転スクロール 38 | #define SCMD_RASTER_ON 0x03 // ラスタースクロール開始 39 | #define SCMD_RASTER_OFF 0x04 // ラスタースクロー終了 40 | #define SCMD_STG3BOSS 0x05 // 背景雲をゲイツモード(謎)に変更する 41 | #define SCMD_STG3RESET 0x06 // 3面の背景をノーマルモードに戻す 42 | #define SCMD_STG6CUBE 0x07 // 6面ボスの3Dキューブモード 43 | #define SCMD_STG6RNDECL 0x08 // 6面ボスのランダム偽ECL列配置 44 | #define SCMD_STG4ROCK 0x09 // 4面岩 45 | #define SCMD_STG4LEAVE 0x0a // 4面岩を画面外に吐き出す 46 | #define SCMD_STG6RASTER 0x0b // 6面ラスター 47 | #define SCMD_STG3STAR 0x0c // 3面高速星 48 | 49 | 50 | 51 | ///// [ 型 ] ///// 52 | typedef uint16_t PBGMAP; // マップパーツ格納用の型 53 | 54 | 55 | 56 | ///// [マクロ] ///// 57 | 58 | 59 | 60 | ///// [構造体] ///// 61 | 62 | // スクロール管理用構造体 // 63 | typedef struct tagScrollInfo{ 64 | // GRP lpMapOffs; // マップパーツデータ(Graphic)の格納先 65 | 66 | BYTE_BUFFER_OWNED DataHead; // マップデータのヘッダ 67 | 68 | PBGMAP *LayerHead[LAYER_MAX]; // 各レイヤーのヘッダ 69 | PBGMAP *LayerPtr[LAYER_MAX]; // 現在のレイヤーのポインタ 70 | uint32_t LayerWait[LAYER_MAX]; // レイヤーの重み 71 | int LayerCount[LAYER_MAX]; // レイヤーごとのカウンタ 72 | uint8_t LayerDy[LAYER_MAX]; // レイヤーの1Dot単位のズレ 73 | 74 | int NumLayer; // レイヤー数 75 | int ScrollSpeed; // スクロール速度 76 | uint32_t Count; // 現在の時刻 77 | uint32_t InfStart; // 無限ループの開始時刻(デフォルトは0) 78 | uint32_t InfEnd; // 無限ループの終了時刻(デフォルトはマップの長さの最小値) 79 | 80 | uint8_t State; // スクロールステータス 81 | uint8_t IsQuake; // 振動中か? 82 | 83 | char RasterDx[31]; // ラスタースクロールによるX加算値 84 | uint8_t RasterWidth; // ラスタースクロールにおける振幅 85 | uint8_t RasterDeg; // ラスタースクロール用の角度 86 | 87 | void(*ExCmd)(void); // 特殊コマンド 88 | uint32_t ExCount; // 特殊コマンド用カウンタ 89 | } SCROLL_INFO; 90 | 91 | // SCL管理用構造体 // 92 | typedef struct tagSCL_INFO{ 93 | bool MsgFlag; // メッセージスキップ用フラグ 94 | bool ReturnFlag; // リターンキー用フラグ 95 | } SCL_INFO; 96 | 97 | 98 | ///// [ 関数 ] ///// 99 | void ScrollMove(void); // 背景を動かす(1フレーム分) 100 | void ScrollDraw(void); // 背景を描画する 101 | 102 | void ScrollSpeed(int speed); // スクロールスピードを変更する(引数:(1)スクロール速度) 103 | void ScrollCommand(uint8_t cmd); // SCL用コマンド実行関数(引数:(1)スクロールコマンド) 104 | 105 | bool ScrollInit(void); // マップデータを初期化する 106 | 107 | 108 | 109 | ///// [ 変数 ] ///// 110 | extern SCROLL_INFO ScrollInfo; // スクロールに関する情報 111 | extern SCL_INFO SclInfo; // SCLに関する情報 112 | 113 | 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /GIAN07/WindowCtrl.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* WINDOWCTRL.h ウィンドウの定義&管理 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_WINDOWCTRL_H 7 | #define PBGWIN_WINDOWCTRL_H "WINDOWCTRL : Version 0.01 : Update 2000/02/12" 8 | //#pragma message(PBGWIN_WINDOWCTRL_H) 9 | 10 | 11 | 12 | ///// [更新履歴] ///// 13 | 14 | // 15 | 16 | 17 | 18 | ///// [Include Files] ///// 19 | 20 | 21 | 22 | ///// [ 定数 ] ///// 23 | ///// [マクロ] ///// 24 | ///// [構造体] ///// 25 | 26 | ///// [グローバル変数] ///// 27 | extern struct tagWINDOW_SYSTEM MainWindow; 28 | extern struct tagWINDOW_SYSTEM BGMPackWindow; 29 | extern struct tagWINDOW_SYSTEM ExitWindow; 30 | extern struct tagWINDOW_SYSTEM ContinueWindow; 31 | 32 | 33 | ///// [関数] ///// 34 | void InitMainWindow(void); // メインメニューの初期化 35 | void InitExitWindow(void); // 終了Y/Nウィンドウの初期化 36 | void InitContinueWindow(void); // コンティニューY/Nウィンドウの初期化 37 | 38 | 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /GIAN07/entity.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic entity management 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | #include 10 | 11 | template void Indsort( 12 | std::array& indices, 13 | uint16_t& count, 14 | const std::array& entities, 15 | ShouldDelete should_delete 16 | ) 17 | { 18 | uint16_t i; 19 | uint16_t next; 20 | 21 | for(i = next = 0; i < count; i++) { 22 | // 消去要請フラグが立っている->swap 立っていない-> counter++ // 23 | if(should_delete(entities[indices[i]])) { 24 | uint16_t temp; 25 | // フラグの立っていないアイテムを検索する // 26 | for(temp = (i + 1); temp < count; temp++) { 27 | if(should_delete(entities[indices[temp]]) == 0){ 28 | next++; 29 | break; 30 | } 31 | } 32 | 33 | // pbg landmine: This looks as if it will write out of bounds on 34 | // the last iteration of the loop ([i] == ([count] - 1). It only 35 | // doesn't because every [count]-mutating setter function ensures 36 | // that it stays ≤([N] - 1), thus reducing the effective [N] by 1. 37 | assert( 38 | (count <= (N - 1)) || 39 | !"setter function violated entity cap precondition" 40 | ); 41 | #pragma warning(suppress: 28020) 42 | std::swap(indices[i], indices[temp]); 43 | } else { 44 | next++; 45 | } 46 | } 47 | count = next; 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 pbghogehoge 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MAIN/MAIN.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Win32 entry point 3 | * 4 | */ 5 | 6 | #include "../GIAN07/ENTRY.H" 7 | #include "game/defer.h" 8 | #include "platform/window_backend.h" 9 | 10 | int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) 11 | { 12 | if(!WndBackend_Create({})) { 13 | return FALSE; 14 | } 15 | defer(WndBackend_Cleanup()); 16 | 17 | if(!XInit()) { 18 | return false; 19 | } 20 | defer(XCleanup()); 21 | 22 | return WndBackend_Run(); 23 | } 24 | -------------------------------------------------------------------------------- /MapEdit2/GrpUty.cpp: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* GrpUty.cpp グラフィック補助関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #include "MapEdit.h" 7 | #include "GrpUty.h" 8 | #include "DirectXUTYs/DD_GRP3D.H" 9 | 10 | 11 | void GrpPuts(char *s,int x,int y) 12 | { 13 | RECT src; 14 | int sx; 15 | 16 | sx = x; 17 | 18 | for(;(*s)!='\0';s++,x+=9){ 19 | if((*s)>='a' && (*s)<='z'){ 20 | src.top = 40; 21 | src.bottom = src.top + 16; 22 | src.left = 256 + ((*s)-'a')*9; 23 | src.right = src.left + 9; 24 | } 25 | else if((*s)>='A' && (*s)<='Z'){ 26 | src.top = 40 + 16; 27 | src.bottom = src.top + 16; 28 | src.left = 256 + ((*s)-'A')*9; 29 | src.right = src.left + 9; 30 | } 31 | else if((*s)>='0' && (*s)<='9'){ 32 | src.top = 40 + 32; 33 | src.bottom = src.top + 16; 34 | src.left = 256 + ((*s)-'0')*9; 35 | src.right = src.left + 9; 36 | } 37 | else{ 38 | switch(*s){ 39 | case('+'): src.left = 256; break; 40 | case('-'): src.left = 256 + 9; break; 41 | case('*'): src.left = 256 + 18; break; 42 | case('/'): src.left = 256 + 27; break; 43 | case('('): src.left = 256 + 36; break; 44 | case(')'): src.left = 256 + 45; break; 45 | case(','): src.left = 256 + 54; break; 46 | case('.'): src.left = 256 + 63; break; 47 | case('!'): src.left = 256 + 72; break; 48 | case('?'): src.left = 256 + 81; break; 49 | case('\"'): src.left = 256 + 90; break; 50 | case('#'): src.left = 256 + 99; break; 51 | case('$'): src.left = 256 + 108; break; 52 | case('%'): src.left = 256 + 117; break; 53 | case('&'): src.left = 256 + 126; break; 54 | case('\''): src.left = 256 + 135; break; 55 | case('\\'): src.left = 256 + 144; break; 56 | 57 | case('='): src.left = 256 + 153; break; 58 | case(':'): src.left = 256 + 162; break; 59 | case(';'): src.left = 256 + 171; break; 60 | case('<'): src.left = 256 + 180; break; 61 | case('>'): src.left = 256 + 189; break; 62 | case('_'): src.left = 256 + 198; break; 63 | 64 | case('\n'): // 改行(x=sx-9,y=y+16とか) 65 | x = sx-9; 66 | y = y+16; 67 | default: 68 | continue; 69 | } 70 | src.top = 40 + 48; 71 | src.bottom = src.top + 16; 72 | src.right = src.left + 9; 73 | } 74 | 75 | GrpBltX(&src,x,y,GrTama); 76 | } 77 | } 78 | 79 | void GrpPut8(char *s,int x,int y) 80 | { 81 | RECT src; 82 | int sx,tx,ty; 83 | 84 | sx = x; 85 | 86 | for(;(*s)!='\0';s++,x+=8){ 87 | if((*s)>='A' && (*s)<='Z'){ 88 | BltSetRect(&src,256+(((*s)-'A')<<3),32,8,8); 89 | } 90 | else if((*s)>='a' && (*s)<='z'){ 91 | BltSetRect(&src,256+(((*s)-'a')<<3),32,8,8); 92 | } 93 | else if((*s)>='0' && (*s)<='9'){ 94 | BltSetRect(&src,640-17*8+20+(((*s)-'0')<<3),72+16+16,8,8); 95 | } 96 | else{ 97 | continue; 98 | } 99 | 100 | tx = x;ty = y; 101 | GrpBlt(&src,tx,ty,GrTama); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /MapEdit2/GrpUty.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* GRPUTY.h グラフィック補助関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_GRPUTY_H 7 | #define PBGWIN_GRPUTY_H "GRPUTY : Version 0.01 : Update 1999/12/05" 8 | #pragma message(PBGWIN_GRPUTY_H) 9 | 10 | 11 | // 更新履歴 // 12 | 13 | 14 | // ヘッダファイル // 15 | #include "PBGUTY_X.H" 16 | 17 | 18 | // 関数 // 19 | void GrpPuts(char *s,int x,int y); 20 | void GrpPut8(char *s,int x,int y); 21 | 22 | /* 23 | _inline void BltSetRect(RECT *rc,int x1,int y1,int x2,int y2) 24 | { 25 | rc->right = (rc->left = x1) + x2; 26 | rc->bottom = (rc->top = y1) + y2; 27 | } 28 | */ 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /MapEdit2/MapEdit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MapEdit.h 簡易マップエディタ 3 | * 4 | */ 5 | 6 | #ifndef PBGWIN_MAPEDIT_H 7 | 8 | #define MAPEDIT2_VERSION "Ver 0.72" 9 | #define PBGWIN_MAPEDIT_H "MapEdit : "MAPEDIT2_VERSION" Update 2000/02/01" 10 | #pragma message(PBGWIN_MAPEDIT_H) 11 | 12 | #include "PBGUTY_X.H" 13 | #include "../Gian07SrcFiles/SCROLL.H" 14 | 15 | 16 | // グラフィック関連定数 // 17 | #define ID_MAP_CHIP 0 18 | #define ID_TAMA 1 19 | 20 | 21 | // マップ管理用定数 // 22 | #define UNDO_MAX 10 // 最大Undo回数 23 | 24 | #define KEY_WAITTIME 10 // キーボード用ウェイト 25 | 26 | 27 | #define RESERVED_WIDTH 2 // 予約済みの幅 28 | #define RESERVED_HEIGHT 1 // 予約済みの高さ 29 | 30 | #define SCROLLWAIT_DEFAULT 1 // スクロールの重みの初期値 31 | 32 | #define MAP_HEIGHT (30-RESERVED_HEIGHT) // マップの表示する縦幅 33 | #define MAP_LEN 1000 // マップの縦幅 34 | #define MAP_SIZE (MAP_WIDTH*MAP_LEN) // マップに必要なメモリ 35 | 36 | #define CHIP_WIDTH (40-RESERVED_WIDTH-MAP_WIDTH) 37 | 38 | #define BMP_CHIP_WIDTH 640 // マップチップの幅 39 | #define BMP_CHIP_HEIGHT 480 // マップチップの高さ 40 | 41 | 42 | 43 | // マップデータ管理用構造体 // 44 | typedef struct tagMapData{ 45 | BOOL bMask; // マスクがかかっているか 46 | PBGMAP DataID; // マップパーツ番号 47 | } MapData; 48 | 49 | 50 | // マップ全体のMapData // 51 | typedef struct tagMapInfo{ 52 | MapData Data[LAYER_MAX][MAP_SIZE]; // 全レイヤーを含むマップデータ 53 | WORD ScrollWait[LAYER_MAX]; // 1Dotスクロールに要するカウント数 54 | } MapInfo; 55 | 56 | 57 | // Undo用の環状スタック // 58 | typedef struct tagUndoStack{ 59 | int StackPtr; // スタックポインタ 60 | int UndoLeft; // 残りUndo回数 61 | int RedoLeft; // 残りRedo回数 62 | MapInfo Data[UNDO_MAX]; // マップデータ1個分 63 | } UndoStack; 64 | 65 | 66 | // マップパーツコピー用構造体 // 67 | typedef struct tagCopyData{ 68 | PBGMAP *Data; // コピーするデータ列 69 | int Width; // 幅 70 | int Height; // 高さ 71 | } CopyData; 72 | 73 | 74 | // マップエディタの状態 // 75 | typedef enum tagMeState{ 76 | ME_NONE, // 何もしない 77 | ME_MASK_ON, // マスク(描き込み不可)領域選択中 78 | ME_MASK_OFF, // マスク(描き込み 可 )領域選択中 79 | ME_GETRECTM, // パーツ選択中(Mapパーツから) 80 | ME_GETRECTE, // パーツ選択中(作業領域から) 81 | ME_PUTRECT, // パーツ貼り付け中 82 | ME_VIEW, // ビューモード 83 | ME_HELP, // ヘルプ表示 84 | } MeState; 85 | 86 | 87 | // マップエディタ管理用構造体 // 88 | typedef struct tagMapEditor{ 89 | POINT MouseInfo; // マウスの状態(座標) 90 | POINT MouseTemp; // PUT用マウス座標保持 91 | BYTE KeyInfo[256]; // キーボードの状態 92 | 93 | BOOL MouseR; // マウスの右ボタンが押されている 94 | BOOL MouseL; // マウスの左ボタンが押されている 95 | 96 | MeState State; // 現在の状態 97 | RECT Select; // 矩形領域選択用 98 | 99 | DWORD KeyCount; // リピート制御カウンタ 100 | DWORD ViewTime; // ビューモードの時間 101 | 102 | int Line; // 画面下は何行か? 103 | int Layer; // 作業中のレイヤー 104 | int ChipX; // マップチップの表示X 105 | 106 | MapInfo Data; // 現在のマップの状態 107 | } MapEditor; 108 | 109 | 110 | // ぐろーばる変数 // 111 | extern UndoStack Undo; 112 | extern MapEditor Map; 113 | extern CopyData Copy; 114 | extern GRP GrMapChip; 115 | extern GRP GrTama; 116 | 117 | 118 | BOOL EditorInit(void); // エディタの初期化 119 | void EditorMain(void); // エディタのメイン 120 | void EditorDraw(void); // 画面描画関連 121 | 122 | BOOL LoadMapData(char *filename); // マップチップの配置データをLoadする 123 | BOOL SaveMapData(char *filename); // マップチップの配置データをSaveする 124 | 125 | void ConvertRect(RECT *rc); // 小→大となる矩形を得る 126 | 127 | void StkRedo(void); // Undo スタックを用いて Redo を行う 128 | void StkPushUndo(void); // Undo スタックに挿入 129 | void StkPopUndo(void); // Undo スタックから取り出し 130 | 131 | void SetMask(void); // マスクをセットする 132 | void ResetMask(void); // マスクをリセットする 133 | 134 | void GetMapDataM(void); // マップデータの取得(マップパーツエリア) 135 | void GetMapDataE(void); // マップデータの取得(作業領域) 136 | void FreeMapData(void); // マップデータの解放 137 | void PutMapData(void); // マップデータの貼り付け 138 | 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /SCLC/Calc.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* CALC.h 式の解析 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_CALC_H 7 | #define PBGWIN_CALC_H "CALC : Version 0.02 : Update 2000/02/03" 8 | #pragma message(PBGWIN_CALC_H) 9 | 10 | #include 11 | 12 | 13 | 14 | ///// [ 定数 ] ///// 15 | #define CALC_DATA_MAX 100 // スタック領域の大きさ 16 | #define OPE1_MINUS '@' // 単項演算子 - に対する記号 17 | 18 | 19 | 20 | ///// [ 関数 ] ///// 21 | extern void CalcSetup(void (*func)(char *s)); // 計算の準備をする 22 | extern int Calc(char *factor); // 引数:空白の無い式 23 | 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /Tupfile.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/Tupfile.ini -------------------------------------------------------------------------------- /Tupfile.linux.lua: -------------------------------------------------------------------------------- 1 | tup.include("libs/tupblocks/toolchain.clang.lua") 2 | tup.include("libs/BLAKE3.lua") 3 | 4 | tup.import("SDL") 5 | SDL = SDL[1] 6 | 7 | local PLATFORM_LINK = EnvConfig(SDL, "pangocairo", "fontconfig") 8 | local LAYERS_LINK = EnvConfig("libwebp", "ogg", "vorbis", "vorbisfile") 9 | local BLAKE3_LINK = (EnvConfig("libblake3") or BuildBLAKE3(CONFIG, 0)) 10 | 11 | -- Since Pango/Cairo adds -pthread to a later configuration, the C++ standard 12 | -- library must also be compiled with this flag. 13 | CONFIG = CONFIG:branch({ cflags = "-pthread" }) 14 | 15 | local ssg_cfg = CONFIG:branch( 16 | BLAKE3_LINK, LAYERS_LINK, SSG_COMPILE, CONFIG:cxx_std_modules(), { 17 | cflags = { "-DLINUX", ("-D" .. string.upper(SDL) .. "=1") }, 18 | } 19 | ) 20 | local ssg_obj = ssg_cfg:cxx(SSG_SRC) 21 | 22 | -- Our platform layer code 23 | LAYERS_SRC += (SSG.glob("platform/c/*.cpp")) 24 | ssg_obj = (ssg_obj + ssg_cfg:cxx(LAYERS_SRC)) 25 | 26 | local platform_cfg = ssg_cfg:branch(PLATFORM_LINK) 27 | local platform_src = SSG.glob("platform/sdl/*.cpp") 28 | platform_src += SSG.glob("platform/miniaudio/*.cpp") 29 | platform_src += SSG.glob("platform/pangocairo/*.cpp") 30 | platform_src += "MAIN/main_sdl.cpp" 31 | platform_src.extra_inputs += PLATFORM_CONSTANTS 32 | ssg_obj = ( 33 | ssg_obj + 34 | platform_cfg:cxx(platform_src) + 35 | 36 | -- Clang does not like C being compiled with clang++, and non-C++ clang 37 | -- does not like module-related switches. 38 | CONFIG:branch(SSG_COMPILE):cc(SSG.glob("platform/miniaudio/*.c")) 39 | ) 40 | 41 | platform_cfg:exe(ssg_obj, "GIAN07") 42 | -------------------------------------------------------------------------------- /Tupfile.lua: -------------------------------------------------------------------------------- 1 | tup.include("libs/tupblocks/Tuprules.lua") 2 | 3 | ---@type ConfigShape 4 | SSG_COMPILE = {} 5 | SSG_COMPILE.cflags = { "-I.", "-IGIAN07/", debug = "-DPBG_DEBUG" } 6 | SSG_COMPILE.objdir = "ssg/" 7 | 8 | SSG = sourcepath("./") 9 | 10 | PLATFORM_CONSTANTS = EnvHeader(SSG.join("obj/platform_constants.h"), { 11 | "APP_ID", "PATH_SKELETON" 12 | }) 13 | 14 | -- pbg code 15 | SSG_SRC += SSG.glob("GIAN07/*.cpp") 16 | SSG_SRC += SSG.glob("GIAN07/*.CPP") 17 | SSG_SRC.extra_inputs += PLATFORM_CONSTANTS 18 | 19 | -- Modern game code 20 | LAYERS_SRC += SSG.glob("game/*.cpp") 21 | LAYERS_SRC += SSG.glob("game/codecs/*.cpp") 22 | 23 | tup.include(string.format("Tupfile.%s.lua", tup.getconfig("TUP_PLATFORM"))) 24 | -------------------------------------------------------------------------------- /art/016_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/016_alpha.png -------------------------------------------------------------------------------- /art/016_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/016_box.png -------------------------------------------------------------------------------- /art/032_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/032_alpha.png -------------------------------------------------------------------------------- /art/032_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/032_box.png -------------------------------------------------------------------------------- /art/032_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/032_text.png -------------------------------------------------------------------------------- /art/048_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/048_alpha.png -------------------------------------------------------------------------------- /art/048_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/048_box.png -------------------------------------------------------------------------------- /art/048_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/048_text.png -------------------------------------------------------------------------------- /art/128_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/128_alpha.png -------------------------------------------------------------------------------- /art/128_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/128_box.png -------------------------------------------------------------------------------- /art/128_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/128_text.png -------------------------------------------------------------------------------- /art/sh01.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/art/sh01.ico -------------------------------------------------------------------------------- /bin/bgm/Folder structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/bin/bgm/Folder structure.png -------------------------------------------------------------------------------- /build_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$#" -eq 0 ] || { [ "$1" != "sdl2" ] && [ "$1" != "sdl3" ]; }; then 4 | >&2 echo "Usage: $0 sdl2|sdl3 [tup-targets...]" 5 | exit 1 6 | fi 7 | export SDL="$1" 8 | shift 9 | 10 | ./version_from_git.sh 11 | 12 | # We can't commit this file directly because Tup's database initialization 13 | # check literally just looks for the directory, and refuses to auto-initialize 14 | # the database if it already exists. (Also, Windows doesn't need it.) 15 | [ ! -d .tup ] && tup init 16 | [ ! -f .tup/options ] && 17 | echo "[updater] 18 | full_deps = 1 ; Necessary to track compiler updates on Linux" > .tup/options 19 | 20 | # Libraries that either aren't packaged by any distro or that we always want 21 | # to use the vendored version of 22 | ./submodules_check.sh \ 23 | libs/tupblocks \ 24 | libs/dr_libs \ 25 | libs/miniaudio \ 26 | || exit 1 27 | 28 | . ./libs/tupblocks/pkg_config_env.sh 29 | 30 | # Libraries that are supposed to be installed through the system's package 31 | # manager 32 | pkg_config_env_required \ 33 | "$SDL" \ 34 | fontconfig \ 35 | libwebp \ 36 | ogg \ 37 | pangocairo \ 38 | vorbis \ 39 | vorbisfile \ 40 | 41 | # Vendored libraries that we only use when they aren't installed system-wide 42 | pkg_config_env_optional libblake3 43 | ! pkg-config --exists libblake3 && { 44 | ./submodules_check.sh libs/BLAKE3 || exit 1; 45 | } 46 | 47 | tup "$@" 48 | -------------------------------------------------------------------------------- /build_windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if "%VCINSTALLDIR%" == "" ( 4 | echo Error: The build must be run from within Visual Studio's `x64_x86 Cross Tools Command Prompt`. 5 | exit 1 6 | ) 7 | 8 | sh ./version_from_git.sh 9 | sh ./submodules_check.sh ^ 10 | libs/9xcompat ^ 11 | libs/BLAKE3 ^ 12 | libs/dr_libs ^ 13 | libs/libogg ^ 14 | libs/libvorbis ^ 15 | libs/libwebp_lossless ^ 16 | libs/miniaudio ^ 17 | libs/SDL2 ^ 18 | libs/SDL3 ^ 19 | libs/tupblocks 20 | if %errorlevel% neq 0 exit /b %errorlevel% 21 | 22 | tup %* 23 | exit /b 24 | -------------------------------------------------------------------------------- /game/README.md: -------------------------------------------------------------------------------- 1 | Core game functionality, independent of any platform. Sits next to the [`platform` subdirectory](../platform/) in the layer hierarchy, and can `#include` code from the top level of `platform/`. 2 | 3 | Must not contain anything that is implemented in terms of system calls, but *can* contain platform-independent base classes for platform-specific functionality. 4 | -------------------------------------------------------------------------------- /game/bgm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Format-independent background music interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | #include "game/hash.h" 10 | #include "game/narrow.h" 11 | #include "platform/buffer.h" 12 | 13 | // Loads the BGM with the given 0-based [id] from the game's original BGM data 14 | // source. 15 | extern bool (*const BGM_MidLoadOriginal)(unsigned int id); 16 | 17 | // Loads MIDI BGM from the given byte buffer. 18 | extern bool (*const BGM_MidLoadBuffer)(BYTE_BUFFER_OWNED); 19 | 20 | // Loads the source MIDI via its hash from the game's original BGM data source. 21 | extern bool (*const BGM_MidLoadByHash)(const HASH& hash); 22 | 23 | bool BGM_Init(void); 24 | void BGM_Cleanup(void); 25 | 26 | // General queries 27 | // --------------- 28 | 29 | enum class BGM_PLAYING { 30 | NONE, 31 | WAVEFORM, 32 | MIDI, 33 | }; 34 | 35 | bool BGM_Enabled(void); 36 | bool BGM_LoadedOriginalMIDI(void); 37 | bool BGM_HasGainFactor(void); 38 | bool BGM_GainApply(void); 39 | BGM_PLAYING BGM_Playing(void); 40 | std::chrono::duration BGM_PlayTime(void); 41 | Narrow::string_view BGM_Title(void); 42 | // --------------- 43 | 44 | bool BGM_ChangeMIDIDevice(int8_t direction); // 出力デバイスを変更する 45 | 46 | // Playback 47 | // -------- 48 | 49 | // Stops the currently playing BGM, then loads and plays the track with the 50 | // given 0-based [id]. Returns `true` if the BGM was changed successfully. 51 | bool BGM_Switch(unsigned int id); 52 | 53 | void BGM_Play(void); 54 | void BGM_Stop(void); 55 | 56 | void BGM_Pause(void); 57 | void BGM_Resume(void); 58 | // -------- 59 | 60 | // Processes all MIDI events of a playing waveform track's source MIDI that 61 | // have occurred since the last call to this function. 62 | void BGM_UpdateMIDITables(void); 63 | 64 | // Volume control 65 | // -------------- 66 | 67 | // Changes the gain apply flag, and applies the result to any currently playing 68 | // waveform track. 69 | void BGM_SetGainApply(bool apply); 70 | 71 | void BGM_UpdateVolume(void); 72 | 73 | // フェードアウト(数字が大きいほど早い) 74 | void BGM_FadeOut(uint8_t speed); 75 | // -------------- 76 | 77 | // Tempo control 78 | // ------------- 79 | 80 | static constexpr uint8_t BGM_TEMPO_DENOM = (1 << 7); // 標準のテンポ 81 | static constexpr int8_t BGM_TEMPO_MIN = -100; 82 | static constexpr int8_t BGM_TEMPO_MAX = 100; 83 | 84 | int8_t BGM_GetTempo(void); 85 | void BGM_SetTempo(int8_t tempo); // テンポを変更する 86 | // ------------- 87 | 88 | // BGM pack management 89 | // ------------------- 90 | 91 | // Returns whether at least one BGM pack exists under the BGM root directory. 92 | // The result is cached and invalidated whenever BGM is paused. 93 | bool BGM_PacksAvailable(bool invalidate_cache = false); 94 | 95 | size_t BGM_PackCount(void); 96 | void BGM_PackForeach(void func(const std::u8string&& str)); 97 | 98 | // Restarts any currently playing BGM when switching to a different [pack]. 99 | // Returns `false` if the given [pack] doesn't exist, and switches to the empty 100 | // pack in that case. 101 | bool BGM_PackSet(const std::u8string_view pack); 102 | // ------------------- 103 | -------------------------------------------------------------------------------- /game/cast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Directional casts for integers 3 | * 4 | * Inspired by the Guidelines Support Library: 5 | * 6 | * https://github.com/microsoft/GSL 7 | */ 8 | 9 | #pragma once 10 | 11 | import std; 12 | 13 | namespace Cast { 14 | 15 | template constexpr T down(F&& f) noexcept 16 | { 17 | using To = std::remove_reference_t; 18 | using From = std::remove_reference_t; 19 | static_assert(sizeof(To) < sizeof(From)); 20 | static_assert(std::is_signed_v == std::is_signed_v); 21 | return static_cast(std::forward(f)); 22 | } 23 | 24 | template constexpr T sign(F&& f) noexcept 25 | { 26 | using To = std::remove_reference_t; 27 | using From = std::remove_reference_t; 28 | static_assert(sizeof(To) == sizeof(From)); 29 | static_assert(std::is_signed_v != std::is_signed_v); 30 | return static_cast(std::forward(f)); 31 | } 32 | 33 | template constexpr T down_sign(F&& f) noexcept 34 | { 35 | using To = std::remove_reference_t; 36 | using From = std::remove_reference_t; 37 | static_assert(sizeof(To) < sizeof(From)); 38 | static_assert(std::is_signed_v != std::is_signed_v); 39 | return static_cast(std::forward(f)); 40 | } 41 | 42 | template constexpr T up(F&& f) noexcept 43 | { 44 | using To = std::remove_reference_t; 45 | using From = std::remove_reference_t; 46 | static_assert(sizeof(To) > sizeof(From)); 47 | static_assert(std::is_signed_v == std::is_signed_v); 48 | return static_cast(std::forward(f)); 49 | } 50 | 51 | template constexpr T up_sign(F&& f) noexcept 52 | { 53 | using To = std::remove_reference_t; 54 | using From = std::remove_reference_t; 55 | static_assert(sizeof(To) > sizeof(From)); 56 | static_assert(std::is_signed_v != std::is_signed_v); 57 | return static_cast(std::forward(f)); 58 | } 59 | 60 | } // namespace Cast 61 | -------------------------------------------------------------------------------- /game/codecs/vorbis.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Vorbis streaming support 3 | * 4 | * Adapted from thcrap's bgmmod module. 5 | */ 6 | 7 | #include "game/bgm_track.h" 8 | #include 9 | 10 | #define OV_EXCLUDE_STATIC_CALLBACKS 11 | #include 12 | 13 | namespace BGM { 14 | 15 | // Callbacks 16 | // --------- 17 | 18 | static size_t CB_Vorbis_Read( 19 | void* ptr, size_t size, size_t nmemb, void* datasource 20 | ) 21 | { 22 | auto* stream = static_cast(datasource); 23 | return stream->Read({ static_cast(ptr), (size * nmemb) }); 24 | } 25 | 26 | int CB_Vorbis_Seek(void* datasource, ogg_int64_t offset, int ov_whence) 27 | { 28 | auto* stream = static_cast(datasource); 29 | 30 | #pragma warning(suppress : 26494) // type.5 31 | SEEK_WHENCE whence; 32 | switch(ov_whence) { 33 | case 0: whence = SEEK_WHENCE::BEGIN; break; 34 | case 1: whence = SEEK_WHENCE::CURRENT; break; 35 | case 2: whence = SEEK_WHENCE::END; break; 36 | default: 37 | assert(!"Invalid seek origin?"); 38 | return -1; 39 | } 40 | return stream->Seek(offset, whence); 41 | } 42 | 43 | long CB_Vorbis_Tell(void* datasource) 44 | { 45 | auto* stream = static_cast(datasource); 46 | return stream->Tell().value_or(-1); 47 | } 48 | 49 | static const ov_callbacks VORBIS_CALLBACKS = { 50 | CB_Vorbis_Read, CB_Vorbis_Seek, nullptr, CB_Vorbis_Tell, 51 | }; 52 | // --------- 53 | 54 | struct PCM_PART_VORBIS : public BGM::PCM_PART { 55 | OggVorbis_File vf; 56 | 57 | size_t PartDecodeSingle(std::span buf) override; 58 | void PartSeekToSample(size_t sample) override; 59 | 60 | PCM_PART_VORBIS(OggVorbis_File&& vf, const PCM_FORMAT& pcmf) : 61 | vf(vf), PCM_PART(pcmf) { 62 | } 63 | virtual ~PCM_PART_VORBIS(); 64 | }; 65 | 66 | size_t PCM_PART_VORBIS::PartDecodeSingle(std::span buf) 67 | { 68 | assert(pcmf.format == PCM_SAMPLE_FORMAT::S16); 69 | auto* buf_as_char = reinterpret_cast(buf.data()); 70 | return ov_read(&vf, buf_as_char, buf.size_bytes(), 0, 2, 1, nullptr); 71 | } 72 | 73 | void PCM_PART_VORBIS::PartSeekToSample(size_t sample) 74 | { 75 | const auto ret = ov_pcm_seek(&vf, sample); 76 | assert(ret == 0); 77 | } 78 | 79 | PCM_PART_VORBIS::~PCM_PART_VORBIS() 80 | { 81 | ov_clear(&vf); 82 | } 83 | 84 | std::unique_ptr Vorbis_Open( 85 | FILE_STREAM_READ& stream, std::optional on_metadata 86 | ) 87 | { 88 | OggVorbis_File vf = { 0 }; 89 | const auto ret = ov_open_callbacks( 90 | &stream, &vf, nullptr, 0, VORBIS_CALLBACKS 91 | ); 92 | if(ret || !vf.vi) { 93 | return nullptr; 94 | } 95 | assert(vf.vi->rate >= 0); 96 | assert(vf.vi->channels >= 0); 97 | 98 | if(on_metadata) { 99 | const auto* vc = ov_comment(&vf, -1); 100 | if(vc) { 101 | for(decltype(vc->comments) i = 0; i < vc->comments; i++) { 102 | // Why signed!? 103 | const auto len = vc->comment_lengths[i]; 104 | if(vc->comment_lengths[i] < 2) { 105 | continue; 106 | } 107 | BGM::OnVorbisComment(on_metadata.value(), { 108 | reinterpret_cast(vc->user_comments[i]), 109 | static_cast(len), 110 | }); 111 | } 112 | } 113 | } 114 | 115 | const auto samplingrate = static_cast(vf.vi->rate); 116 | const auto channels = static_cast(vf.vi->channels); 117 | PCM_FORMAT pcmf = { samplingrate, channels, PCM_SAMPLE_FORMAT::S16 }; 118 | return std::make_unique(std::move(vf), pcmf); 119 | } 120 | 121 | } // namespace BGM 122 | -------------------------------------------------------------------------------- /game/debug.cpp: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DX_ERROR.c DirectX のエラー出力用関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #include "game/debug.h" 7 | #include "platform/file.h" 8 | #include "platform/time.h" 9 | #pragma message(PBGWIN_DX_ERROR_H) 10 | 11 | 12 | // グローバル変数 // 13 | constexpr auto ErrorOut = _PATH("ErrLOG_UTF8.TXT"); 14 | static bool ErrorActive = false; 15 | 16 | 17 | extern void DebugSetup() 18 | { 19 | #pragma warning(suppress : 26494) // type.5 20 | std::array str; 21 | 22 | const auto tm = Time_NowLocal(); 23 | const auto len = snprintf( 24 | str.data(), 25 | str.size(), 26 | "[%02u/%02u/%02u][%02u:%02u:%02u]\n", 27 | tm.month, 28 | tm.day, 29 | (tm.year % 100), 30 | tm.hour, 31 | tm.minute, 32 | tm.second 33 | ); 34 | if(len <= 0) { 35 | return; 36 | } 37 | FileAppend(ErrorOut, std::span(str.data(), static_cast(len))); 38 | ErrorActive = true; 39 | } 40 | 41 | extern void DebugCleanup(void) 42 | { 43 | ErrorActive = false; 44 | } 45 | 46 | void DebugLog(std::u8string_view prefix, std::u8string_view s) 47 | { 48 | using namespace std::string_view_literals; 49 | 50 | if(!ErrorActive) { 51 | return; 52 | } 53 | const std::array bufs = { 54 | std::span(prefix), std::span(s), std::span("\n"sv), 55 | }; 56 | FileAppend(ErrorOut, std::span{ bufs }); 57 | } 58 | 59 | void DebugLog(std::u8string_view s) 60 | { 61 | return DebugLog(u8"", s); 62 | } 63 | 64 | extern void DebugOut(std::u8string_view s) 65 | { 66 | return DebugLog(u8"Error : ", s); 67 | } 68 | -------------------------------------------------------------------------------- /game/debug.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DX_ERROR.h DirectX のエラー出力用関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DX_ERROR_H 7 | #define PBGWIN_DX_ERROR_H "DX_ERROR : Version 0.01 : Update 1999/11/20" 8 | 9 | import std; 10 | 11 | // 更新履歴 // 12 | 13 | // 1999/12/10 : ファイルにエラー出力をする関数を追加 14 | // 1999/11/20 : 作成開始 15 | 16 | 17 | // 関数プロトタイプ宣言 // 18 | extern void DebugSetup(void); // エラー出力準備(->LogFile) 19 | extern void DebugCleanup(void); // エラー吐き出し用ファイルを閉じる 20 | extern void DebugLog(std::u8string_view s); 21 | extern void DebugOut(std::u8string_view s); // デバッグメッセージ吐き出し 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /game/defer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Go/Zig-style `defer` implementation for C++ 3 | * 4 | * https://www.gingerbill.org/article/2015/08/19/defer-in-cpp/ 5 | */ 6 | 7 | template struct privDefer { 8 | F f; 9 | privDefer(F f) : f(f) {} 10 | ~privDefer() { f(); } 11 | }; 12 | 13 | template privDefer defer_func(F f) { 14 | return privDefer(f); 15 | } 16 | 17 | #define DEFER_1(x, y) x##y 18 | #define DEFER_2(x, y) DEFER_1(x, y) 19 | #define DEFER_3(x) DEFER_2(x, __COUNTER__) 20 | #define defer(code) auto DEFER_3(_defer_) = defer_func([&](){code;}) 21 | -------------------------------------------------------------------------------- /game/endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Little- and big-endian integer types 3 | * 4 | * Why did the C++ committee standardize std::endian, but not anything like 5 | * this?! 6 | * (See https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html.) 7 | */ 8 | 9 | #pragma once 10 | 11 | import std.compat; 12 | 13 | template class ENDIAN_VALUE { 14 | std::byte v[sizeof(T)]; 15 | 16 | using UT = std::make_unsigned_t; 17 | static constexpr UT ShiftOffset(uint8_t byte) { 18 | return ((Big ? (sizeof(T) - 1 - byte) : byte) * 8); 19 | } 20 | 21 | public: 22 | ENDIAN_VALUE() noexcept { 23 | *this = 0; 24 | } 25 | 26 | ENDIAN_VALUE(const T& other) noexcept { 27 | *this = other; 28 | } 29 | 30 | constexpr operator T() const noexcept { 31 | T ret = 0; 32 | for(uint8_t byte = 0; byte < sizeof(T); byte++) { 33 | ret |= (std::to_integer(v[byte]) << ShiftOffset(byte)); 34 | } 35 | return ret; 36 | } 37 | 38 | const T& operator =(const T& other) noexcept { 39 | for(uint8_t byte = 0; byte < sizeof(T); byte++) { 40 | v[byte] = static_cast( 41 | static_cast(other) >> ShiftOffset(byte) 42 | ); 43 | } 44 | return other; 45 | } 46 | }; 47 | 48 | template using ENDIAN_LITTLE = ENDIAN_VALUE; 49 | template using ENDIAN_BIG = ENDIAN_VALUE; 50 | 51 | // Let's help the optimizer a bit. 52 | template using ENDIAN_SELECT_LITTLE = std::conditional_t< 53 | (std::endian::native == std::endian::little), T, ENDIAN_LITTLE 54 | >; 55 | template using ENDIAN_SELECT_BIG = std::conditional_t< 56 | (std::endian::native == std::endian::big), T, ENDIAN_BIG 57 | >; 58 | 59 | using I16LE = ENDIAN_SELECT_LITTLE; 60 | using U16LE = ENDIAN_SELECT_LITTLE; 61 | using I32LE = ENDIAN_SELECT_LITTLE; 62 | using U32LE = ENDIAN_SELECT_LITTLE; 63 | using I16BE = ENDIAN_SELECT_BIG; 64 | using U16BE = ENDIAN_SELECT_BIG; 65 | using I32BE = ENDIAN_SELECT_BIG; 66 | using U32BE = ENDIAN_SELECT_BIG; 67 | 68 | static I16LE I16LEAt(const void *p) { return *static_cast(p); } 69 | static U16LE U16LEAt(const void *p) { return *static_cast(p); } 70 | static I32LE I32LEAt(const void *p) { return *static_cast(p); } 71 | static U32LE U32LEAt(const void *p) { return *static_cast(p); } 72 | static I16BE I16BEAt(const void *p) { return *static_cast(p); } 73 | static U16BE U16BEAt(const void *p) { return *static_cast(p); } 74 | static I32BE I32BEAt(const void *p) { return *static_cast(p); } 75 | static U32BE U32BEAt(const void *p) { return *static_cast(p); } 76 | -------------------------------------------------------------------------------- /game/enum_array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * std::array with one element for each member of an enum, delimited with a 3 | * `COUNT` field. 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | #include 10 | 11 | template concept ENUMARRAY_ID = ( 12 | std::is_enum_v && 13 | std::is_unsigned_v> && 14 | requires { E::COUNT; } 15 | ); 16 | 17 | template class ENUMARRAY : public std::array< 18 | T, std::to_underlying(IDType::COUNT) 19 | > { 20 | using BASE = std::array; 21 | 22 | public: 23 | // We could do something like 24 | // 25 | // using T_ref_or_value = std::conditional_t< 26 | // std::derived_from, T, T& 27 | // >; 28 | // 29 | // to opt into returning by value for certain classes, but this does not 30 | // compile on Visual Studio 2022 17.11.0 Preview 4.0. 31 | 32 | constexpr T& operator[](IDType id) noexcept { 33 | #pragma warning(suppress: 26445) // gsl.view 34 | return BASE::operator[](std::to_underlying(id)); 35 | } 36 | 37 | constexpr const T& operator[](IDType id) const noexcept { 38 | #pragma warning(suppress: 26445) // gsl.view 39 | return BASE::operator[](std::to_underlying(id)); 40 | } 41 | }; 42 | 43 | namespace Cast { 44 | 45 | template constexpr inline IDType down_enum( 46 | std::underlying_type_t f 47 | ) 48 | { 49 | assert(f < std::to_underlying(IDType::COUNT)); 50 | return static_cast(f); 51 | } 52 | 53 | } // namespace Cast 54 | -------------------------------------------------------------------------------- /game/enum_flags.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Operators for using enums as flags. 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | 10 | template concept ENUMFLAGS = (std::is_enum_v && requires { 11 | { T::_HAS_BITFLAG_OPERATORS }; 12 | }); 13 | 14 | template constexpr inline bool operator !(const T& v) noexcept { 15 | return (std::to_underlying(v) == 0); 16 | } 17 | 18 | template constexpr inline std::underlying_type_t operator~( 19 | const T& v 20 | ) noexcept 21 | { 22 | return ~std::to_underlying(v); 23 | } 24 | 25 | template constexpr inline T operator&( 26 | const T& a, const T& b 27 | ) noexcept 28 | { 29 | return static_cast(std::to_underlying(a) & std::to_underlying(b)); 30 | } 31 | 32 | template constexpr inline T operator|( 33 | const T& a, const T& b 34 | ) noexcept 35 | { 36 | return static_cast(std::to_underlying(a) | std::to_underlying(b)); 37 | } 38 | 39 | template constexpr inline T operator^( 40 | const T& a, const T& b 41 | ) noexcept 42 | { 43 | return static_cast(std::to_underlying(a) ^ std::to_underlying(b)); 44 | } 45 | 46 | template constexpr inline T& operator|=(T& a, const T& b) noexcept 47 | { 48 | a = static_cast(std::to_underlying(a) | std::to_underlying(b)); 49 | return a; 50 | } 51 | 52 | template constexpr inline T& operator&=( 53 | T& a, const std::underlying_type_t& b 54 | ) noexcept 55 | { 56 | a = static_cast(std::to_underlying(a) & b); 57 | return a; 58 | } 59 | 60 | template constexpr inline T& operator^=(T& a, const T& b) noexcept 61 | { 62 | a = static_cast(a ^ b); 63 | return a; 64 | } 65 | 66 | // Sets the given [flag] in [self] to the value of [val]. 67 | template constexpr void EnumFlagSet( 68 | T& self, T flag, std::underlying_type_t val 69 | ) 70 | { 71 | const auto shift = std::countr_zero(std::to_underlying(flag)); 72 | self = static_cast(std::to_underlying(self) & ~flag); 73 | self |= static_cast(static_cast(val << shift) & flag); 74 | } 75 | -------------------------------------------------------------------------------- /game/format_bmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * .BMP file format 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "platform/file.h" 9 | #include "game/coords.h" 10 | #include "game/endian.h" 11 | #include "game/pixelformat.h" 12 | 13 | // Platform-independent .BMP header types 14 | // -------------------------------------- 15 | // Yup, these actually need to be packed. 16 | #pragma pack(push, 1) 17 | 18 | // Same as the standard Win32 BITMAPFILEHEADER structure, renamed to avoid 19 | // collisions. 20 | struct BMP_FILEHEADER { 21 | U16LE bfType; 22 | U32LE bfSize; 23 | U16LE bfReserved1; 24 | U16LE bfReserved2; 25 | U32LE bfOffBits; 26 | }; 27 | 28 | // Same as the standard Win32 BITMAPINFOHEADER structure, renamed to avoid 29 | // collisions. 30 | struct BMP_INFOHEADER { 31 | U32LE biSize; 32 | I32LE biWidth; 33 | I32LE biHeight; 34 | U16LE biPlanes; 35 | U16LE biBitCount; 36 | U32LE biCompression; 37 | U32LE biSizeImage; 38 | I32LE biXPelsPerMeter; 39 | I32LE biYPelsPerMeter; 40 | U32LE biClrUsed; 41 | U32LE biClrImportant; 42 | 43 | uint32_t Stride() const { 44 | return ((((biWidth * biBitCount) + 31u) & ~31) / 8u); 45 | } 46 | }; 47 | 48 | #pragma pack(pop) 49 | // -------------------------------------- 50 | 51 | // A valid .BMP buffer, with convenient references to the header, optional 52 | // palette, and pixel data inside the buffer. 53 | struct BMP_OWNED { 54 | BYTE_BUFFER_OWNED buffer; 55 | const BMP_INFOHEADER& info; 56 | std::span palette; // Empty if not palettized. 57 | std::span pixels; // Exactly as large as the image. 58 | }; 59 | 60 | // Can be safely used for static allocations. 61 | constexpr uint16_t BMP_PALETTE_SIZE_MAX = 256; 62 | 63 | // Returns a value between 0 and [BMP_PALETTE_SIZE_MAX]. 64 | constexpr uint16_t BMPPaletteSizeFromBPP(uint8_t bpp); 65 | 66 | std::optional BMPLoad(BYTE_BUFFER_OWNED buffer); 67 | 68 | // Returns `true` if BMPSave() supports the given [format]. 69 | bool BMPSaveSupports(PIXELFORMAT format); 70 | 71 | bool BMPSave( 72 | FILE_STREAM_WRITE* stream, 73 | PIXEL_SIZE size, 74 | uint16_t planes, 75 | uint16_t bpp, 76 | std::span palette, 77 | std::span pixels 78 | ); 79 | -------------------------------------------------------------------------------- /game/frame.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Per-frame function, implemented by the game. 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | // Runs the next game frame after updating inputs. Returns `false` if the game 9 | // should quit. 10 | bool GameFrame(void); 11 | -------------------------------------------------------------------------------- /game/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hash functions and helpers 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/narrow.h" 9 | #include "platform/buffer.h" 10 | #include 11 | 12 | using HASH = std::array; 13 | 14 | static constexpr std::optional HashFrom(Narrow::string_view str) 15 | { 16 | if(str.size() != (std::tuple_size_v * 2)) { 17 | return std::nullopt; 18 | } 19 | HASH ret = { std::byte{ 0 } }; 20 | uint8_t shift = true; 21 | for(size_t i = 0; i < str.size(); i++) { 22 | const auto ch = str[i]; 23 | const auto nibble = ( 24 | ((ch >= 'A') && (ch <= 'F')) ? ((ch - 'A') + 0xA) : 25 | ((ch >= 'a') && (ch <= 'f')) ? ((ch - 'a') + 0xA) : 26 | ((ch >= '0') && (ch <= '9')) ? ((ch - '0') + 0x0) : 27 | 0xFF 28 | ); 29 | if(nibble == 0xFF) { 30 | return std::nullopt; 31 | } 32 | ret[i / 2] |= static_cast(nibble << (shift * 4)); 33 | shift = !shift; 34 | } 35 | return ret; 36 | } 37 | 38 | // Hashes the given buffer. 39 | static HASH Hash(const BYTE_BUFFER_BORROWED& buffer) 40 | { 41 | HASH ret; 42 | blake3_hasher h; 43 | blake3_hasher_init(&h); 44 | blake3_hasher_update(&h, buffer.data(), buffer.size_bytes()); 45 | blake3_hasher_finalize( 46 | &h, reinterpret_cast(ret.data()), BLAKE3_OUT_LEN 47 | ); 48 | return ret; 49 | } 50 | 51 | constexpr HASH operator ""_B3(const char* str, size_t len) 52 | { 53 | const auto ret = HashFrom(Narrow::string_view{ str, len }); 54 | if(!ret) { 55 | throw "Invalid hash literal"; 56 | } 57 | return ret.value(); 58 | } 59 | 60 | // Compile-time-sorted arrays 61 | // -------------------------- 62 | 63 | template concept HASHABLE = requires { 64 | { T::hash } -> std::same_as; 65 | }; 66 | 67 | template struct SORTED : public std::array { 68 | std::array::const_iterator Lookup(const HASH& hash) const noexcept { 69 | const auto ret = std::ranges::lower_bound(*this, hash, {}, &T::hash); 70 | if((ret == this->cend()) || (ret->hash != hash)) { 71 | return this->cend(); 72 | } 73 | return ret; 74 | } 75 | }; 76 | 77 | template constexpr SORTED HashesSorted( 78 | std::array&& unsorted 79 | ) { 80 | std::ranges::sort(unsorted, [](const auto& a, const auto& b) { 81 | if(a.hash == b.hash) { 82 | throw "Duplicated hash"; 83 | } 84 | return (a.hash < b.hash); 85 | }); 86 | return SORTED{ unsorted }; 87 | } 88 | // -------------------------- 89 | -------------------------------------------------------------------------------- /game/input.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Cross-platform input declarations 3 | * 4 | */ 5 | 6 | #include "game/input.h" 7 | 8 | // グローバル変数(Public)の実体 9 | INPUT_BITS Key_Data = 0; 10 | INPUT_BITS Pad_Data = 0; 11 | INPUT_SYSTEM_BITS SystemKey_Data = 0; 12 | 13 | // MSVC's static analyzer suggests to make the functions below `constexpr`, 14 | // which won't work because they are used in other translation units and this 15 | // is not a header. 16 | #pragma warning(suppress: 26497) // f.4 17 | bool Input_IsOK(INPUT_BITS key) 18 | { 19 | return ((key == KEY_RETURN) || (key == KEY_TAMA)); 20 | } 21 | 22 | #pragma warning(suppress: 26497) // f.4 23 | bool Input_IsCancel(INPUT_BITS key) 24 | { 25 | return ((key == KEY_BOMB) || (key == KEY_ESC)); 26 | } 27 | 28 | int_fast8_t Input_OptionKeyDelta(INPUT_BITS key) 29 | { 30 | return ( 31 | (Input_IsOK(key) || (key == KEY_RIGHT)) ? 1 : 32 | (key == KEY_LEFT) ? -1 : 33 | 0 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /game/input.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Cross-platform input declarations 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | 10 | // Current pressed/released state for all virtual KEY_* keys. 11 | using INPUT_BITS = uint16_t; 12 | 13 | // 0 = unmapped. 14 | using INPUT_PAD_BUTTON = uint8_t; 15 | 16 | // キーボード定数 // 17 | // Braced initializers cause a compile error if the constants don't fit within 18 | // the INPUT_BITS type. 19 | constexpr INPUT_BITS KEY_UP = { 0x0001 }; 20 | constexpr INPUT_BITS KEY_DOWN = { 0x0002 }; 21 | constexpr INPUT_BITS KEY_LEFT = { 0x0004 }; 22 | constexpr INPUT_BITS KEY_RIGHT = { 0x0008 }; 23 | constexpr INPUT_BITS KEY_TAMA = { 0x0010 }; 24 | constexpr INPUT_BITS KEY_BOMB = { 0x0020 }; 25 | constexpr INPUT_BITS KEY_SHIFT = { 0x0040 }; 26 | constexpr INPUT_BITS KEY_RETURN = { 0x0080 }; 27 | constexpr INPUT_BITS KEY_ESC = { 0x0100 }; 28 | 29 | constexpr INPUT_BITS KEY_ULEFT = (KEY_UP | KEY_LEFT); 30 | constexpr INPUT_BITS KEY_URIGHT = (KEY_UP | KEY_RIGHT); 31 | constexpr INPUT_BITS KEY_DLEFT = (KEY_DOWN | KEY_LEFT); 32 | constexpr INPUT_BITS KEY_DRIGHT = (KEY_DOWN | KEY_RIGHT); 33 | 34 | // Returns whether this key represents an "OK" action. 35 | bool Input_IsOK(INPUT_BITS key); 36 | 37 | // Returns whether this key represents a "Cancel" action. 38 | bool Input_IsCancel(INPUT_BITS key); 39 | 40 | // Returns the delta that this key would apply to a numeric option value. 41 | int_fast8_t Input_OptionKeyDelta(INPUT_BITS key); 42 | 43 | // Additional virtual keys for inputs that were read using GetAsyncKeyState() 44 | // in the original game. Treated separately to not complicate any existing 45 | // comparisons of [Key_Data] with 0. 46 | using INPUT_SYSTEM_BITS = uint16_t; 47 | 48 | constexpr INPUT_SYSTEM_BITS SYSKEY_SNAPSHOT = { 0x0001 }; 49 | constexpr INPUT_SYSTEM_BITS SYSKEY_SKIP = { 0x0002 }; 50 | constexpr INPUT_SYSTEM_BITS SYSKEY_BGM_FADE = { 0x0004 }; 51 | constexpr INPUT_SYSTEM_BITS SYSKEY_BGM_DEVICE = { 0x0008 }; 52 | constexpr INPUT_SYSTEM_BITS SYSKEY_GRP_FULLSCREEN = { 0x0010 }; 53 | constexpr INPUT_SYSTEM_BITS SYSKEY_GRP_SCALE_DOWN = { 0x0020 }; 54 | constexpr INPUT_SYSTEM_BITS SYSKEY_GRP_SCALE_UP = { 0x0040 }; 55 | constexpr INPUT_SYSTEM_BITS SYSKEY_GRP_SCALE_MODE = { 0x0080 }; 56 | constexpr INPUT_SYSTEM_BITS SYSKEY_GRP_TURBO = { 0x0100 }; 57 | constexpr INPUT_SYSTEM_BITS SYSKEY_GRP_API = { 0x0200 }; 58 | 59 | using INPUT_PAD_BINDING = std::pair; 60 | 61 | // グローバル変数(Public) // 62 | extern INPUT_BITS Key_Data; 63 | extern INPUT_BITS Pad_Data; 64 | extern INPUT_SYSTEM_BITS SystemKey_Data; 65 | 66 | // Initialized by game code. 67 | extern std::span Key_PadBindings; 68 | -------------------------------------------------------------------------------- /game/narrow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Narrow string types 3 | * 4 | * Strings in these types are either in the game's original narrow encoding 5 | * or in UTF-8. Rendering functions must handle both possibilities. 6 | */ 7 | 8 | #pragma once 9 | 10 | import std; 11 | 12 | namespace Any { 13 | // Strings from outside the game with an unknown and not yet validated 14 | // encoding. 15 | using string_view = std::string_view; 16 | } 17 | 18 | namespace Narrow { 19 | 20 | class string_view; 21 | 22 | struct literal { 23 | const char* ptr; 24 | 25 | constexpr literal() noexcept = delete; 26 | constexpr literal(const char* other) noexcept : ptr(other) { 27 | } 28 | 29 | // Encoding-erasing conversions from UTF-8 are OK. 30 | literal(const std::u8string& other) noexcept : 31 | ptr(reinterpret_cast(other.c_str())) { 32 | } 33 | }; 34 | 35 | class string : public std::string { 36 | using std::string::string; 37 | 38 | public: 39 | // Concatenating another narrow string might lead to mixed encodings within 40 | // the same string. 41 | constexpr string operator+(const string& other) = delete; 42 | 43 | inline constexpr string& operator=(const string_view view); 44 | }; 45 | 46 | class string_view : public std::string_view { 47 | using std::string_view::string_view; 48 | 49 | public: 50 | constexpr string_view(const string& str) noexcept : 51 | std::string_view(str) { 52 | } 53 | 54 | // This asserts that [other]'s encoding is either of the two. 55 | constexpr string_view(Any::string_view other) noexcept : 56 | std::string_view(other) { 57 | } 58 | 59 | constexpr string_view(const literal& other) noexcept : 60 | std::string_view(other.ptr) { 61 | } 62 | 63 | // Encoding-erasing conversions from UTF-8 are OK... 64 | constexpr string_view(const std::u8string_view other) noexcept : 65 | std::string_view( 66 | { std::bit_cast(other.data()), other.size() } 67 | ) { 68 | } 69 | constexpr string_view(const std::u8string& other) noexcept : 70 | string_view(std::u8string_view{ other }) { 71 | } 72 | 73 | // ...but not the other way round. 74 | operator std::u8string_view() const = delete; 75 | operator std::u8string() const = delete; 76 | }; 77 | 78 | inline constexpr string& string::operator=(const string_view view) { 79 | assign(view); 80 | return *this; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /game/pcm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Sampling rate / bit depth / channel structure 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | 10 | enum class PCM_SAMPLE_FORMAT : uint8_t { 11 | S16 = 2, 12 | S32 = 4, 13 | }; 14 | 15 | struct PCM_FORMAT { 16 | const uint32_t samplingrate; 17 | const uint16_t channels; 18 | const PCM_SAMPLE_FORMAT format; 19 | 20 | std::strong_ordering operator <=>(const PCM_FORMAT& other) const = default; 21 | 22 | size_t SampleSize() const { 23 | const auto byte_depth = std::to_underlying(format); 24 | return (channels * byte_depth); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /game/snd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Sound interface 3 | * 4 | */ 5 | 6 | #include "game/snd.h" 7 | #include "game/enum_flags.h" 8 | #include "platform/snd_backend.h" 9 | #include 10 | 11 | float Snd_BGMGainFactor = 1.0f; 12 | 13 | static enum class SND_SYS { 14 | _HAS_BITFLAG_OPERATORS, 15 | NOTHING = 0x0, 16 | SYSTEM = 0x1, 17 | BGM = 0x2, 18 | SE = 0x4, 19 | } Initialized; 20 | 21 | bool Snd_SystemInit(void) 22 | { 23 | if(!!(Initialized & SND_SYS::SYSTEM)) { 24 | return true; 25 | } 26 | assert(Initialized == SND_SYS::NOTHING); 27 | if(!SndBackend_Init()) { 28 | return false; 29 | } 30 | Initialized |= SND_SYS::SYSTEM; 31 | return true; 32 | } 33 | 34 | bool Snd_SubsystemInit(SND_SYS sys, bool (&SubsystemInit)(void)) 35 | { 36 | if(!!(Initialized & sys)) { 37 | return true; 38 | } else if(!Snd_SystemInit() || !SubsystemInit()) { 39 | return false; 40 | } 41 | Initialized |= sys; 42 | Snd_UpdateVolumes(); 43 | return true; 44 | } 45 | 46 | void Snd_Cleanup(SND_SYS sys) 47 | { 48 | auto cleanup_sys = [](SND_SYS should, SND_SYS sys, void (&cleanup)(void)) { 49 | if(!!(should & sys) && !!(Initialized & sys)) { 50 | cleanup(); 51 | Initialized &= ~sys; 52 | } 53 | }; 54 | 55 | cleanup_sys(sys, SND_SYS::SE, SndBackend_SECleanup); 56 | cleanup_sys(sys, SND_SYS::BGM, SndBackend_BGMCleanup); 57 | 58 | // Silly double negation to work around C26813... 59 | if(~Initialized == ~SND_SYS::SYSTEM) { 60 | SndBackend_Cleanup(); 61 | Initialized = SND_SYS::NOTHING; 62 | } 63 | } 64 | 65 | void Snd_Cleanup(void) 66 | { 67 | Snd_Cleanup(SND_SYS::BGM | SND_SYS::SE); 68 | } 69 | 70 | void Snd_UpdateVolumes(void) 71 | { 72 | if(!!(Initialized & SND_SYS::BGM)) { 73 | SndBackend_BGMUpdateVolume(); 74 | } 75 | if(!!(Initialized & SND_SYS::SE)) { 76 | SndBackend_SEUpdateVolume(); 77 | } 78 | } 79 | 80 | bool Snd_BGMInit(void) 81 | { 82 | return Snd_SubsystemInit(SND_SYS::BGM, SndBackend_BGMInit); 83 | } 84 | 85 | bool Snd_SEInit(void) 86 | { 87 | return Snd_SubsystemInit(SND_SYS::SE, SndBackend_SEInit); 88 | } 89 | 90 | void Snd_BGMCleanup(void) 91 | { 92 | Snd_Cleanup(SND_SYS::BGM); 93 | } 94 | 95 | void Snd_SECleanup(void) 96 | { 97 | Snd_Cleanup(SND_SYS::SE); 98 | } 99 | 100 | bool Snd_SELoad(BYTE_BUFFER_OWNED buffer, uint8_t id, SND_INSTANCE_ID max) 101 | { 102 | return SndBackend_SELoad(std::move(buffer), id, max); 103 | } 104 | 105 | void Snd_SEPlay(uint8_t id, int x, bool loop) 106 | { 107 | return SndBackend_SEPlay(id, x, loop); 108 | } 109 | 110 | void Snd_SEStop(uint8_t id) 111 | { 112 | return SndBackend_SEStop(id); 113 | } 114 | 115 | void Snd_SEStopAll(void) 116 | { 117 | for(auto i = 0; i < SND_OBJ_MAX; i++) { 118 | SndBackend_SEStop(i); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /game/snd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PCM sound interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | 9 | // ヘッダファイル // 10 | #include "game/enum_flags.h" 11 | #include "game/volume.h" 12 | #include "platform/buffer.h" 13 | #include "constants.h" 14 | 15 | // 定数&マクロ // 16 | using SND_INSTANCE_ID = uint8_t; 17 | 18 | #define SND_OBJ_MAX 30 // 効果音の種類の最大数 19 | 20 | extern const uint8_t& Snd_BGMTempoNum; 21 | extern const uint8_t& Snd_BGMTempoDenom; 22 | 23 | extern const VOLUME& Snd_VolumeBGM; 24 | extern const VOLUME& Snd_VolumeSE; 25 | 26 | void Snd_Cleanup(void); 27 | void Snd_UpdateVolumes(void); 28 | 29 | // BGM 30 | // --- 31 | 32 | extern float Snd_BGMGainFactor; 33 | 34 | bool Snd_BGMInit(void); 35 | void Snd_BGMCleanup(void); 36 | // --- 37 | 38 | bool Snd_SEInit(void); 39 | void Snd_SECleanup(void); 40 | 41 | bool Snd_SELoad(BYTE_BUFFER_OWNED buffer, uint8_t id, SND_INSTANCE_ID max); 42 | 43 | // 再生&停止 // 44 | void Snd_SEPlay(uint8_t id, int x = SND_X_MID, bool loop = false); 45 | void Snd_SEStop(uint8_t id); 46 | void Snd_SEStopAll(void); 47 | -------------------------------------------------------------------------------- /game/string_format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * String formatting helpers 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | 10 | // Number of decimal digits required to store the highest value of the given 11 | // type. 12 | template constexpr auto STRING_NUM_CAP = ( 13 | ((241 * sizeof(T)) / 100) + 1 14 | ); 15 | 16 | namespace String { 17 | template struct Num { 18 | std::array) + 1)> str; 19 | const size_t len; 20 | 21 | Num(T v) : len( 22 | sprintf(str.data(), "%0*u", static_cast(Width), v) 23 | ) { 24 | } 25 | }; 26 | } 27 | 28 | template std::u8string& StringCatNum( 29 | T num, std::u8string& out 30 | ) { 31 | String::Num n = { num }; 32 | return out.append(reinterpret_cast(n.str.data()), n.len); 33 | } 34 | -------------------------------------------------------------------------------- /game/surface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 2D surfaces 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/coords.h" 9 | 10 | struct SURFACE { 11 | PIXEL_SIZE size = { 0, 0 }; 12 | }; 13 | -------------------------------------------------------------------------------- /game/text.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common font rendering interface, independent of a specific rasterizer 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "constants.h" 9 | #include "game/coords.h" 10 | #include "game/enum_array.h" 11 | #include "game/graphics.h" 12 | #include "game/narrow.h" 13 | 14 | using TEXTRENDER_RECT_ID = unsigned int; 15 | 16 | // Concept for a text render session on a single rectangle, abstracting away 17 | // the rasterizer. 18 | template concept TEXTRENDER_SESSION_BASE = ( 19 | ENUMARRAY_ID && requires ( 20 | T t, 21 | PIXEL_POINT topleft_rel, 22 | Narrow::string_view str, 23 | RGB color, 24 | FONT_ID font 25 | ) { 26 | { t.RectSize() } -> std::same_as; 27 | 28 | t.SetFont(font); 29 | t.SetColor(color); 30 | 31 | // Calculates the width and height of [str] as rendered with the 32 | // current font. 33 | { t.Extent(str) } -> std::same_as; 34 | 35 | // Text display with the current color and font. [str] can be either 36 | // UTF-8 or Shift-JIS. 37 | t.Put(topleft_rel, str); 38 | 39 | // Convenience overload to change the color before rendering the text. 40 | t.Put(topleft_rel, str, color); 41 | } 42 | ); 43 | class TEXTRENDER_SESSION; 44 | 45 | // Horizontally centers [str] on [s]'s rectangle. 46 | PIXEL_COORD TextLayoutXCenter( 47 | TEXTRENDER_SESSION_BASE auto& s, Narrow::string_view str 48 | ) { 49 | return ((s.RectSize().w - s.Extent(str).w) / 2); 50 | } 51 | 52 | // Concept for a text rendering backend. 53 | template concept TEXTRENDER_BASE = requires( 54 | T t, 55 | FONT_ID font, 56 | PIXEL_SIZE size, 57 | WINDOW_POINT dst, 58 | Narrow::string_view contents, 59 | TEXTRENDER_RECT_ID rect_id, 60 | void (*func)(TEXTRENDER_SESSION&), 61 | std::optional subrect 62 | ) { 63 | // Rectangle management 64 | // -------------------- 65 | 66 | // Registers a new text rectangle of the given size, and returns a unique 67 | // ID to it on success. This ID is valid until the next Clear(). 68 | // This can resize the text surface on the next (pre-)rendering call if the 69 | // current one can't fit the new rectangle, which will clear any previously 70 | // rendered text rectangles. Therefore, it should only be called during 71 | // game state initialization. 72 | { t.Register(size) } -> std::same_as; 73 | 74 | // Invalidates all registered text rectangles. 75 | t.Clear(); 76 | // -------------------- 77 | 78 | // Forces the next (pre-)render call to clear all image data and recreate 79 | // the surface with the necessary size, but retaining all registered 80 | // rectangles. Necessary for mode switches. 81 | t.WipeBeforeNextRender(); 82 | 83 | // Calculates the width and height of [contents] as rendered with the given 84 | // font. 85 | { t.TextExtent(font, contents) } -> std::same_as; 86 | 87 | // Associates the results of [func] with the given [contents], thus caching 88 | // the result rendered to [rect_id]. [func] will only be called again if 89 | // the [contents] changed. 90 | 91 | t.Render(dst, rect_id, contents, func, subrect); 92 | }; 93 | -------------------------------------------------------------------------------- /game/text_packed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Rectangle management for text rendering by packing each rectangle into a 3 | * larger surface 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "game/text.h" 10 | 11 | class TEXTRENDER_PACKED { 12 | protected: 13 | struct RECT_AND_CONTENTS { 14 | PIXEL_LTWH rect; 15 | std::optional contents; 16 | }; 17 | 18 | PIXEL_SIZE bounds = {}; 19 | std::vector spaces; 20 | std::vector rects; 21 | 22 | template void SpaceAdd(T&& space) { 23 | if((space.w > 0) && (space.h > 0)) { 24 | spaces.emplace_back(std::forward(space)); 25 | } 26 | } 27 | 28 | // Inserts a rectangle of the given size, expanding the empty space as 29 | // needed. 30 | PIXEL_LTWH Insert(const PIXEL_SIZE& subrect_size); 31 | 32 | public: 33 | PIXEL_LTWH Subrect( 34 | TEXTRENDER_RECT_ID rect_id, std::optional maybe_subrect 35 | ); 36 | 37 | TEXTRENDER_RECT_ID Register(const PIXEL_SIZE& size); 38 | 39 | bool Wipe(); 40 | 41 | // Resets both bounds and empty spaces. 42 | void Clear(); 43 | 44 | bool Blit( 45 | WINDOW_POINT dst, 46 | TEXTRENDER_RECT_ID rect_id, 47 | std::optional subrect = std::nullopt 48 | ); 49 | 50 | template bool Render( 51 | this Self&& self, 52 | WINDOW_POINT dst, 53 | TEXTRENDER_RECT_ID rect_id, 54 | Narrow::string_view contents, 55 | std::invocable auto func, 56 | std::optional subrect = std::nullopt 57 | ) { 58 | assert(rect_id < self.rects.size()); 59 | auto& rect = self.rects[rect_id]; 60 | if(rect.contents != contents) { 61 | auto maybe_session = self.Session(rect_id); 62 | if(!maybe_session) { 63 | return false; 64 | } 65 | func(maybe_session.value()); 66 | rect.contents = contents; 67 | } 68 | return self.Blit(dst, rect_id, subrect); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /game/ut_math.h: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* UT_MATH.h 整数限定の数学関数群 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_UT_MATH_H 7 | #define PBGWIN_UT_MATH_H "UT_MATH : Version 0.01 : Update 1999/12/04" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | // 1999/12/05 : PBG_MATH.c より移植開始 13 | 14 | 15 | // 使用禁止かな // 16 | #ifndef DISABLE_UT_MATH 17 | 18 | 19 | // ヘッダファイル // 20 | import std.compat; 21 | 22 | 23 | // マクロ // 24 | #ifndef max 25 | #define max(a,b) ((a>b) ? (a) : (b)) 26 | #define min(a,b) ((a 0) ? SIN(deg) : 256)) 43 | int sinDiv(uint8_t deg, int length); 44 | 45 | // ((length * 256) / ((COS(deg) > 0) ? COS(deg) : 256)) 46 | int cosDiv(uint8_t deg, int length); 47 | 48 | uint8_t atan8(int x, int y); // 32ビット版です 49 | 50 | 51 | // 平方根(整数版) // 52 | // Calculates √[s], rounded to the nearest integer. 53 | int32_t isqrt(int32_t s); 54 | 55 | 56 | // 乱数 // 57 | void rnd_seed_set(uint32_t val); 58 | uint16_t rnd(void); 59 | 60 | 61 | // デバッグ用(後で消すこと) // 62 | //extern uint32_t random_ref; 63 | 64 | 65 | // 使用禁止かな // 66 | #endif 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /game/volume.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Volume handling 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | #include "game/cast.h" 10 | #include 11 | 12 | // Discrete volume values for MIDI and the UI. 13 | using VOLUME = uint8_t; 14 | 15 | static constexpr VOLUME VOLUME_MAX = 127; 16 | 17 | constexpr float VolumeLinear(VOLUME discrete) 18 | { 19 | return (discrete / float{ VOLUME_MAX }); 20 | } 21 | 22 | constexpr VOLUME VolumeDiscrete(float linear) 23 | { 24 | assert((linear >= 0.0f) && (linear <= 1.0f)); 25 | return Cast::down_sign((linear * VOLUME_MAX) + 0.5f); 26 | } 27 | 28 | // Maps a linear volume value to decibels, using the simple x² curve used by 29 | // the MIDI standard. 30 | inline const float VolumeDBSquare(float linear) 31 | { 32 | // Yup, MIDI does *not* use logarithmic curves for volume or expression. 33 | // The "Volume, Expression & Master Volume Response" section of the spec 34 | // defines the dB level exactly as `40 × log₁₀(volume / 127)`. A MIDI 35 | // volume of 64 therefore turns into -11.9 dB or an amplitude of 0.25, 36 | // which can also be observed on the Microsoft GS Wavetable Synth. 37 | return (40.0f * log10f(linear)); 38 | } 39 | 40 | // Maps a linear volume value to a sample multiplication factor, using the 41 | // simple x² curve used by the MIDI standard. 42 | constexpr float VolumeFactorSquare(float linear) 43 | { 44 | // The `40 × log₁₀(volume / 127)` curve corresponds to a simple (volume²) 45 | // when converted back to an amplitude, as outlined by 46 | // 47 | // https://music.stackexchange.com/a/123067 48 | // 49 | // Ironically, the spec then goes on to recommend an exponential function 50 | // for note *velocity*... 51 | return (linear * linear); 52 | } 53 | 54 | constexpr float VolumeFactorSquare(VOLUME discrete) 55 | { 56 | return VolumeFactorSquare(VolumeLinear(discrete)); 57 | } 58 | -------------------------------------------------------------------------------- /install_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$#" -lt 1 ]; then 4 | >&2 echo "Usage: ROOT= PATH_SKELETON= $0 APP_ID" 5 | exit 1 6 | fi 7 | 8 | set -x 9 | 10 | ROOT=${ROOT:-/usr} 11 | PATH_SKELETON=${PATH_SKELETON:-$ROOT/share/skel} 12 | 13 | install -Dm755 "./bin/GIAN07" -t "$ROOT/bin/" 14 | install -Dm644 "./bin/bgm/Folder structure.png" -t "$PATH_SKELETON/bgm/" 15 | install -Dm755 -d "$ROOT/share/applications/" 16 | sed "s//$1/" "./GIAN07/GIAN07.desktop.in" > "$ROOT/share/applications/$1.desktop" 17 | install -Dm644 "./art/016_box.png" "$ROOT/share/icons/hicolor/16x16/apps/$1.png" 18 | install -Dm644 "./art/032_text.png" "$ROOT/share/icons/hicolor/32x32/apps/$1.png" 19 | install -Dm644 "./art/048_text.png" "$ROOT/share/icons/hicolor/48x48/apps/$1.png" 20 | install -Dm644 "./art/128_text.png" "$ROOT/share/icons/hicolor/128x128/apps/$1.png" 21 | install -Dm644 "./LICENSE" -t "$ROOT/share/licenses/$1/" 22 | -------------------------------------------------------------------------------- /libs/9xcompat.lua: -------------------------------------------------------------------------------- 1 | local NINEXCOMPAT = sourcepath(tup.getcwd() .. "/9xcompat/") 2 | 3 | ---Builds the 9xcompat submodule. 4 | ---@param base_cfg Config 5 | ---@return ConfigShape 6 | function Build9xcompat(base_cfg) 7 | local cfg = base_cfg:branch({ 8 | cflags = { "/std:c++latest", "/GS-" }, 9 | lflags = { "kernel32.lib" }, 10 | }) 11 | 12 | -- 9xcompat doesn't make sense for DLL CRTs because it can't influence 13 | -- their imports. 14 | for index_or_buildtype, flag_or_vars in pairs(cfg.vars.cflags) do 15 | if (type(flag_or_vars) == "table") then 16 | for _, flag in pairs(flag_or_vars) do 17 | if flag:match("^/MD") then 18 | cfg.vars.cflags[index_or_buildtype] = nil 19 | cfg.buildtypes[index_or_buildtype] = nil 20 | break 21 | end 22 | end 23 | else 24 | if flag_or_vars:match("^/MD") then 25 | return {} 26 | end 27 | end 28 | end 29 | 30 | local compat_obj = cfg:cxx(NINEXCOMPAT.join("9xcompat.cpp")) 31 | local aliases_obj = tup.rule( 32 | NINEXCOMPAT.join("aliases.asm"), 33 | 'ml /nologo /c /Fo "%o" "%f"', 34 | (cfg.vars.objdir .. "9xcompat_%B.obj") 35 | ) 36 | 37 | -- Only add `aliases.obj` to the types we actually build. 38 | -- TODO: Won't be necessary once tupblocks has proper ASM support. 39 | local link = { linputs = compat_obj } 40 | for buildtype, fn in pairs(compat_obj) do 41 | link.linputs[buildtype] += aliases_obj[1] 42 | end 43 | return link 44 | end 45 | -------------------------------------------------------------------------------- /libs/BLAKE3.lua: -------------------------------------------------------------------------------- 1 | local BLAKE3 = sourcepath(tup.getcwd() .. "/BLAKE3/c/") 2 | 3 | ---Builds the BLAKE3 submodule. 4 | ---@param base_cfg Config 5 | ---@param generic integer Nonzero for a generic build without hand-written optimized versions for modern CPUs 6 | function BuildBLAKE3(base_cfg, generic) 7 | local arch = tup.getconfig("TUP_ARCH") 8 | local platform = tup.getconfig("TUP_PLATFORM") 9 | 10 | ---@type ConfigShape 11 | local link = { cflags = ("-I" .. BLAKE3.root) } 12 | 13 | ---@type ConfigShape 14 | local compile = { objdir = "BLAKE3/", cflags = {} } 15 | if (platform == "win32") then 16 | -- Visual C++ has no SSE4.1 flag, and I don't trust the /arch:AVX option 17 | compile.cflags += "/DBLAKE3_NO_SSE41" 18 | 19 | if (generic ~= 0) then 20 | compile.cflags += { 21 | "/DBLAKE3_NO_SSE2", "/DBLAKE3_NO_AVX2", "/DBLAKE3_NO_AVX512", 22 | } 23 | end 24 | end 25 | local cfg = base_cfg:branch(compile) 26 | local src 27 | src += BLAKE3.join("blake3.c") 28 | src += BLAKE3.join("blake3_dispatch.c") 29 | src += BLAKE3.join("blake3_portable.c") 30 | 31 | local obj = cfg:cc(src) 32 | if (generic == 0) then 33 | if (platform == "win32") then 34 | -- Each optimized version must be built with the matching MSVC 35 | -- `/arch` flag. This is not only necessary for the compiler to 36 | -- actually emit the intended instructions, but also prevents newer 37 | -- instruction sets from accidentally appearing in older code. (For 38 | -- example, globally setting `/arch:AVX512` for all of these files 39 | -- would cause AVX-512 instructions to also appear in the AVX2 40 | -- version, breaking it on those CPUs.) 41 | -- That's why they recommend the ASM versions, but they're 42 | -- 64-bit-exclusive… 43 | local arch_cfg_1 = cfg:branch({ cflags = "/arch:SSE2" }) 44 | local arch_cfg_2 = cfg:branch({ cflags = "/arch:AVX2" }) 45 | local arch_cfg_3 = cfg:branch({ cflags = "/arch:AVX512" }) 46 | obj = ( 47 | obj + 48 | arch_cfg_1:cc(BLAKE3.join("blake3_sse2.c")) + 49 | arch_cfg_2:cc(BLAKE3.join("blake3_avx2.c")) + 50 | arch_cfg_3:cc(BLAKE3.join("blake3_avx512.c")) 51 | ) 52 | else 53 | if (arch == "x86_64") then 54 | obj = (obj + cfg:cc(BLAKE3.glob("*unix.S"))) 55 | end 56 | end 57 | end 58 | link.linputs = cfg:lib(obj, "BLAKE3") 59 | return link 60 | end 61 | -------------------------------------------------------------------------------- /libs/BLAKE3.sparse-checkout: -------------------------------------------------------------------------------- 1 | c/ 2 | -------------------------------------------------------------------------------- /libs/SDL2.sparse-checkout: -------------------------------------------------------------------------------- 1 | include/ 2 | src/ 3 | -------------------------------------------------------------------------------- /libs/SDL3.sparse-checkout: -------------------------------------------------------------------------------- 1 | include/ 2 | src/ 3 | -------------------------------------------------------------------------------- /libs/dr_libs.sparse-checkout: -------------------------------------------------------------------------------- 1 | dr_flac.h 2 | -------------------------------------------------------------------------------- /libs/libogg.sparse-checkout: -------------------------------------------------------------------------------- 1 | include/ogg 2 | src/ 3 | -------------------------------------------------------------------------------- /libs/libvorbis.sparse-checkout: -------------------------------------------------------------------------------- 1 | include/vorbis/ 2 | lib/ 3 | -------------------------------------------------------------------------------- /libs/libwebp_lossless.lua: -------------------------------------------------------------------------------- 1 | local LIBWEBP = sourcepath(tup.getcwd() .. "/libwebp_lossless/") 2 | 3 | ---Builds the WebP encoder from the libwebp_lossless submodule. 4 | ---@param base_cfg Config 5 | ---@param generic integer Nonzero for a generic build without hand-written optimized versions for modern CPUs 6 | function BuildLibWebPLosslessEncode(base_cfg, generic) 7 | ---@type ConfigShape 8 | local link = { cflags = string.format("-I%ssrc", LIBWEBP.root) } 9 | 10 | local src = {} 11 | local cfg = base_cfg:branch(link, { 12 | cflags = { 13 | ("-I" .. LIBWEBP.root), 14 | "-DWEBP_DISABLE_STATS", 15 | "-DWEBP_NEAR_LOSSLESS=0", -- We want actual lossless, not "near" 16 | "-DWEBP_REDUCE_SIZE", 17 | 18 | -- WebP only uses multithreading for effort levels 8 and 9, where 19 | -- it does significantly boost performance. 20 | "-DWEBP_USE_THREAD", 21 | }, 22 | objdir = "libwebp/", 23 | }) 24 | if (generic ~= 0) then 25 | src.extra_inputs += Header((cfg.vars.objdir .. "src/webp/config.h"), { 26 | WEBP_HAVE_SSE2 = false, 27 | WEBP_HAVE_SSE41 = false, 28 | WEBP_HAVE_AVX2 = false, 29 | }) 30 | cfg = cfg:branch({ 31 | cflags = { 32 | ("-I" .. cfg.vars.objdir), 33 | "-DHAVE_CONFIG_H", 34 | "-DUSE_CREATE_THREAD", -- Avoid _beginthreadex() on Windows 9x 35 | }, 36 | }) 37 | end 38 | 39 | src += LIBWEBP.glob("src/dsp/alpha_processing*.c") 40 | src += LIBWEBP.glob("src/dsp/cpu.c") 41 | src += LIBWEBP.glob("src/dsp/enc*.c") 42 | src += LIBWEBP.glob("src/dsp/lossless*.c") 43 | src += (LIBWEBP.glob("src/enc/*.c") - { 44 | "picture_psnr_enc.c$", "near_lossless_enc.c$" 45 | }) 46 | src += (LIBWEBP.glob("src/utils/*.c") - { 47 | "bit_reader_utils.c$", 48 | "filters_utils.c$", 49 | "huffman_utils.c$", 50 | "rescaler_utils.c$", 51 | "quant_levels_dec_utils.c", 52 | "random_utils.c$", 53 | }) 54 | local _ = TableDrain(src, { "_neon.c$", "_mips.*.c$", "_msa.c$" }) 55 | local src_x86ext 56 | src_x86ext += TableDrain(src, { "_sse2.c$" }) 57 | src_x86ext += TableDrain(src, { "_sse41.c$" }) 58 | src_x86ext += TableDrain(src, { "_avx2.c$" }) 59 | local obj = cfg:cc(src) 60 | if (generic == 0) then 61 | -- Since Visual Studio sadly has no `/arch:SSE41` flag, we need to 62 | -- limit the optimizer to SSE2 levels. 63 | obj = (obj + cfg:branch({ cflags = "/arch:SSE2" }):cc(src_x86ext)) 64 | end 65 | 66 | link.linputs = cfg:lib(obj, "libwebp_lossless") 67 | return link 68 | end 69 | -------------------------------------------------------------------------------- /libs/libwebp_lossless.sparse-checkout: -------------------------------------------------------------------------------- 1 | src/ 2 | sharpyuv/ 3 | -------------------------------------------------------------------------------- /libs/miniaudio.sparse-checkout: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /libs/xiph.lua: -------------------------------------------------------------------------------- 1 | local LIBOGG = sourcepath(tup.getcwd() .. "/libogg/") 2 | local LIBVORBIS = sourcepath(tup.getcwd() .. "/libvorbis/") 3 | 4 | ---Builds the submodules for the Xiph audio codecs. 5 | ---@param base_cfg Config 6 | function BuildXiph(base_cfg) 7 | ---@type ConfigShape 8 | local link = { cflags = string.format( 9 | "-I%sinclude -I%sinclude", LIBOGG.root, LIBVORBIS.root 10 | ) } 11 | local libogg_cfg = base_cfg:branch(link, { objdir = "libogg/" }) 12 | local libogg_src = LIBOGG.glob("src/*.c") 13 | 14 | local libvorbis_cfg = base_cfg:branch(link, { objdir = "libvorbis/" }) 15 | local libvorbis_src = (LIBVORBIS.glob("lib/*.c") - { 16 | "barkmel.c$", "misc.c$", "psytune.c$", "tone.c$", "vorbisenc.c$" 17 | }) 18 | 19 | link.linputs = ( 20 | libogg_cfg:lib(libogg_cfg:cc(libogg_src), "libogg") + 21 | libogg_cfg:lib(libvorbis_cfg:cc(libvorbis_src), "libvorbis") 22 | ) 23 | return link 24 | end 25 | -------------------------------------------------------------------------------- /obj/dinput.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmlgc/ssg/3829b6d1f20d5279c50d7dbc9daaf3a111fc5e52/obj/dinput.lib -------------------------------------------------------------------------------- /platform/README.md: -------------------------------------------------------------------------------- 1 | Functionality that is implemented in terms of platform-specific system calls. 2 | If possible, game code should only include headers from this directory, not from any subdirectories. 3 | -------------------------------------------------------------------------------- /platform/buffer.h: -------------------------------------------------------------------------------- 1 | #include "platform/c/buffer.h" 2 | -------------------------------------------------------------------------------- /platform/c/README.md: -------------------------------------------------------------------------------- 1 | Implementations of the platform functions in terms of the C or C++ standard library, used as defaults for platforms that don't offer superior native methods. 2 | -------------------------------------------------------------------------------- /platform/c/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory ownership semantics 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | 10 | struct BYTE_BUFFER_BORROWED : public std::span { 11 | using span::span; 12 | 13 | template BYTE_BUFFER_BORROWED(std::span val) : 14 | span(reinterpret_cast(val.data()), val.size_bytes()) { 15 | } 16 | }; 17 | 18 | template < 19 | typename ConstOrNonConstByte 20 | > struct BYTE_BUFFER_CURSOR : public std::span { 21 | using std::span::span; 22 | 23 | template using transfer_const = std::conditional_t< 24 | std::is_const_v, const T, T 25 | >; 26 | 27 | size_t cursor = 0; 28 | 29 | // Required to work around a C26495 false positive, for some reason? 30 | BYTE_BUFFER_CURSOR(const std::span other) : 31 | std::span(other) { 32 | } 33 | 34 | // Reads up to [n] contiguous values of type T from the active cursor 35 | // position if possible. If the function returns a valid span, all [n] 36 | // objects are safe to access. 37 | template std::optional>> next( 38 | size_t n = 1 39 | ) { 40 | const auto cursor_new = (cursor + (sizeof(T) * n)); 41 | if((cursor_new > this->size()) || (cursor_new < cursor)) { 42 | return std::nullopt; 43 | } 44 | #pragma warning(suppress : 26473) // type.1 45 | auto ret = std::span>{ 46 | reinterpret_cast *>(this->data() + cursor), n 47 | }; 48 | cursor = cursor_new; 49 | return ret; 50 | } 51 | }; 52 | 53 | // Same semantics as the underlying unique_ptr: Can be either allocated or 54 | // empty. 55 | struct BYTE_BUFFER_OWNED : public std::unique_ptr { 56 | private: 57 | size_t size_; 58 | 59 | public: 60 | // Creates an empty buffer, with no allocation. 61 | BYTE_BUFFER_OWNED(std::nullptr_t null = nullptr) noexcept : 62 | std::unique_ptr(null), 63 | size_(0) { 64 | } 65 | 66 | // Tries to allocate [size] bytes, and leaves the buffer empty on failure. 67 | BYTE_BUFFER_OWNED(size_t size) : 68 | std::unique_ptr(new (std::nothrow) uint8_t[size]), 69 | size_(get() ? size : 0) { 70 | } 71 | 72 | auto size() const { 73 | return size_; 74 | } 75 | 76 | // Borrows a buffer with an immutable cursor. 77 | BYTE_BUFFER_CURSOR cursor() const { 78 | return { get(), size() }; 79 | } 80 | 81 | // Borrows a buffer with a mutable cursor. 82 | BYTE_BUFFER_CURSOR cursor_mut() { 83 | return { get(), size() }; 84 | } 85 | }; 86 | 87 | using BYTE_BUFFER_GROWABLE = std::vector; 88 | -------------------------------------------------------------------------------- /platform/c/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Threads via std::jthread 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | 10 | struct THREAD_STOP : public std::stop_token { 11 | explicit operator bool() const { 12 | return stop_requested(); 13 | } 14 | }; 15 | 16 | struct THREAD : public std::jthread { 17 | using std::jthread::jthread; 18 | 19 | bool Joinable() const noexcept { 20 | return joinable(); 21 | } 22 | void Join() { 23 | join(); 24 | } 25 | 26 | THREAD() noexcept = default; 27 | THREAD(THREAD&& other) noexcept = default; 28 | THREAD(const THREAD&) = delete; 29 | THREAD& operator=(THREAD&& other) noexcept = default; 30 | ~THREAD() { 31 | request_stop(); 32 | } 33 | }; 34 | 35 | [[nodiscard]] THREAD ThreadStart(std::invocable auto&& func) 36 | { 37 | return THREAD{ [func = std::move(func)](std::stop_token st) mutable { 38 | func(THREAD_STOP{ st }); 39 | } }; 40 | } 41 | -------------------------------------------------------------------------------- /platform/c/time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Time interface (std::chrono implementation) 3 | * 4 | */ 5 | 6 | #include "platform/time.h" 7 | #include 8 | 9 | uint32_t Time_SteadyTicksMS() 10 | { 11 | const auto now = (std::chrono::steady_clock::now().time_since_epoch()); 12 | return std::chrono::duration_cast(now).count(); 13 | } 14 | 15 | TIME_OF_DAY Time_NowLocal() 16 | { 17 | const auto ctime = std::time(nullptr); 18 | const auto& tm = *std::localtime(&ctime); 19 | 20 | // Signed integers! Yay! 21 | assert(tm.tm_year >= 0); 22 | assert(tm.tm_mon >= 0); 23 | assert(tm.tm_mday >= 0); 24 | assert(tm.tm_hour >= 0); 25 | assert(tm.tm_min >= 0); 26 | assert(tm.tm_sec >= 0); 27 | 28 | return TIME_OF_DAY{ 29 | .year = static_cast(1900 + tm.tm_year), 30 | .month = static_cast(1 + tm.tm_mon), 31 | .day = static_cast(tm.tm_mday), 32 | .hour = static_cast(tm.tm_hour), 33 | .minute = static_cast(tm.tm_min), 34 | .second = static_cast(tm.tm_sec), 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /platform/c/unicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode types for native system APIs (generic narrow/bag-of-bytes version) 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | 10 | using UNICODE_STRING = std::string; 11 | using UNICODE_STRING_VIEW = std::string_view; 12 | using UNICODE_LITERAL = const char *; 13 | #define _UNICODE(str) str 14 | -------------------------------------------------------------------------------- /platform/input.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Keyboard and pad input interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/input.h" 9 | 10 | // 関数プロトタイプ宣言 // 11 | bool Key_Start(void); // キー入力開始 12 | void Key_End(void); // キー入力終了 13 | 14 | void Key_Read(void); 15 | 16 | // Returns: 17 | // • ≥1: ID of the single gamepad button that is being pressed 18 | // • 0: More than one gamepad button is being pressed 19 | // • std::nullopt: No gamepad button is being pressed 20 | std::optional Key_PadSingle(void); 21 | -------------------------------------------------------------------------------- /platform/midi_backend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Platform-specific MIDI backend interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #ifdef WIN32 9 | #define SUPPORT_MIDI_BACKEND 10 | #endif 11 | 12 | #ifdef SUPPORT_MIDI_BACKEND 13 | 14 | import std.compat; 15 | #include "game/narrow.h" 16 | 17 | // Initializes the backend with a default output device. 18 | bool MidBackend_Init(void); // MIDI関連初期化 19 | 20 | // Shuts down the backend. 21 | void MidBackend_Cleanup(void); // MIDI関連おしまい 22 | 23 | // Returns the name of the current MIDI device, or std::nullopt if the backend 24 | // is not initialized. Can also be used for general initialization checks. 25 | std::optional MidBackend_DeviceName(void); 26 | 27 | // Switches to the next working output device in the given positive or negative 28 | // [direction]. 29 | bool MidBackend_DeviceChange(int8_t direction); // 出力デバイスを変更する 30 | 31 | // Starts a timer that periodically calls Mid_Proc(). 32 | void MidBackend_StartTimer(void); 33 | 34 | // Stops the timer. 35 | void MidBackend_StopTimer(void); 36 | 37 | // Sends a raw MIDI event to the active device. [event] unfortunately has to be 38 | // mutable because MIDIHDR on Windows wants a non-const pointer... 39 | void MidBackend_Out(uint8_t byte_1, uint8_t byte_2, uint8_t byte_3 = 0x00); 40 | void MidBackend_Out(std::span event); 41 | 42 | // Stops all currently playing notes. 43 | void MidBackend_Panic(void); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /platform/miniaudio/flags.h: -------------------------------------------------------------------------------- 1 | /* 2 | * miniaudio configuration 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #define MA_NO_ENCODING 9 | #define MA_NO_GENERATION 10 | #define MA_NO_RESOURCE_MANAGER 11 | #define MA_NO_FLAC 12 | #define MA_NO_MP3 13 | #define MA_NO_NULL 14 | #ifdef WIN32_VINTAGE 15 | #define MA_NO_WASAPI 16 | #endif 17 | 18 | // Slightly crispier than what you'd get with DirectSound, but 2 would already 19 | // come with fewer high frequencies in comparison. 20 | #define MA_DEFAULT_RESAMPLER_LPF_ORDER 1 21 | -------------------------------------------------------------------------------- /platform/miniaudio/miniaudio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * miniaudio compilation 3 | * 4 | */ 5 | 6 | #include "platform/miniaudio/flags.h" 7 | #include 8 | -------------------------------------------------------------------------------- /platform/pangocairo/text_pangocairo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Text rendering via Pango/Cairo 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/text_packed.h" 9 | #include "platform/graphics_backend.h" 10 | 11 | class TEXTRENDER_SESSION { 12 | protected: 13 | PIXEL_POINT tex_origin; 14 | PIXEL_SIZE size; 15 | FONT_ID font_cur = FONT_ID::COUNT; 16 | RGB color_cur = { 0, 0, 0 }; 17 | 18 | public: 19 | class PIXELACCESS { 20 | friend class TEXTRENDER_SESSION; 21 | 22 | uint8_t *buf; 23 | int stride; 24 | 25 | PIXELACCESS(void); 26 | uint32_t& PixelAt(const PIXEL_POINT& xy_rel); 27 | 28 | public: 29 | uint32_t GetRaw(const PIXEL_POINT& xy_rel); 30 | void SetRaw(const PIXEL_POINT& xy_rel, uint32_t col); 31 | 32 | RGB Get(const PIXEL_POINT& xy_rel); 33 | void Set(const PIXEL_POINT& xy_rel, const RGB col); 34 | 35 | ~PIXELACCESS(void); 36 | }; 37 | 38 | PIXEL_SIZE RectSize(void) const; 39 | void SetFont(FONT_ID font); 40 | void SetColor(const RGB& color); 41 | PIXEL_SIZE Extent(Narrow::string_view str); 42 | void Put( 43 | const PIXEL_POINT& topleft_rel, 44 | Narrow::string_view str, 45 | std::optional color = std::nullopt 46 | ); 47 | auto PixelAccess(std::invocable auto f) { 48 | PIXELACCESS p; 49 | return f(p); 50 | } 51 | 52 | TEXTRENDER_SESSION(const PIXEL_LTWH rect); 53 | ~TEXTRENDER_SESSION(); 54 | }; 55 | 56 | class TEXTRENDER : public TEXTRENDER_PACKED { 57 | friend class TEXTRENDER_PACKED; 58 | 59 | std::optional Session(TEXTRENDER_RECT_ID rect_id); 60 | 61 | public: 62 | void WipeBeforeNextRender(); 63 | PIXEL_SIZE TextExtent(FONT_ID font, Narrow::string_view str); 64 | }; 65 | -------------------------------------------------------------------------------- /platform/path.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common paths 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | 10 | // Returns the directory containing the game's data. Guaranteed to end with the 11 | // native directory separator. Can be the empty string on platforms with no 12 | // concept of a base data directory. 13 | std::u8string_view PathForData(void); 14 | -------------------------------------------------------------------------------- /platform/sdl/graphics_sdl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Graphics via SDL_Renderer 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "platform/graphics_backend.h" 9 | 10 | class GRAPHICS_GEOMETRY_SDL : public GRAPHICS_GEOMETRY { 11 | public: 12 | // Generic methods 13 | // --------------- 14 | 15 | void Lock(void) final; 16 | void Unlock(void) final; 17 | void SetColor(RGB216 col) final; 18 | void SetAlphaNorm(uint8_t a) final; 19 | void SetAlphaOne(void) final; 20 | void DrawLine(int x1, int y1, int x2, int y2) final; 21 | void DrawBox(int x1, int y1, int x2, int y2) final; 22 | void DrawBoxA(int x1, int y1, int x2, int y2) final; 23 | void DrawTriangleFan(VERTEX_XY_SPAN<>) final; 24 | // ---------- 25 | 26 | // Poly methods 27 | // ------------ 28 | 29 | void DrawLineStrip(VERTEX_XY_SPAN<>); 30 | void DrawTriangles( 31 | TRIANGLE_PRIMITIVE, VERTEX_XY_SPAN<>, VERTEX_RGBA_SPAN<> colors = {} 32 | ); 33 | void DrawTrianglesA( 34 | TRIANGLE_PRIMITIVE, VERTEX_XY_SPAN<>, VERTEX_RGBA_SPAN<> colors = {} 35 | ); 36 | void DrawGrdLineEx(int x, int y1, RGB c1, int y2, RGB c2); 37 | // ------------ 38 | 39 | // Framebuffer methods 40 | // ------------------- 41 | // Just required to satisfy the framebuffer concept, since our GrpGeom_FB() 42 | // also returns a pointer to this class. 43 | 44 | void DrawPoint(WINDOW_POINT p); 45 | void DrawHLine(int x1, int x2, int y); 46 | // ------------------- 47 | }; 48 | 49 | extern GRAPHICS_GEOMETRY_SDL GrpGeomSDL; 50 | #define GrpGeom (&GrpGeomSDL) 51 | 52 | GRAPHICS_GEOMETRY_SDL *GrpGeom_Poly(void); 53 | GRAPHICS_GEOMETRY_SDL *GrpGeom_FB(void); 54 | 55 | // Must be kept in sync with the hardcoded ones in the SDL_GL_ResetAttributes() 56 | // implementation. 57 | #define OPENGL_TARGET_CORE_MAJ 2 58 | #define OPENGL_TARGET_CORE_MIN 1 59 | #define OPENGL_TARGET_ES1_MIN 1 60 | #define OPENGL_TARGET_ES2_MIN 0 61 | 62 | #undef SUPPORT_GRP_BITDEPTH 63 | #define SUPPORT_GRP_SCALING 64 | #define SUPPORT_GRP_WINDOWED 65 | #define SUPPORT_GRP_API 66 | -------------------------------------------------------------------------------- /platform/sdl/log_sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Internal logging helpers for the SDL platform 3 | * 4 | */ 5 | 6 | // SDL headers must come first to avoid import→#include bugs on Clang 19. 7 | #ifdef SDL3 8 | #include 9 | #else 10 | #include 11 | #endif 12 | #include "platform/sdl/sdl2_wrap.h" 13 | 14 | #include "platform/sdl/log_sdl.h" 15 | 16 | const char *log_title = nullptr; 17 | SDL_LogOutputFunction log_default_func; 18 | void *log_default_data; 19 | 20 | void SDLCALL LogCriticalAsMessageBox( 21 | void *userdata, int category, SDL_LogPriority priority, const char *message 22 | ) 23 | { 24 | if(priority == SDL_LOG_PRIORITY_CRITICAL) { 25 | SDL_ShowSimpleMessageBox( 26 | SDL_MESSAGEBOX_ERROR, log_title, message, nullptr 27 | ); 28 | } else { 29 | log_default_func(log_default_data, category, priority, message); 30 | } 31 | } 32 | 33 | void Log_Init(const char8_t *title) 34 | { 35 | log_title = reinterpret_cast(title); 36 | 37 | // The easiest workaround for SDL_ShowSimpleMessageBox()'s lack of built-in 38 | // string interpolation: Route errors through the log system instead. 39 | SDL_GetLogOutputFunction(&log_default_func, &log_default_data); 40 | SDL_SetLogOutputFunction(LogCriticalAsMessageBox, nullptr); 41 | } 42 | 43 | void Log_Fail(SDL_LogCategory category, const char *msg) 44 | { 45 | SDL_LogCritical(category, "%s: %s", msg, SDL_GetError()); 46 | } 47 | -------------------------------------------------------------------------------- /platform/sdl/log_sdl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Internal logging helpers for the SDL platform 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | 10 | #ifdef SDL3 11 | #include 12 | #else 13 | #include 14 | #endif 15 | 16 | void Log_Init(const char8_t *title); 17 | 18 | // Logs [msg] together with the last SDL_GetError() as a critical error. 19 | void Log_Fail(SDL_LogCategory category, const char *msg); 20 | -------------------------------------------------------------------------------- /platform/sdl/path_sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Common paths as determined by SDL's path functions 3 | * 4 | */ 5 | 6 | // SDL headers must come first to avoid import→#include bugs on Clang 19. 7 | #ifdef SDL3 8 | #include 9 | #else 10 | #include 11 | #endif 12 | 13 | #include "platform/path.h" 14 | #include "constants.h" 15 | 16 | #if (!defined(WIN32) || !defined(SDL3)) 17 | constexpr auto SDL_free_deleter = [](auto* p) { SDL_free(p); }; 18 | static std::unique_ptr PathData = { 19 | nullptr 20 | }; 21 | #endif 22 | static std::u8string_view PathDataView; 23 | 24 | std::u8string_view PathForData(void) 25 | { 26 | if(PathDataView.data() != nullptr) { 27 | return PathDataView; 28 | } 29 | #ifdef WIN32 30 | #ifdef SDL3 31 | PathDataView = std::bit_cast(SDL_GetBasePath()); 32 | #else 33 | PathData.reset(std::bit_cast(SDL_GetBasePath())); 34 | PathDataView = PathData.get(); 35 | #endif 36 | #else 37 | #ifdef PATH_XDG_DATA_HOME_HAS_APP_ID 38 | auto* path_base = SDL_GetPrefPath(nullptr, ""); 39 | #else 40 | auto* path_base = SDL_GetPrefPath(GAME_ORG, GAME_APP); 41 | #endif 42 | PathData.reset(std::bit_cast(path_base)); 43 | PathDataView = PathData.get(); 44 | 45 | // Remove the unsightly second slash in case we passed an empty app 46 | if(PathDataView.ends_with(u8"//")) { 47 | PathDataView.remove_suffix(1); 48 | } 49 | #endif 50 | 51 | return PathDataView; 52 | } 53 | -------------------------------------------------------------------------------- /platform/sdl/sdl2_wrap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SDL 2 compatibility wrappers 3 | * 4 | * This backend is primarily written against SDL 3. This header abstracts 5 | * away some of the changes to make it compile with SDL 2 – the inverse of 6 | * sdl2-compat, so to speak. 7 | */ 8 | 9 | #pragma once 10 | 11 | #ifdef SDL3 12 | inline constexpr bool HelpFailed(bool sdl_ret) 13 | { 14 | return !sdl_ret; 15 | } 16 | #else 17 | inline constexpr bool HelpFailed(int sdl_ret) 18 | { 19 | return (sdl_ret != 0); 20 | } 21 | 22 | // Yeah, `using` would be cleaner, but it rightfully refuses to override the 23 | // `SDL_PixelFormat` struct definition from SDL 2... 24 | #define SDL_PixelFormat Uint32 25 | 26 | using SDL_DisplayID = int; 27 | 28 | // Renamed constants 29 | // ----------------- 30 | 31 | #define SDL_EVENT_FIRST SDL_FIRSTEVENT 32 | #define SDL_EVENT_JOYSTICK_ADDED SDL_JOYDEVICEADDED 33 | #define SDL_EVENT_JOYSTICK_AXIS_MOTION SDL_JOYAXISMOTION 34 | #define SDL_EVENT_JOYSTICK_BUTTON_DOWN SDL_JOYBUTTONDOWN 35 | #define SDL_EVENT_JOYSTICK_BUTTON_UP SDL_JOYBUTTONUP 36 | #define SDL_EVENT_JOYSTICK_REMOVED SDL_JOYDEVICEREMOVED 37 | #define SDL_EVENT_KEY_DOWN SDL_KEYDOWN 38 | #define SDL_EVENT_KEY_UP SDL_KEYUP 39 | #define SDL_EVENT_LAST SDL_LASTEVENT 40 | #define SDL_EVENT_QUIT SDL_QUIT 41 | #define SDL_EVENT_WINDOW_FOCUS_GAINED SDL_WINDOWEVENT_FOCUS_GAINED 42 | #define SDL_EVENT_WINDOW_FOCUS_LOST SDL_WINDOWEVENT_FOCUS_LOST 43 | #define SDL_KMOD_LALT KMOD_LALT 44 | #define SDL_KMOD_SCROLL KMOD_SCROLL 45 | #define SDL_SCALEMODE_LINEAR SDL_ScaleModeBest 46 | #define SDL_SCALEMODE_NEAREST SDL_ScaleModeNearest 47 | #define SDL_SCANCODE_COUNT SDL_NUM_SCANCODES 48 | // ----------------- 49 | 50 | inline SDL_Surface *SDL_CreateSurface(int w, int h, SDL_PixelFormat format) 51 | { 52 | return SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, format); 53 | } 54 | 55 | // Renamed functions 56 | // ----------------- 57 | 58 | #define SDL_CloseGamepad SDL_GameControllerClose 59 | #define SDL_CloseJoystick SDL_JoystickClose 60 | #define SDL_DestroySurface SDL_FreeSurface 61 | #define SDL_FlushRenderer SDL_RenderFlush 62 | #define SDL_GetJoystickFromID SDL_JoystickFromInstanceID 63 | #define SDL_GetLogOutputFunction SDL_LogGetOutputFunction 64 | #define SDL_GetRenderScale SDL_RenderGetScale 65 | #define SDL_GetTicks SDL_GetTicks64 66 | #define SDL_IOFromMem SDL_RWFromMem 67 | #define SDL_IsGamepad SDL_IsGameController 68 | #define SDL_LoadBMP_IO SDL_LoadBMP_RW 69 | #define SDL_OpenGamepad SDL_GameControllerOpen 70 | #define SDL_OpenJoystick SDL_JoystickOpen 71 | #define SDL_RenderFillRect SDL_RenderFillRectF 72 | #define SDL_RenderLine SDL_RenderDrawLine 73 | #define SDL_RenderLines SDL_RenderDrawLinesF 74 | #define SDL_RenderTexture SDL_RenderCopy 75 | #define SDL_SetLogOutputFunction SDL_LogSetOutputFunction 76 | #define SDL_SetLogPriorities SDL_LogSetAllPriority 77 | #define SDL_SetRenderClipRect SDL_RenderSetClipRect 78 | #define SDL_SetSurfaceColorKey SDL_SetColorKey 79 | // ----------------- 80 | #endif 81 | -------------------------------------------------------------------------------- /platform/sdl/thread_sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Threads via SDL 3 | * 4 | */ 5 | 6 | #ifdef SDL3 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #include "platform/sdl/thread_sdl.h" 13 | 14 | THREAD::THREAD(SDL_Thread *sdl_thread, std::unique_ptr st) : 15 | sdl_thread(sdl_thread), st(std::move(st)) 16 | { 17 | } 18 | 19 | THREAD::THREAD(THREAD&& other) noexcept 20 | { 21 | *this = std::move(other); 22 | } 23 | 24 | THREAD& THREAD::operator=(THREAD&& other) noexcept 25 | { 26 | // Must turn this instance to an empty thread to avoid double-frees when 27 | // calling the destructor. 28 | sdl_thread = std::exchange(other.sdl_thread, nullptr); 29 | st = std::exchange(other.st, nullptr); 30 | return *this; 31 | }; 32 | 33 | THREAD::~THREAD() 34 | { 35 | Abort(); 36 | } 37 | 38 | SDL_Thread *HelpCreateThread(int(*fn)(void *), void *data) 39 | { 40 | return SDL_CreateThread(fn, "", data); 41 | } 42 | 43 | bool THREAD::Joinable() const noexcept 44 | { 45 | return (sdl_thread != nullptr); 46 | } 47 | 48 | void THREAD::Join() noexcept 49 | { 50 | if(sdl_thread) { 51 | SDL_WaitThread(sdl_thread, nullptr); 52 | sdl_thread = nullptr; 53 | } 54 | } 55 | 56 | void THREAD::Abort() noexcept 57 | { 58 | if(st) { 59 | st->store(true); 60 | } 61 | Join(); 62 | } 63 | -------------------------------------------------------------------------------- /platform/sdl/thread_sdl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Threads via SDL 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | struct SDL_Thread; 10 | 11 | using THREAD_STOP = std::atomic; 12 | 13 | template F> struct THREAD_META { 14 | F f; 15 | THREAD_STOP& st; 16 | }; 17 | 18 | class THREAD { 19 | SDL_Thread *sdl_thread = nullptr; 20 | std::unique_ptr st; 21 | 22 | public: 23 | bool Joinable() const noexcept; 24 | void Join() noexcept; 25 | void Abort() noexcept; 26 | 27 | THREAD() noexcept = default; 28 | THREAD(SDL_Thread *sdl_thread, std::unique_ptr st); 29 | THREAD(THREAD&& other) noexcept; 30 | THREAD(const THREAD&) = delete; 31 | THREAD& operator=(THREAD&& other) noexcept; 32 | ~THREAD(); 33 | }; 34 | 35 | SDL_Thread *HelpCreateThread(int(*fn)(void *), void *data); 36 | 37 | template F> int ThreadFunc(void *data) 38 | { 39 | // Wrap the leaked functor into a `unique_ptr` to destroy both `F` and 40 | // [meta] upon returning. 41 | const std::unique_ptr> meta( 42 | static_cast *>(data) 43 | ); 44 | 45 | meta.get()->f(meta.get()->st); 46 | return 0; 47 | } 48 | 49 | template < 50 | std::invocable F 51 | > [[nodiscard]] THREAD ThreadStart(F&& f) 52 | { 53 | // Note the two distinct lifetimes here: 54 | // 55 | // • [st] must live as long as the returned `THREAD`. It must also be at a 56 | // fixed location in memory since we pass it by pointer to ThreadFunc(), 57 | // and this pointer must be preserved across assignment operations. 58 | // 59 | // • [meta] must destroy itself at the end of [f] to run `F`'s destructor. 60 | // It must also be a pointer because SDL_CreateThread() only takes a 61 | // single parameter and we must pass two fields that can't be on the 62 | // stack, as this function might have long returned by the time the new 63 | // thread starts executing. 64 | auto st = std::make_unique(); 65 | auto meta = std::make_unique>(std::forward(f), *st.get()); 66 | auto sdl_thread = HelpCreateThread(ThreadFunc, meta.get()); 67 | if(!sdl_thread) { 68 | return {}; 69 | } 70 | // Ownership is now managed on the thread 71 | meta.release(); 72 | return THREAD{ sdl_thread, std::move(st) }; 73 | } 74 | -------------------------------------------------------------------------------- /platform/sdl/urlopen_sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * URL opener 3 | * 4 | */ 5 | 6 | #include "platform/urlopen.h" 7 | #ifdef SDL3 8 | #include 9 | #else 10 | #include 11 | #endif 12 | 13 | void URLOpen(const char* url) 14 | { 15 | SDL_OpenURL(url); 16 | } 17 | -------------------------------------------------------------------------------- /platform/sdl/window_sdl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SDL window creation 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #ifdef SDL3 9 | #include 10 | #else 11 | #include 12 | #endif 13 | #include "platform/sdl/sdl2_wrap.h" 14 | #include "game/graphics.h" 15 | 16 | // We can't retrieve the original window position in fullscreen mode via 17 | // SDL_GetWindowPosition(), so let's back it up before we go fullscreen. 18 | // Also helpful because these coordinates determine the display that the 19 | // fullscreen window is placed on. 20 | extern std::optional> TopleftBeforeFullscreen; 21 | 22 | // Falls back to the primary display if the window doesn't exist yet. 23 | SDL_DisplayID HelpGetDisplayForWindow(void); 24 | 25 | std::pair HelpGetWindowPosition(SDL_Window *window); 26 | 27 | // Returns the SDL render driver index that matches [hint]. If the hint doesn't 28 | // match any driver, the function resets SDL's render driver hints and returns 29 | // -1. 30 | int8_t WndBackend_ValidateRenderDriver(const std::u8string_view hint); 31 | 32 | // Looks like it belongs into `graphics_sdl`, but is also needed for window 33 | // creation. 34 | std::u8string_view WndBackend_SDLRendererName(int8_t id); 35 | 36 | #ifdef SDL3 37 | // Returns the new active fullscreen flags if the mode change was successful. 38 | [[nodiscard]] std::optional HelpSetFullscreenMode( 39 | SDL_Window *window, GRAPHICS_FULLSCREEN_FLAGS fs 40 | ); 41 | #else 42 | static constexpr Uint32 HelpFullscreenFlag(const GRAPHICS_FULLSCREEN_FLAGS& fs) 43 | { 44 | return (!fs.fullscreen ? 0 : 45 | (fs.exclusive ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP) 46 | ); 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /platform/snd_backend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Platform-specific PCM sound interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/snd.h" 9 | 10 | bool SndBackend_Init(void); 11 | void SndBackend_Cleanup(void); 12 | 13 | // The platform-independent layer always calls this after SndBackend_Init(). 14 | bool SndBackend_BGMInit(void); 15 | 16 | // The platform-independent layer always calls this before SndBackend_Cleanup(). 17 | void SndBackend_BGMCleanup(void); 18 | 19 | void SndBackend_BGMUpdateVolume(void); 20 | 21 | namespace BGM { 22 | struct TRACK; 23 | } 24 | bool SndBackend_BGMLoad(std::shared_ptr track); 25 | void SndBackend_BGMPlay(void); 26 | void SndBackend_BGMStop(void); 27 | 28 | // Returns the amount of milliseconds that the subsystem has been playing the 29 | // BGM track for. 30 | std::chrono::milliseconds SndBackend_BGMPlayTime(void); 31 | 32 | void SndBackend_BGMUpdateVolume(void); 33 | void SndBackend_BGMUpdateTempo(void); 34 | 35 | // The platform-independent layer always calls this after SndBackend_Init(). 36 | bool SndBackend_SEInit(void); 37 | 38 | // The platform-independent layer always calls this before SndBackend_Cleanup(). 39 | void SndBackend_SECleanup(void); 40 | 41 | void SndBackend_SEUpdateVolume(void); 42 | 43 | bool SndBackend_SELoad( 44 | BYTE_BUFFER_OWNED buffer, uint8_t id, SND_INSTANCE_ID max 45 | ); 46 | void SndBackend_SEPlay(uint8_t id, int x = SND_X_MID, bool loop = false); 47 | void SndBackend_SEStop(uint8_t id); 48 | 49 | // Pause or resume all playing sounds if the window loses focus 50 | void SndBackend_PauseAll(); 51 | void SndBackend_ResumeAll(); 52 | -------------------------------------------------------------------------------- /platform/text_backend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Platform-specific text rendering backend 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/graphics.h" 9 | 10 | // Concept for pixel access within a text rendering session. Offers access 11 | // using both RGB colors and the raw underlying format. 12 | template concept TEXTRENDER_SESSION_PIXELACCESS_BASE = requires( 13 | T t, PIXEL_POINT xy_rel, decltype(t.GetRaw(xy_rel)) color_raw, RGB color 14 | ) { 15 | { t.GetRaw(xy_rel) } -> std::same_as; 16 | t.SetRaw(xy_rel, color_raw); 17 | 18 | { t.Get(xy_rel) } -> std::same_as; 19 | t.Set(xy_rel, color); 20 | }; 21 | 22 | #ifdef WIN32 23 | #include "platform/windows/text_gdi.h" 24 | #elif defined(LINUX) 25 | #include "platform/pangocairo/text_pangocairo.h" 26 | #endif 27 | 28 | static_assert( 29 | TEXTRENDER_SESSION_PIXELACCESS_BASE 30 | ); 31 | static_assert(TEXTRENDER_SESSION_BASE); 32 | static_assert(TEXTRENDER_BASE); 33 | 34 | extern TEXTRENDER TextObj; 35 | 36 | // Shuts down the backend, deleting all fonts. 37 | void TextBackend_Cleanup(void); 38 | -------------------------------------------------------------------------------- /platform/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Platform-specific thread interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "platform/sdl/thread_sdl.h" 9 | -------------------------------------------------------------------------------- /platform/time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Platform-specific time interface 3 | * 4 | */ 5 | 6 | import std.compat; 7 | 8 | struct TIME_OF_DAY { 9 | uint32_t year; 10 | uint8_t month; // 1-based 11 | uint8_t day; // 1-based 12 | uint8_t hour; 13 | uint8_t minute; 14 | uint8_t second; 15 | }; 16 | 17 | // Returns some kind of steady system tick value in milliseconds. 18 | uint32_t Time_SteadyTicksMS(); 19 | 20 | // Returns the current local system time. 21 | TIME_OF_DAY Time_NowLocal(); 22 | -------------------------------------------------------------------------------- /platform/unicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode types for native system APIs 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #ifdef WIN32 9 | #include "platform/windows/unicode.h" 10 | #else 11 | #include "platform/c/unicode.h" 12 | #endif 13 | 14 | using UNICODE_CODEUNIT = UNICODE_STRING::value_type; 15 | 16 | using PATH_STRING = UNICODE_STRING; 17 | using PATH_STRING_VIEW = UNICODE_STRING_VIEW; 18 | using PATH_LITERAL = UNICODE_LITERAL; 19 | using PATH_CODEUNIT = UNICODE_CODEUNIT; 20 | #define _PATH _UNICODE 21 | -------------------------------------------------------------------------------- /platform/urlopen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * URL opener 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | // Opens a browser at the specific URL. 9 | void URLOpen(const char* url); 10 | -------------------------------------------------------------------------------- /platform/window_backend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Platform-specific window backend interface 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std.compat; 9 | struct GRAPHICS_PARAMS; 10 | 11 | // Initialization 12 | // -------------- 13 | // Just here to support switchable window backends for certain graphics 14 | // backends. 15 | 16 | typedef struct SDL_Window SDL_Window; 17 | 18 | // Returns the SDL handle of the current window. 19 | SDL_Window *WndBackend_SDL(void); 20 | 21 | // Creates the game window and returns the actual configuration the backend is 22 | // running. Fails if the window already exists. 23 | std::optional WndBackend_Create(GRAPHICS_PARAMS); 24 | 25 | #ifdef WIN32_VINTAGE 26 | #include 27 | 28 | // Returns the Win32 handle of the current window. 29 | HWND WndBackend_Win32(void); 30 | #endif 31 | 32 | void WndBackend_Cleanup(void); 33 | // -------------- 34 | 35 | // Returns the current top-left position of the game window. 36 | std::optional> WndBackend_Topleft(void); 37 | 38 | // Runs the main loop each frame, and returns the exit code after the game was 39 | // quit. 40 | int WndBackend_Run(void); 41 | -------------------------------------------------------------------------------- /platform/windows/surface_gdi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 2D surfaces via GDI bitmaps 3 | * 4 | */ 5 | 6 | #include "platform/windows/surface_gdi.h" 7 | #include "platform/file.h" 8 | #include "game/format_bmp.h" 9 | #include 10 | #include // for offsetof() 11 | 12 | #pragma comment(lib, "gdi32.lib") 13 | #pragma comment(lib, "user32.lib") 14 | 15 | SURFACE_GDI::SURFACE_GDI() noexcept : 16 | dc(CreateCompatibleDC(GetDC(nullptr))) 17 | { 18 | } 19 | 20 | SURFACE_GDI::~SURFACE_GDI() 21 | { 22 | Delete(); 23 | DeleteDC(dc); 24 | } 25 | 26 | static_assert(sizeof(RGBQUAD) == sizeof(BGRA)); 27 | static_assert(offsetof(RGBQUAD, rgbBlue) == offsetof(BGRA, b)); 28 | static_assert(offsetof(RGBQUAD, rgbGreen) == offsetof(BGRA, g)); 29 | static_assert(offsetof(RGBQUAD, rgbRed) == offsetof(BGRA, r)); 30 | static_assert(offsetof(RGBQUAD, rgbReserved) == offsetof(BGRA, a)); 31 | 32 | bool SURFACE_GDI::Save(FILE_STREAM_WRITE* stream) const 33 | { 34 | if(!stream) { 35 | return false; 36 | } 37 | 38 | DIBSECTION dib; 39 | if(!GetObject(img, sizeof(DIBSECTION), &dib)) { 40 | return false; 41 | } 42 | 43 | if((dib.dsBm.bmHeight < 0) || (dib.dsBm.bmWidthBytes < 0)) { 44 | assert(!"Negative height or stride?"); 45 | return false; 46 | } 47 | 48 | const auto bpp = (dib.dsBm.bmPlanes * dib.dsBm.bmBitsPixel); 49 | const auto palette_size = BMPPaletteSizeFromBPP(bpp); 50 | 51 | if(!dib.dsBm.bmBits) { 52 | // This is a DDB, not a DIB, which means that the BITMAPINFOHEADER 53 | // structure is invalid. Reconstruct it from what we have. 54 | // Adapted from 55 | // 56 | // https://learn.microsoft.com/en-us/windows/win32/gdi/storing-an-image 57 | const PIXEL_SIZE size = { dib.dsBm.bmWidth, dib.dsBm.bmHeight }; 58 | 59 | // GetDIBits() will write the color table after the BITMAPINFOHEADER 60 | // structure. 61 | std::vector info_buf( 62 | sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * palette_size) 63 | ); 64 | 65 | auto* info = reinterpret_cast(info_buf.data()); 66 | const std::span palette = { 67 | reinterpret_cast(&info[1]), palette_size 68 | }; 69 | 70 | // According to MSDN, we explicitly only need the first 6 members. 71 | // GetDIBits() overwrites the rest anyway. 72 | *info = { 73 | .biSize = sizeof(dib.dsBmih), 74 | .biWidth = size.w, 75 | .biHeight = size.h, 76 | .biPlanes = dib.dsBm.bmPlanes, 77 | .biBitCount = dib.dsBm.bmBitsPixel, 78 | .biCompression = BI_RGB, 79 | }; 80 | info->biSizeImage = (info->Stride() * info->biHeight); 81 | 82 | std::vector pixels(info->biSizeImage); 83 | auto* bmi = reinterpret_cast(info); 84 | if(!GetDIBits(dc, img, 0, size.h, pixels.data(), bmi, DIB_RGB_COLORS)) { 85 | assert(!"GetDIBits failed"); 86 | return false; 87 | } 88 | return BMPSave( 89 | stream, size, info->biPlanes, info->biBitCount, palette, pixels 90 | ); 91 | } 92 | 93 | // For DIBs, we get direct access to the pixel data. 94 | std::array bgra; 95 | std::span palette = {}; 96 | const auto color_table_ret = GetDIBColorTable( 97 | dc, 0, palette_size, reinterpret_cast(bgra.data()) 98 | ); 99 | if(color_table_ret == palette_size) { 100 | palette = bgra; 101 | } 102 | const std::span pixels = { 103 | static_cast(dib.dsBm.bmBits), 104 | 105 | // Negative values are checked above. 106 | static_cast(dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight) 107 | }; 108 | return BMPSave( 109 | stream, 110 | { dib.dsBmih.biWidth, dib.dsBmih.biHeight }, 111 | dib.dsBmih.biPlanes, 112 | dib.dsBmih.biBitCount, 113 | palette, 114 | pixels 115 | ); 116 | } 117 | 118 | void SURFACE_GDI::Delete() noexcept 119 | { 120 | if(img) { 121 | SelectObject(dc, stock_img); 122 | DeleteObject(img); 123 | img = nullptr; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /platform/windows/surface_gdi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 2D surfaces via GDI bitmaps 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/surface.h" 9 | 10 | // Only required for the HBITMAP type, which is basically void*. 11 | #define WIN32_LEAN_AND_MEAN 12 | #include 13 | 14 | struct BMP_OWNED; 15 | struct FILE_STREAM_WRITE; 16 | 17 | class SURFACE_GDI : public SURFACE { 18 | public: 19 | // Required for unselecting [img] prior to deleting it. Could have probably 20 | // been `static`, but let's keep it correct for now. 21 | HGDIOBJ stock_img = nullptr; 22 | 23 | // Source bitmap data, if any. 24 | HBITMAP img = nullptr; 25 | 26 | // Always has any valid [img] selected into it. 27 | HDC dc; 28 | 29 | SURFACE_GDI() noexcept; 30 | SURFACE_GDI(const SURFACE_GDI&) = delete; 31 | SURFACE_GDI& operator=(const SURFACE_GDI&) = delete; 32 | ~SURFACE_GDI(); 33 | 34 | // Calls Delete() and reinitializes [img]. 35 | bool Load(const BMP_OWNED& bmp); 36 | 37 | // Saves [img] as a .BMP file to the given stream. 38 | bool Save(FILE_STREAM_WRITE*) const; 39 | 40 | void Delete() noexcept; 41 | }; 42 | -------------------------------------------------------------------------------- /platform/windows/text_gdi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Text rendering via GDI 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "game/text_packed.h" 9 | #include "platform/graphics_backend.h" 10 | 11 | class TEXTRENDER_SESSION { 12 | protected: 13 | // HFONT would require a cast of the value returned from SelectObject(). 14 | // Thankfully, this type doesn't even require . 15 | using HGDIOBJ = void *; 16 | 17 | std::optional font_initial = std::nullopt; 18 | 19 | // A COLORREF created with the RGB macro always has 0x00 in the topmost 8 20 | // bits. 21 | uint32_t color_cur = -1; 22 | 23 | FONT_ID font_cur = FONT_ID::COUNT; 24 | const PIXEL_LTWH rect; 25 | 26 | public: 27 | class PIXELACCESS { 28 | friend class TEXTRENDER_SESSION; 29 | 30 | const PIXEL_LTWH rect; 31 | 32 | PIXELACCESS(const PIXEL_LTWH rect) : rect(rect) { 33 | } 34 | 35 | public: 36 | uint32_t GetRaw(const PIXEL_POINT& xy_rel); 37 | void SetRaw(const PIXEL_POINT& xy_rel, uint32_t col); 38 | 39 | RGB Get(const PIXEL_POINT& xy_rel); 40 | void Set(const PIXEL_POINT& xy_rel, const RGB col); 41 | }; 42 | 43 | PIXEL_SIZE RectSize(void) const; 44 | void SetFont(FONT_ID font); 45 | void SetColor(const RGB color); 46 | PIXEL_SIZE Extent(Narrow::string_view str); 47 | void Put( 48 | const PIXEL_POINT& topleft_rel, 49 | Narrow::string_view str, 50 | std::optional color = std::nullopt 51 | ); 52 | auto PixelAccess(std::invocable auto f) { 53 | PIXELACCESS p = { rect }; 54 | return f(p); 55 | } 56 | 57 | TEXTRENDER_SESSION(const PIXEL_LTWH& rect); 58 | ~TEXTRENDER_SESSION(); 59 | }; 60 | 61 | class TEXTRENDER : public TEXTRENDER_PACKED { 62 | friend class TEXTRENDER_PACKED; 63 | 64 | bool Wipe(); 65 | std::optional Session(TEXTRENDER_RECT_ID rect_id); 66 | 67 | public: 68 | void WipeBeforeNextRender(); 69 | PIXEL_SIZE TextExtent(FONT_ID font, Narrow::string_view str); 70 | }; 71 | -------------------------------------------------------------------------------- /platform/windows/time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Time interface (Win32 implementation) 3 | * 4 | */ 5 | 6 | #include "platform/time.h" 7 | #include "game/cast.h" 8 | #include 9 | 10 | #pragma comment(lib, "winmm.lib") 11 | 12 | uint32_t Time_SteadyTicksMS() 13 | { 14 | return timeGetTime(); 15 | } 16 | 17 | TIME_OF_DAY Time_NowLocal() 18 | { 19 | SYSTEMTIME systime; 20 | GetLocalTime(&systime); 21 | return TIME_OF_DAY{ 22 | .year = systime.wYear, 23 | .month = Cast::down(systime.wMonth), 24 | .day = Cast::down(systime.wDay), 25 | .hour = Cast::down(systime.wHour), 26 | .minute = Cast::down(systime.wMinute), 27 | .second = Cast::down(systime.wSecond), 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /platform/windows/unicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode types for native system APIs (Win32 Unicode version) 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | import std; 9 | 10 | using UNICODE_STRING = std::wstring; 11 | using UNICODE_STRING_VIEW = std::wstring_view; 12 | using UNICODE_LITERAL = const wchar_t *; 13 | #define _UNICODE_INNER(str) L##str 14 | #define _UNICODE(str) _UNICODE_INNER(str) 15 | -------------------------------------------------------------------------------- /platform/windows/utf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode conversion helpers 3 | * 4 | */ 5 | 6 | #pragma once 7 | 8 | #define WIN32_LEAN_AND_MEAN 9 | 10 | #include "game/narrow.h" 11 | #include 12 | #include 13 | #include 14 | 15 | namespace UTF { 16 | 17 | template std::optional WithUTF16( 18 | Narrow::string_view str, 19 | std::invocable auto&& func, 20 | UINT fallback = 932 21 | ) 22 | { 23 | if(str.size() == 0) { 24 | return std::nullopt; 25 | } 26 | 27 | auto* str_w = static_cast(_malloca( 28 | str.size() * sizeof(wchar_t) 29 | )); 30 | if(!str_w) { 31 | return std::nullopt; 32 | } 33 | 34 | // Try UTF-8 35 | auto len_w = MultiByteToWideChar( 36 | CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str.size(), str_w, str.size() 37 | ); 38 | if((len_w == 0) && (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)) { 39 | if(fallback == 0) { 40 | return std::nullopt; 41 | } 42 | len_w = MultiByteToWideChar( 43 | fallback, MB_PRECOMPOSED, str.data(), str.size(), str_w, str.size() 44 | ); 45 | assert(len_w > 0); 46 | } 47 | auto ret = func({ str_w, static_cast(len_w) }); 48 | _freea(str_w); 49 | return ret; 50 | } 51 | 52 | template std::optional WithUTF16( 53 | std::u8string_view str, std::invocable auto&& func 54 | ) 55 | { 56 | return WithUTF16(str, func, 0); 57 | } 58 | 59 | // Wrapper for null-terminated strings that are guaranteed to be UTF-8. 60 | template std::optional WithUTF16( 61 | const char8_t* str, std::invocable auto&& func 62 | ) 63 | { 64 | // The terminating \0 must be part of the view. 65 | const size_t len = (strlen(reinterpret_cast(str)) + 1); 66 | return WithUTF16({ str, len }, func); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /platform/windows_vintage/DD_CLIP2D.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DD_CLIP2D.h 2D図形描画用クリッピング */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DD_CLIP2D_H 7 | #define PBGWIN_DD_CLIP2D_H "DD_CLIP2D : Version 0.01 : Update 1999/12/03" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | // 1999/12/03 : CLIP.C から引っぱり出してきました 13 | 14 | 15 | // ヘッダファイル // 16 | import std.compat; 17 | #include "platform/graphics_backend.h" 18 | 19 | 20 | // 関数 // 21 | // ポリゴン用クリッピング 22 | // Returns: 23 | // • An empty span if all of [src]'s points lie outside the clipping region 24 | // • [src] if all its points were inside the clipping region and nothing needed 25 | // to be clipped 26 | // • A span pointing into [temp] describing the clipped polygon 27 | VERTEX_XY_SPAN<> Grp_PClip(std::span temp, VERTEX_XY_SPAN<> src); 28 | 29 | 30 | #define OUTCODE_X 0x03 31 | #define OUTCODE_LEFT 0x01 32 | #define OUTCODE_RIGHT 0x02 33 | 34 | #define OUTCODE_Y 0x30 35 | #define OUTCODE_TOP 0x20 36 | #define OUTCODE_BOTTOM 0x10 37 | 38 | 39 | // アウトコードを取得する // 40 | inline uint8_t GetLineOutcode(int x, int y) 41 | { 42 | extern int CLIP_X_MIN,CLIP_X_MAX,CLIP_Y_MIN,CLIP_Y_MAX; 43 | uint8_t temp = (OUTCODE_LEFT | OUTCODE_BOTTOM); 44 | 45 | if(CLIP_X_MIN <= x){ 46 | temp ^= OUTCODE_X; 47 | if(x <= CLIP_X_MAX) temp ^= OUTCODE_RIGHT; 48 | } 49 | 50 | if(y <= CLIP_Y_MAX){ 51 | temp ^= OUTCODE_Y; 52 | if(CLIP_Y_MIN <= y) temp ^= OUTCODE_TOP; 53 | } 54 | 55 | return temp; 56 | } 57 | 58 | // 実際にクリッピングを行う // 59 | inline bool GrpLineCut(int *x1, int *y1, int *x2, int *y2, uint8_t outcode) 60 | { 61 | extern int CLIP_X_MIN,CLIP_X_MAX,CLIP_Y_MIN,CLIP_Y_MAX; 62 | int temp; 63 | 64 | // x方向のクリッピングが必要な場合 // 65 | if(outcode&OUTCODE_X){ 66 | temp = (outcode&OUTCODE_LEFT) ? CLIP_X_MIN : CLIP_X_MAX; 67 | (*x1) -= (*x2); // dx 68 | if((*x1) == 0) return false; 69 | (*y1) -= (*y2); // dy 70 | 71 | (*y1) = ( (temp-(*x2))*(*y1) )/(*x1) + (*y2); 72 | (*x1) = temp; 73 | 74 | if((*y1)CLIP_Y_MAX) outcode = OUTCODE_BOTTOM; 76 | else return true; 77 | } 78 | 79 | // y方向のクリッピングが必要な場合 // 80 | if(outcode&OUTCODE_Y){ 81 | temp = (outcode&OUTCODE_TOP) ? CLIP_Y_MIN : CLIP_Y_MAX; 82 | (*y1) -= (*y2); // dy 83 | if((*y1) == 0) return false; 84 | 85 | (*x1) -= (*x2); // dx 86 | 87 | (*x1) = ( (temp-(*y2))*(*x1) )/(*y1) + (*x2); 88 | (*y1) = temp; 89 | } 90 | 91 | return (((*x1) >= CLIP_X_MIN) && ((*x1) <= CLIP_X_MAX)); 92 | } 93 | 94 | // ReturnValue == TRUE : 完全に範囲内もしくはクリッピングが正常に行われた // 95 | // ReturnValue == FALSE : 完全に範囲外 96 | inline bool GrpLineClip(int *x1, int *y1, int *x2, int *y2) 97 | { 98 | const auto Outcode1 = GetLineOutcode(*x1, *y1); 99 | const auto Outcode2 = GetLineOutcode(*x2, *y2); 100 | 101 | if((Outcode1 & Outcode2) != 0) { 102 | return false; 103 | } 104 | if((Outcode1 == 0) && (Outcode2 == 0)) { 105 | return true; 106 | } 107 | return ( 108 | GrpLineCut(x1, y1, x2, y2, Outcode1) && 109 | GrpLineCut(x2, y2, x1, y1, Outcode2) 110 | ); 111 | } 112 | 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /platform/windows_vintage/DD_GRP2D.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DD_GRP2D.h 2D&8Bit時の図形描画関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DD_GRP2D_H 7 | #define PBGWIN_DD_GRP2D_H "DD_GRP2D : Version 0.03 : Update 1999/01/12" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | // 2000/ 1/12 : α関連の関数を一部追加 13 | // 1999/12/03 : 2D図形描画作成(αをのぞく) 14 | 15 | 16 | // ヘッダファイル // 17 | #include "platform/graphics_backend.h" 18 | #include "constants.h" 19 | 20 | class GRAPHICS_GEOMETRY_DDRAW : public GRAPHICS_GEOMETRY { 21 | public: 22 | // Generic methods 23 | // --------------- 24 | 25 | void Lock(void) final; 26 | void Unlock(void) final; 27 | void SetColor(RGB216 col) final; 28 | void SetAlphaNorm(uint8_t a) final; 29 | void SetAlphaOne(void) final; 30 | void DrawLine(int x1, int y1, int x2, int y2) final; 31 | void DrawBox(int x1, int y1, int x2, int y2) final; 32 | void DrawBoxA(int x1, int y1, int x2, int y2) final; 33 | void DrawTriangleFan(VERTEX_XY_SPAN<>) final; 34 | // ---------- 35 | 36 | // Framebuffer methods 37 | // ------------------- 38 | 39 | void DrawPoint(WINDOW_POINT p); 40 | void DrawHLine(int x1, int x2, int y); 41 | // ------------------- 42 | 43 | void Setup(void); // 描画系関数ポインタをセットする 44 | }; 45 | 46 | static_assert(GRAPHICS_GEOMETRY_FB); 47 | 48 | // Returns the instance of the framebuffer geometry interface if active, or a 49 | // nullptr otherwise. 50 | GRAPHICS_GEOMETRY_DDRAW *GrpGeom_FB(void); 51 | 52 | void DisableAlphaTable(void); 53 | 54 | 55 | 56 | // インライン関数 // 57 | inline bool _2DChkPoint(int x, int y) 58 | { 59 | extern int CLIP_X_MIN,CLIP_X_MAX,CLIP_Y_MIN,CLIP_Y_MAX; 60 | 61 | return !( 62 | (x < CLIP_X_MIN) || 63 | (x > CLIP_X_MAX) || 64 | (y < CLIP_Y_MIN) || 65 | (y > CLIP_Y_MAX) 66 | ); 67 | } 68 | 69 | // 正方形クリップ : ReturnValue true:クリッピング成功 false:完全に範囲外 70 | inline bool _2DClipRect(int *x1, int *y1, int *x2, int *y2) 71 | { 72 | extern int CLIP_X_MIN,CLIP_X_MAX,CLIP_Y_MIN,CLIP_Y_MAX; 73 | 74 | // 完全判定 // 75 | if((*x1 > CLIP_X_MAX) || (*x2 < CLIP_X_MIN)) { 76 | return false; 77 | } 78 | if((*y1 > CLIP_Y_MAX) || (*y2 < CLIP_Y_MIN)) { 79 | return false; 80 | } 81 | 82 | // クリッピング // 83 | if((*x1)CLIP_X_MAX) (*x2)=CLIP_X_MAX; 86 | if((*y2)>CLIP_Y_MAX) (*y2)=CLIP_Y_MAX; 87 | 88 | return true; 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /platform/windows_vintage/DD_GRP3D.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DD_GRP3D.h 3D時の図形描画関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DD_GRP3D_H 7 | #define PBGWIN_DD_GRP3D_H "DD_GRP3D : Version 0.03 : Update 2000/02/22" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | // 2000/02/22 : GrpGrdPolygon() を追加 13 | // 1999/12/04 : レーザー用特殊α関数を追加 14 | // 1999/12/02 : やっと一部の関数が動作し始めた。16Bit-αはやっぱり綺麗だな... 15 | 16 | 17 | // ヘッダファイル // 18 | #include "platform/graphics_backend.h" 19 | 20 | class GRAPHICS_GEOMETRY_D3D : public GRAPHICS_GEOMETRY { 21 | public: 22 | // Generic methods 23 | // --------------- 24 | 25 | void Lock(void) final; 26 | void Unlock(void) final; 27 | void SetColor(RGB216 col) final; 28 | void SetAlphaNorm(uint8_t a) final; 29 | void SetAlphaOne(void) final; 30 | void DrawLine(int x1, int y1, int x2, int y2) final; 31 | void DrawBox(int x1, int y1, int x2, int y2) final; 32 | void DrawBoxA(int x1, int y1, int x2, int y2) final; 33 | void DrawTriangleFan(VERTEX_XY_SPAN<>) final; 34 | // ---------- 35 | 36 | // Poly methods 37 | // ------------ 38 | 39 | void DrawLineStrip(VERTEX_XY_SPAN<>); 40 | void DrawTriangles( 41 | TRIANGLE_PRIMITIVE, VERTEX_XY_SPAN<>, VERTEX_RGBA_SPAN<> colors = {} 42 | ); 43 | void DrawTrianglesA( 44 | TRIANGLE_PRIMITIVE, VERTEX_XY_SPAN<>, VERTEX_RGBA_SPAN<> colors = {} 45 | ); 46 | void DrawGrdLineEx(int x, int y1, RGB c1, int y2, RGB c2); 47 | // ------------ 48 | }; 49 | 50 | // Returns the instance of the channeled geometry interface if active, or a 51 | // nullptr otherwise. 52 | GRAPHICS_GEOMETRY_D3D *GrpGeom_Poly(void); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /platform/windows_vintage/DD_UTY.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DD_UTY.h 描画関連の関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DD_UTY_H 7 | #define PBGWIN_DD_UTY_H "DD_UTY : Version 0.07 : Update 2000/02/03" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | // 2000/08/21 : クリッピング関数を更新・追加 13 | 14 | // 2000/03/01 : GrpSetRestoreHook() を追加 15 | // 2000/02/28 : GrpFatCircleA() を追加。使い方次第では便利なのでは? 16 | 17 | // 1999/12/05 : クリッピング描画を追加(一通りの関数が揃う) 18 | // 1999/12/02 : 列挙系の関数がほぼ完成する。BMPローダも後少しで完成するはず 19 | // : 関数ポインタの追加 20 | // 1999/11/30 : D3D_IM を使用するように変更。それに伴い、全体的に大幅な変更あり 21 | // : また、D3DRM_UTY を削除した。 22 | 23 | 24 | // ヘッダファイル // 25 | #include "DD_GRP2D.H" // 2D用描画関数(公開しないこと) 26 | #include "DD_GRP3D.H" // 3D用描画関数(公開しないこと) 27 | #include "game/graphics.h" 28 | 29 | 30 | // Forward declarations // 31 | struct BMP_OWNED; 32 | struct IDirectDraw2; 33 | struct IDirectDrawPalette; 34 | struct IDirectDrawSurface; 35 | struct IDirect3D2; 36 | struct IDirect3DDevice2; 37 | struct IDirect3DViewport2; 38 | struct SURFACE_DDRAW; 39 | 40 | // 構造体 // 41 | struct GRAPHICS_DDRAW { 42 | IDirectDraw2* DD; // DirectDraw Object 43 | IDirect3D2* D3; 44 | IDirect3DDevice2* D3Dev; 45 | IDirect3DViewport2* View; 46 | 47 | IDirectDrawPalette* Pal; // パレット(8Bitのときだけ) 48 | 49 | IDirectDrawSurface* Prim; // 表画面 50 | IDirectDrawSurface* Back; // 裏画面 51 | IDirectDrawSurface* Zbuf; // Zバッファ 52 | 53 | PALETTE Palette; 54 | 55 | PIXELFORMAT PixelFormat; 56 | bool bNeedChgPal; // パレットを変更する必要があるか 57 | 58 | public: 59 | // Ensures that a DirectDraw surface matches its underlying image. 60 | bool SurfaceRestore(SURFACE_DDRAW& surf); 61 | 62 | // Also ensures the correct color key for palettized pixel formats. 63 | bool SurfaceSetColorKeyFromFirstPixel(SURFACE_DDRAW& surf); 64 | 65 | // ロード済みのSurfaceを修復 66 | bool Restore(void); 67 | 68 | // (Re-)creates the DirectDraw surface associated with [surf_id], in the 69 | // given size and with undefined initial contents, retaining whatever state 70 | // the GDI surface might have had. After filling the GDI surface with the 71 | // intended pixels, call SurfaceRestore() to upload them to the DirectDraw 72 | // surface. 73 | bool SurfaceCreateUninitialized(SURFACE_DDRAW& surf, PIXEL_SIZE size); 74 | 75 | // Mutates the top-left pixel of the DirectDraw (not GDI) surface. 76 | bool SurfaceSetColorKey(SURFACE_DDRAW& surf, RGB col); 77 | }; 78 | 79 | 80 | // グローバル変数 // 81 | extern GRAPHICS_DDRAW DxObj; 82 | extern GRAPHICS_GEOMETRY *GrpGeom; 83 | 84 | #define SUPPORT_GRP_BITDEPTH 85 | #undef SUPPORT_GRP_SCALING 86 | #undef SUPPORT_GRP_WINDOWED 87 | #undef SUPPORT_GRP_API 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /platform/windows_vintage/README.md: -------------------------------------------------------------------------------- 1 | Subsystem implementations from pbg's original codebase. 2 | -------------------------------------------------------------------------------- /platform/windows_vintage/path_vintage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Common paths for vintage Windows systems 3 | * 4 | */ 5 | 6 | #define WIN32_LEAN_AND_MEAN 7 | 8 | #include "platform/path.h" 9 | #include 10 | 11 | static std::u8string PathData; 12 | 13 | std::u8string_view PathForData(void) 14 | { 15 | if(!PathData.empty()) { 16 | return PathData; 17 | } 18 | 19 | // Like pbg's original code, but updated to Unicode. 20 | const auto* cmdline_w = (GetCommandLineW() + 1); 21 | const auto* p = wcschr(cmdline_w, '\"'); 22 | if(!p || !wcschr(cmdline_w, '\\')) { 23 | return {}; 24 | } 25 | while(*p != '\\') { 26 | p--; 27 | } 28 | const size_t len_w = ((p + 1) - cmdline_w); 29 | PathData.resize_and_overwrite((len_w * 4), [&](auto buf, size_t len_utf8) { 30 | auto* lpstr = reinterpret_cast(buf); 31 | return WideCharToMultiByte( 32 | CP_UTF8, 0, cmdline_w, len_w, lpstr, len_utf8, nullptr, nullptr 33 | ); 34 | }); 35 | return PathData; 36 | } 37 | -------------------------------------------------------------------------------- /strings/title.h: -------------------------------------------------------------------------------- 1 | #define GAME_ORG "rec98" 2 | #define GAME_APP "sh01" 3 | #define GAME_TITLE "秋霜玉" 4 | -------------------------------------------------------------------------------- /submodules_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | submodule_init() { 4 | git submodule init "$1" 5 | if [ ! -f "$1.sparse-checkout" ]; then 6 | # Do a regular submodule checkout 7 | git submodule update "$1" 8 | return; 9 | fi 10 | 11 | hash=$(git submodule status --cached "$1" | cut -c 2-41) 12 | 13 | # Do a manual sparse checkout by 14 | # 1) setting up the repo from scratch to emulate `git submodule`'s shallow 15 | # cloning of only the given ref, 16 | git -C "$1" init 17 | git -C "$1" remote add origin "$(git config submodule."$1".url)" 18 | git -C "$1" fetch --depth=1 --filter=blob:none origin "$hash" 19 | 20 | # 2) setting the sparse-checkout parameters, and 21 | git -C "$1" sparse-checkout set --stdin < "$1.sparse-checkout" 22 | git -C "$1" reset --hard "$hash" 23 | 24 | # 3) converting the result back into a submodule. 25 | # Can we declaratively specify all that in .gitmodules somehow, please? 26 | git submodule absorbgitdirs "$1" 27 | } 28 | 29 | # `git submodule` is quite slow on Windows, so it's a good idea to just call it 30 | # a single time in the optimal case. 31 | git submodule status "$@" | while read -r line; do 32 | case $line in 33 | # Submodule not initialized? 34 | "-"*) 35 | module=$(echo "$line" | cut -d ' ' -f2) 36 | submodule_init "$module";; 37 | 38 | # Mismatch? 39 | "+"*) 40 | module=$(echo "$line" | cut -d ' ' -f2) 41 | recorded=$(git submodule status --cached "$module" | cut -c 2-41) 42 | current=$(echo "$line" | cut -c 2-41) 43 | echo Error: Submodule "$module": Checked-out commit does not match the recorded commit in Git: 44 | echo 45 | echo " Recorded: $recorded" 46 | echo " Current: $current" 47 | echo 48 | echo If you just pulled this repository, run 49 | echo 50 | echo " git submodule update $module" 51 | echo 52 | echo Otherwise, resolve the conflict manually. 53 | echo Exiting the build process just to be safe. 54 | exit 1 55 | ;; 56 | esac 57 | done 58 | -------------------------------------------------------------------------------- /unused/D3_TEX.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* D3_TEX.h テクスチャ管理用関数 */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_D3_TEX_H 7 | #define PBGWIN_D3_TEX_H "D3_TEX : Version 0.02 : Update 1999/12/13" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | 13 | 14 | // 定数&マクロ // 15 | #define TEXTURE_MAX 20 // テクスチャの枚数(最大) 16 | 17 | 18 | // 関数 // 19 | FBOOL TexInit(void); // 最適なテクスチャフォーマットを検索する 20 | FBOOL TexCreateTexture(char *name,DWORD txid); // テクスチャをロードする 21 | FVOID TexReleaseTexture(DWORD txid); // テクスチャを解放する 22 | FVOID TexSetTexture(DWORD txid); // テクスチャハンドルをセットする 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /unused/DD_GRP2D.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused snippets from the original DD_GRP2D component 3 | * 4 | */ 5 | 6 | #include "DD_GRP2D.H" 7 | 8 | // α円塗りつぶし // 9 | FVOID _2DCircleA(int x,int y,int r) 10 | { 11 | // 工事中につき、少々お待ち下さい... // 12 | if(AlphaFlag) _2DUpdateAlphaTable(); 13 | } 14 | 15 | // αポリゴン塗りつぶし // 16 | FVOID _2DPolygonA(POINT *p,int n) 17 | { 18 | // 工事中につき、少々お待ち下さい... // 19 | if(AlphaFlag) _2DUpdateAlphaTable(); 20 | } 21 | 22 | // ガンマコントロール // 23 | FVOID _2DGamma(BYTE r,BYTE g,BYTE b,BYTE a) 24 | { 25 | PALETTEENTRY pe[256]; 26 | int i; 27 | 28 | for(i=0;i<256;i++){ 29 | pe[i].peRed = min(255,DxObj.pe[i].peRed * (r+1) * (a+1) / (256*128)); 30 | pe[i].peGreen = min(255,DxObj.pe[i].peGreen * (g+1) * (a+1) / (256*128)); 31 | pe[i].peBlue = min(255,DxObj.pe[i].peBlue * (b+1) * (a+1) / (256*128)); 32 | pe[i].peFlags = DxObj.pe[i].peFlags; 33 | } 34 | 35 | DxObj.Pal->SetEntries(0,0,256,pe); 36 | DxObj.Back->SetPalette(DxObj.Pal); 37 | } 38 | -------------------------------------------------------------------------------- /unused/DD_GRP2D.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused snippets from the original DD_GRP2D component 3 | * 4 | */ 5 | 6 | FVOID _2DCircleA(int x,int y,int r); // α円塗りつぶし 7 | FVOID _2DPolygonA(POINT *p,int n); // αポリゴン塗りつぶし 8 | FVOID _2DGamma(BYTE r,BYTE g,BYTE b,BYTE a); // ガンマコントロール 9 | -------------------------------------------------------------------------------- /unused/DD_GRP3D.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused Direct3D graphics code 3 | * 4 | */ 5 | 6 | // Text boxes were originally supposed to be textured? 7 | FVOID GrpTexBox(int x1,int y1,int x2,int y2) 8 | { 9 | if(!bLocked) return; 10 | 11 | Set2DPoint(work+0,x1,y1);work[0].tu = 0;work[0].tv = 0; 12 | Set2DPoint(work+1,x2,y1);work[1].tu = 1;work[1].tv = 0; 13 | Set2DPoint(work+2,x1,y2);work[2].tu = 0;work[2].tv = 1; 14 | Set2DPoint(work+3,x2,y2);work[3].tu = 1;work[3].tv = 1; 15 | 16 | DxObj.D3Dev->DrawPrimitive(D3DPT_TRIANGLESTRIP,D3DVT_TLVERTEX,work,4,D3DDP_WAIT); 17 | } 18 | 19 | FVOID GrpTexBoxEx(POINT *p) 20 | { 21 | int i; 22 | 23 | if(!bLocked) return; 24 | 25 | for(i=0;i<4;i++){ 26 | Set2DPoint(work+i,p[i].x,p[i].y); 27 | } 28 | 29 | work[0].tu = 0; work[0].tv = 0; 30 | work[1].tu = 1; work[1].tv = 0; 31 | work[2].tu = 1; work[2].tv = 1; 32 | work[3].tu = 0; work[3].tv = 1; 33 | 34 | DxObj.D3Dev->DrawPrimitive(D3DPT_TRIANGLEFAN,D3DVT_TLVERTEX,work,4,D3DDP_WAIT); 35 | 36 | AlphaEnable(FALSE); 37 | } 38 | -------------------------------------------------------------------------------- /unused/DD_UTY.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused general graphics code 3 | * 4 | */ 5 | 6 | // 直接番号指定で矩形内を塗りつぶす // 7 | FVOID GrpClsEx(RECT *Target, DWORD col) 8 | { 9 | DDBLTFX ddbltfx; 10 | HRESULT ddrval; 11 | 12 | ZeroMemory(&ddbltfx,sizeof(ddbltfx)); 13 | ddbltfx.dwSize = sizeof(ddbltfx); 14 | ddbltfx.dwFillColor = col; 15 | 16 | for(;;){ 17 | ddrval = DxObj.Back->Blt(Target,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); 18 | 19 | if(ddrval == DD_OK) 20 | break; 21 | 22 | if(ddrval == DDERR_SURFACELOST){ 23 | if(!GrpRestore()) 24 | return; 25 | } 26 | 27 | if(ddrval != DDERR_WASSTILLDRAWING) 28 | break; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /unused/DD_UTY.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused general graphics code 3 | * 4 | */ 5 | 6 | // Had a [Target] parameter in pbg's code. 7 | FVOID GrpClsEx(RECT *Target, DWORD col); // 直接番号指定で矩形内を塗りつぶす 8 | -------------------------------------------------------------------------------- /unused/DX_TYPE.H: -------------------------------------------------------------------------------- 1 | /* */ 2 | /* DX_TYPE.h DX関連の定数とか */ 3 | /* */ 4 | /* */ 5 | 6 | #ifndef PBGWIN_DX_TYPE_H 7 | #define PBGWIN_DX_TYPE_H "DX_TYPE : Version 0.02" 8 | 9 | 10 | // 更新履歴 // 11 | 12 | // 2000/05/15 : 関数呼び出し規約 FINT 等を追加 13 | // 2000/01/30 : バージョン文字列を出力するようにした 14 | // 1999/12/02 : DD_UTYから分離する 15 | 16 | 17 | // ヘッダファイル // 18 | #include 19 | #include 20 | 21 | 22 | // ヘッダファイルのバージョンを表示する // 23 | #pragma message("-----[" PBGWIN_DX_TYPE_H " / " __TIMESTAMP__ "]-----") 24 | #pragma message("------------------------------") 25 | 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /unused/EFFECT.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused effect code 3 | * 4 | */ 5 | 6 | #include "EFFECT.H" 7 | #include "GIAN07/EFFECT.H" 8 | #include "GIAN07/FONTUTY.H" 9 | #include "game/coords.h" 10 | 11 | void SEffectMove(void) 12 | { 13 | for(const auto& e : SEffect) { 14 | switch(e.cmd) { 15 | case(SEFC_GAMEOVER2): 16 | if(e.time == 0) { 17 | e.cmd = SEFC_GAMEOVER3; 18 | e.time = 180; 19 | } 20 | break; 21 | 22 | case(SEFC_GAMEOVER3): 23 | if(e.time == 0) { 24 | e.cmd = SEFC_NONE; 25 | } 26 | break; 27 | } 28 | } 29 | } 30 | 31 | void SEffectDraw(void) 32 | { 33 | char buf[20]; 34 | 35 | for(const auto& e : SEffect) { 36 | switch(e.cmd) { 37 | case(SEFC_GAMEOVER3): 38 | strcpy(buf,"GAME OVER"); 39 | // if((e.time % 60) < 30) { 40 | // break; 41 | // } 42 | for(auto j = 0; j < 9; j++) { 43 | // *37 // 44 | const auto x = ((e.x >> WORLD_COORD_BITS) + ((j - 4) * 35)); 45 | const auto y = (e.y >> WORLD_COORD_BITS); 46 | GrpPutc(x, y, buf[j]); 47 | } 48 | break; 49 | } 50 | } 51 | } 52 | 53 | FVOID GrpDrawSpect(int x,int y) 54 | { 55 | // Unused spectrum analyzer colors for the palettized 8-bit mode? 56 | BYTE ColTable[10]={ 57 | RGB256(2,0,0),RGB256(3,0,0),RGB256(4,0,0),RGB256(5,0,0),RGB256(5,1,0), 58 | RGB256(5,2,1),RGB256(5,3,1),RGB256(5,4,2),RGB256(5,5,3),RGB256(5,5,4) 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /unused/EFFECT.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused effect code 3 | * 4 | */ 5 | 6 | // The original game blocked on the last frame of SEFC_GAMEOVER2, causing this 7 | // state to never be shown. 8 | #define SEFC_GAMEOVER3 0x09 9 | -------------------------------------------------------------------------------- /unused/EFFECT3D.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused snippets from 3D effect code 3 | * 4 | */ 5 | 6 | typedef struct tagTriangle3D{ 7 | Point3D Current; 8 | Point3D Speed; 9 | 10 | WINDOW_POINT Grp[3]; 11 | 12 | uint8_t deg_x,deg_y,deg_z; 13 | char roll_x,roll_y,roll_z; 14 | } Triangle3D; 15 | 16 | void InitTriangle(void); 17 | void MoveTriangle(void); 18 | void DrawTriangle(void); 19 | 20 | void InitCircle(void); 21 | void MoveCircle(void); 22 | void DrawCircle(void); 23 | -------------------------------------------------------------------------------- /unused/ENDING.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Usage code for the unused double-spiral moiré animation 3 | * 4 | */ 5 | 6 | #include "FONTUTY.H" 7 | 8 | // フォント情報格納用ね // 9 | ExtraFontInfo *pFontInfo[7]; 10 | ExtraFontInfo *pMember[7]; 11 | 12 | bool EndingInit(void) 13 | { 14 | int i; 15 | 16 | for(i=0; i<7; i++){ 17 | pFontInfo[i] = CreateExtraFont(GrEndingCredits, &src[i]); 18 | if(pFontInfo[i] == NULL) return FALSE; 19 | } 20 | 21 | for(i=0; i<7; i++){ 22 | pMember[i] = CreateExtraFont(GrEndingCredits, &src2[i]); 23 | if(pMember[i] == NULL) return FALSE; 24 | } 25 | } 26 | 27 | // スタッフの描画 // 28 | void DrawStfInfo() 29 | { 30 | int i; 31 | 32 | if(!EStfTask.bWantDisp) return; 33 | 34 | DrawExtraFont(pFontInfo[EStfTask.TitleID], 35 | EStfTask.ox, EStfTask.oy, 0);//255-EStfTask.alpha); 36 | 37 | for(i=0; isize = { 48, 48 }; 17 | a->n = 16; 18 | a->mode = ANM_DEG; 19 | 20 | for(i=0;i<16;i++){ 21 | a->ptn[i].top = y+(i/8)*48; 22 | a->ptn[i].left = x+(i%8)*48; 23 | a->ptn[i].bottom = a->ptn[i].top + 48; 24 | a->ptn[i].right = a->ptn[i].left + 48; 25 | } 26 | } 27 | 28 | extern void SetAnime80(int x,int y,int id) 29 | { 30 | int i; 31 | ANIME_DATA *a = Anime+id; 32 | 33 | a->size = { 80, 80 }; 34 | a->n = 16; 35 | a->mode = ANM_DEG; 36 | 37 | for(i=0;i<16;i++){ 38 | a->ptn[i].top = y+(i/8)*80; 39 | a->ptn[i].left = x+(i%8)*80; 40 | a->ptn[i].bottom = a->ptn[i].top + 80; 41 | a->ptn[i].right = a->ptn[i].left + 80; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /unused/FONTUTY.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused double-spiral moiré animation 3 | * 4 | * This animation was intended to be used for the staff roll sprites, but was 5 | * effectively commented out for the final release and replaced with regular 6 | * sprite blitting. A recording of the originally intended effect can be 7 | * found at 8 | * 9 | * https://rec98.nmlgc.net/blog/2022-12-31 10 | * 11 | * Moved here because the effect directly writes pixels into the back buffer, 12 | * and might therefore be hard to port to non-DirectDraw renderers. 13 | */ 14 | 15 | typedef struct tagEXPOINT { 16 | int x, y; // 元座標(中心からの相対座標) 17 | int l; // 極座標における長さ 18 | BYTE d; // 極座標における角度 19 | 20 | PIXELFORMAT::LARGEST c; // 色情報 21 | } EXPOINT; 22 | 23 | typedef struct tagExtraFontInfo { 24 | int Width; // 元画像の幅 25 | int Height; // 元画像の高さ 26 | 27 | int DataSize; // 点の数 28 | 29 | EXPOINT *Data; // データ格納先 30 | } ExtraFontInfo; 31 | 32 | ExtraFontInfo *CreateExtraFont(SURFACE_DDRAW& Surface, PIXEL_LTRB *pSrc); // フォント生成 33 | void DeleteExtraFont(ExtraFontInfo *pFont); // フォント削除 34 | 35 | // Renders [pFont] to the back buffer at the given left/top position. Setting 36 | // [t] renders the [t]th frame of a double-spiral moiré animation instead; in 37 | // that case, [radius_max] can be used to restrict this animation to the given 38 | // radius in the center of [pFont], which won't render any pixels outside. 39 | void DrawExtraFont(ExtraFontInfo *pFont, int ox, int oy, int t = 0, int radius_max = 0); 40 | -------------------------------------------------------------------------------- /unused/GAMEMAIN.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused MIDI debugging code 3 | * 4 | */ 5 | 6 | #include "unused/PBGMIDI.H" 7 | 8 | void GameDraw(void); 9 | 10 | void GameDraw_unused(void) 11 | { 12 | GameDraw(); 13 | /* 14 | HDC hdc; 15 | char buf[100]; 16 | MID_DATA dat; 17 | 18 | if(DxObj.Back->GetDC(&hdc) == DD_OK){ 19 | Mid_GetData(&dat); 20 | sprintf(buf, "c1 : %I64u", dat.nticks); 21 | //sprintf(buf, "timebase : %d", dat.timebase); 22 | TextOut(hdc, 0, 0, buf, strlen(buf)); 23 | //sprintf(buf, "tempo : %d", dat.tempo); 24 | //TextOut(hdc, 0, 30, buf, strlen(buf)); 25 | 26 | DxObj.Back->ReleaseDC(hdc); 27 | } 28 | */ 29 | } 30 | -------------------------------------------------------------------------------- /unused/GIAN.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused configuration flags 3 | * 4 | */ 5 | 6 | #define GRPF_ALPHA_ENABLE 0x01 // 半透明が有効(無効時はメッシュ???) 7 | -------------------------------------------------------------------------------- /unused/LASER.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused laser code 3 | * 4 | */ 5 | 6 | const int laser_color[16] ={ 7 | RGB256(0,0,3),RGB256(0,4,0),RGB256(0,3,3),RGB256(3,0,0), 8 | RGB256(3,0,3),RGB256(3,3,0),RGB256(3,3,3), 9 | RGB256(0,0,5),RGB256(0,5,0),RGB256(0,5,5),RGB256(5,0,0), 10 | RGB256(5,0,5),RGB256(5,5,0),RGB256(5,5,5) 11 | }; 12 | -------------------------------------------------------------------------------- /unused/LOADER.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused loading code 3 | * 4 | */ 5 | 6 | extern void LoadPaletteFromEnemy(void) 7 | { 8 | /* 9 | LPDIRECTDRAWPALETTE lpdp; 10 | 11 | if(DxObj.Bpp != 8) return; 12 | if(!GrMap) return; 13 | if(GrEnemy->GetPalette(&lpdp) != DD_OK) return; 14 | /* 15 | if(bIsBombPalette){ 16 | lpdp->GetEntries(0, 0, 256, tempPalette); 17 | } 18 | else{ 19 | */ 20 | /* 21 | lpdp->GetEntries(0,0,256,DxObj.pe); 22 | GrpSetPalette(DxObj.pe); 23 | // } 24 | 25 | lpdp->Release(); 26 | */ 27 | } 28 | 29 | /* 30 | // ボム用パレット属性に変更する // 31 | extern void EnterBombPalette(void) 32 | { 33 | LPDIRECTDRAWPALETTE lpdp; 34 | 35 | bIsBombPalette = TRUE; 36 | 37 | if(DxObj.Bpp != 8) return; 38 | if(!GrBomber) return; 39 | if(GrBomber->GetPalette(&lpdp) != DD_OK) return; 40 | 41 | // 現在のパレットを記憶する // 42 | GrpGetPalette(tempPalette); 43 | 44 | lpdp->GetEntries(0,0,256,DxObj.pe); 45 | GrpSetPalette(DxObj.pe); 46 | 47 | lpdp->Release(); 48 | } 49 | 50 | 51 | // ボム用パレット属性を外す 52 | extern void LeaveBombPalette(void) 53 | { 54 | if(!bIsBombPalette) return; 55 | 56 | bIsBombPalette = FALSE; 57 | 58 | GrpSetPalette(tempPalette); 59 | } 60 | */ 61 | -------------------------------------------------------------------------------- /unused/MAID.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused player code 3 | * 4 | */ 5 | 6 | #include "Maid.h" 7 | 8 | DWORD EvadeRate[256]; // かすり得点レート 9 | 10 | // 初期化 // 11 | extern void MaidSet(void) 12 | { 13 | int i; 14 | int sct[4] = {5,10,15,30}; 15 | 16 | for(i=0;i<256;i++) 17 | EvadeRate[i] = i*sct[ConfigDat.GameLevel.v]; 18 | } 19 | -------------------------------------------------------------------------------- /unused/MAID.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused player code 3 | * 4 | */ 5 | 6 | extern DWORD EvadeRate[256]; // かすり得点レート 7 | -------------------------------------------------------------------------------- /unused/PBGMIDI.H: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused MIDI code 3 | * 4 | */ 5 | 6 | // MIDI function flags. These were intended to differentiate between different 7 | // approaches for (1) updating the internal MIDI state and (2) sending MIDI 8 | // data to the playback device. The original game only used [MIDFN_CALLBACK] 9 | // and had no implementation for [MIDFN_STREAM], and this codebase will go a 10 | // different route altogether by decoupling (1) from (2) in order to be more 11 | // portable. 12 | #define MIDFN_NOPLAY 0x00 // 再生しない 13 | #define MIDFN_CALLBACK 0x01 // CALLBACK_FN を使用して再生 14 | #define MIDFN_MIDLOOP 0x02 // ゲーム等の一定スピードのループで再生 15 | #define MIDFN_STREAM 0x04 // MIDI_STREAM を使用して再生(予約のみ) 16 | 17 | // Indicates whether playback should loop ([MIDPL_NORM]) or stop ([MIDPL_STOP]) 18 | // after the MIDI file reached its end. This distinction is better expressed in 19 | // terms of loop points inside the BGM files themselves; it makes little sense 20 | // to control this through game code, and the original game only used 21 | // [MIDPL_NORM] anyway. 22 | #define MIDPL_NORM 0x00 // 曲の最後にきたら最初に戻って再生 23 | #define MIDPL_STOP 0x01 // 曲の最後にきたら停止 24 | 25 | void Mid_Volume(BYTE volume); // マスターボリュームを変更する 26 | 27 | // Why would you ever do this?! It's going to annoy every headphone user, and 28 | // some channels will override this position sooner or later with a CC #10 29 | // inside the MIDI sequence anyway. A 無駄関数 indeed. 30 | void Mid_Pan(char pan); // 全てのチャンネルのパンを変更する(無駄関数) 31 | 32 | // Per-frame function for MIDFN_MIDLOOP. In that mode, the game would call this 33 | // function on every frame. 34 | void Mid_LoopFunc(DWORD time); // 一定間隔ループを自前で生成して再生するとき使用 35 | 36 | // These are internal values that no other code should care about. 37 | DWORDLONG Mid_GetPlaycount1(void); // playcount1 の取得 38 | DWORDLONG Mid_GetPlaycount2(void); // playcount2 の取得 39 | DWORDLONG Mid_GetTicks(void); // tick の取得 40 | void Mid_GetData(MID_DATA *pData); // 全情報を取得 41 | -------------------------------------------------------------------------------- /unused/PaletteEX.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PaletteEx.cpp : 特殊パレット処理 3 | * 4 | */ 5 | 6 | #include "PaletteEx.h" 7 | 8 | 9 | // パレットをuv固定で変換 // 10 | void ConvertPalette(PALETTEENTRY *pal, BYTE u, BYTE v) 11 | { 12 | double ty, tu, tv; 13 | double r, g, b; 14 | int i; 15 | 16 | tu = u; 17 | tv = v; 18 | 19 | // これもダメだね // 20 | for(i=0; i<256; i++, pal++){ 21 | ty = (double)(pal->peRed)*0.299 22 | + (double)(pal->peGreen)*0.587 23 | + (double)(pal->peBlue)*0.144; 24 | 25 | r = ty + tv * 1.4026; 26 | g = ty - tu * 0.3444 + tv * 0.7114; 27 | b = ty + tu * 1.733; 28 | 29 | if(r < 0) r = 0; 30 | else if(r > 255) r = 255; 31 | 32 | if(g < 0) g = 0; 33 | else if(g > 255) g = 255; 34 | 35 | if(b < 0) b = 0; 36 | else if(b > 255) b = 255; 37 | 38 | pal->peRed = r; 39 | pal->peGreen = g; 40 | pal->peBlue = b; 41 | } 42 | } 43 | 44 | 45 | // パレットをαで合成する(p1 = p1*a/255 + p2*(255-a)/255 // 46 | void BlendPalette(PALETTEENTRY *p1, PALETTEENTRY *p2, BYTE a) 47 | { 48 | int i; 49 | DWORD temp; 50 | 51 | // 時間がないから、今回はこれで我慢 // 52 | for(i=0; i<256; i++, p1++, p2++){ 53 | temp = (((DWORD)p1->peRed) * a + ((DWORD)p2->peRed) * (255-a)) / 255; 54 | p1->peRed = (temp > 255) ? 255 : temp; 55 | 56 | temp = (((DWORD)p1->peGreen) * a + ((DWORD)p2->peGreen) * (255-a)) / 255; 57 | p1->peGreen = (temp > 255) ? 255 : temp; 58 | 59 | temp = (((DWORD)p1->peBlue) * a + ((DWORD)p2->peBlue) * (255-a)) / 255; 60 | p1->peBlue = (temp > 255) ? 255 : temp; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /unused/PaletteEx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PaletteEx.h : 特殊パレット処理 3 | * 4 | */ 5 | 6 | #ifndef PBG_PALETTEEX_VERSION 7 | #define PBG_PALETTEEX_VERSION "特殊パレット処理 : Version 0.01 : Update 2000/11/23" 8 | 9 | /* [更新履歴] 10 | * Version 0.01 : 2000/11/23 : 11 | */ 12 | 13 | 14 | 15 | #ifndef WIN32_LEAN_AND_MEAN 16 | #define WIN32_LEAN_AND_MEAN 17 | #include 18 | #endif 19 | 20 | 21 | 22 | /***** [関数プロトタイプ] *****/ 23 | 24 | // パレットをuv固定で変換 // 25 | void ConvertPalette(PALETTEENTRY *pal, BYTE u, BYTE v); 26 | 27 | // パレットをαで合成する(p1 = p1*a/255 + p2*(255-a)/255 // 28 | void BlendPalette(PALETTEENTRY *p1, PALETTEENTRY *p2, BYTE a); 29 | 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /unused/SCORE.CPP: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused High Score list code 3 | * 4 | */ 5 | 6 | BYTE ExtraFlags = 0; 7 | 8 | static BOOL _LoadExBit(BIT_DEVICE_READ *bd, BYTE *flags); 9 | static BOOL _SaveExBit(BIT_DEVICE_WRITE &bd, BYTE flags); 10 | -------------------------------------------------------------------------------- /unused/debug.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Unused debugging code 3 | * 4 | */ 5 | 6 | // In Debug mode, the original code called these macros to output information 7 | // about a subset of ECL and SCL commands. This was broken for several reasons: 8 | // 9 | // • These draw calls occur as part of each frame's movement code and before 10 | // the game clears the backbuffer. Hence, they wouldn't ever be visible. 11 | // 12 | // • Designating only a single row for all ECL and SCL commands isn't all too 13 | // useful. GrpPut16() is a blit operation that is only reflected on-screen 14 | // after the next buffer flip, so you'd only see the last ECL command 15 | // processed during each frame. Printing these debug strings to some kind of 16 | // stream would have greatly supported the use case of single-stepping in a 17 | // debugger. 18 | // 19 | // • Without a draw call to clear the respective line with black pixels before 20 | // every GrpPut16() call, the glyphs of successive debug strings within a 21 | // single frame would be blitted on top of each other, resulting in an 22 | // unreadable mess. 23 | // 24 | // • Besides, the designated positions on the HUD are already occupied with the 25 | // "Tama1" and "Tama2" output. 26 | // 27 | // • Also, why are they so weirdly indented? 28 | // 29 | // This fork changes these macros to output to the log file instead, which is 30 | // much more useful in the age of hot-reloading text editors and multi-monitor 31 | // setups. 32 | 33 | // ECLデバッグ用マクロ // 34 | #ifdef _DEBUG 35 | #define ECL_DEBUG(s,param) \ 36 | { \ 37 | char _ECL_Debug[1000]; \ 38 | sprintf(_ECL_Debug,s,param); \ 39 | GrpPut16(10,10+16*10,_ECL_Debug); \ 40 | } 41 | #else 42 | #define ECL_DEBUG(s,param) 43 | #endif 44 | 45 | // デバッグ用マクロ // 46 | #ifdef _DEBUG 47 | #define SCL_DEBUG(s) \ 48 | { \ 49 | GrpPut16(10,10+16*11,s); \ 50 | } 51 | #else 52 | #define SCL_DEBUG(s) 53 | #endif 54 | -------------------------------------------------------------------------------- /version_from_git.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Since Tup refuses to depend on files inside `.git/`… 3 | 4 | version_fn="obj/version.h" 5 | version_tag="(unknown)" 6 | 7 | if [ -d .git ]; then 8 | { 9 | [ ".git/HEAD" -ot "$version_fn" ] && 10 | [ ".git/refs/tags" -ot "$version_fn" ] && 11 | [ "$0" -ot "$version_fn" ]; 12 | } && exit 0; 13 | 14 | tag=$(git tag --points-at HEAD) 15 | 16 | if ! { git diff-files --quiet && [ -n "$tag" ]; }; then 17 | desc=$(git describe --tags --abbrev=0) 18 | commit=$(git rev-parse --short=4 HEAD) 19 | version_tag="WIP ($desc^$commit)" 20 | else 21 | version_tag="$tag" 22 | fi 23 | fi 24 | 25 | mkdir -p "$(dirname "$version_fn")" 26 | >$version_fn echo // Generated by \`"$0"\`. 27 | >>$version_fn echo \#define VERSION_TAG \""$version_tag"\" 28 | --------------------------------------------------------------------------------