From 5187ef5dc61ca7c819120c3c544a9f42d1ebff32 Mon Sep 17 00:00:00 2001 From: elasota Date: Tue, 4 May 2021 18:25:49 -0400 Subject: [PATCH 01/31] Use upscale filter at 1.5x and 2.5x --- AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp b/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp index eee9354..7b7557b 100644 --- a/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp +++ b/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp @@ -2713,7 +2713,7 @@ bool GpDisplayDriver_SDL_GL2::InitBackBuffer(uint32_t width, uint32_t height) m_gl.BindFramebuffer(GL_FRAMEBUFFER, 0); } - m_useUpscaleFilter = ((m_pixelScaleX < 2.0f && m_pixelScaleX > 1.0f) || (m_pixelScaleY < 2.0f && m_pixelScaleY > 1.0f)); + m_useUpscaleFilter = (m_pixelScaleX == 1.5f || m_pixelScaleX == 2.5f || m_pixelScaleY == 1.5f || m_pixelScaleY == 2.5f); if (m_useUpscaleFilter) { From 65d47846184102f37b8bd3c82f74f0060e79b192 Mon Sep 17 00:00:00 2001 From: elasota Date: Tue, 4 May 2021 18:26:23 -0400 Subject: [PATCH 02/31] Fix desaturation filter not isolating wand star. --- AerofoilSDL/ShaderCode/Functions.h | 2 +- .../DrawQuadPaletteP_D3D11.cpp | 99 ++++++++++--------- .../DrawQuadPaletteP_ICC_D3D11.cpp | 88 +++++++++-------- .../CompiledShaders/DrawQuadRGBP_D3D11.cpp | 98 +++++++++--------- .../DrawQuadRGBP_ICC_D3D11.cpp | 90 +++++++++-------- ShaderSrc/Functions.h | 6 +- 6 files changed, 210 insertions(+), 173 deletions(-) diff --git a/AerofoilSDL/ShaderCode/Functions.h b/AerofoilSDL/ShaderCode/Functions.h index 372f77d..bb05cad 100644 --- a/AerofoilSDL/ShaderCode/Functions.h +++ b/AerofoilSDL/ShaderCode/Functions.h @@ -58,7 +58,7 @@ "vec4 ApplyDesaturation(float desaturation, vec4 color)\n"\ "{\n"\ " // This is intentionally done in gamma space\n"\ -" if (desaturation == 0.0)\n"\ +" if (desaturation == 0.0 || (color.r == 1.0 && color.g == 1.0 && color.b == 0.0))\n"\ " return color;\n"\ "\n"\ " float grayLevel = dot(color.rgb, vec3(3.0, 6.0, 1.0) / 10.0);\n"\ diff --git a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_D3D11.cpp b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_D3D11.cpp index e612160..e1e3dd9 100644 --- a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_D3D11.cpp +++ b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_D3D11.cpp @@ -1,8 +1,8 @@ static unsigned char gs_shaderData[] = { - 68, 88, 66, 67, 200, 182, 33, 104, 202, 4, 76, 179, 221, 223, 225, - 247, 101, 77, 248, 3, 1, 0, 0, 0, 12, 8, 0, 0, 5, 0, + 68, 88, 66, 67, 183, 33, 168, 132, 150, 47, 5, 18, 245, 254, 40, + 246, 168, 148, 158, 158, 1, 0, 0, 0, 176, 8, 0, 0, 5, 0, 0, 0, 52, 0, 0, 0, 172, 2, 0, 0, 4, 3, 0, 0, 56, - 3, 0, 0, 144, 7, 0, 0, 82, 68, 69, 70, 112, 2, 0, 0, + 3, 0, 0, 52, 8, 0, 0, 82, 68, 69, 70, 112, 2, 0, 0, 1, 0, 0, 0, 180, 0, 0, 0, 3, 0, 0, 0, 28, 0, 0, 0, 0, 4, 255, 255, 0, 137, 0, 0, 72, 2, 0, 0, 124, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 255, @@ -54,7 +54,7 @@ static unsigned char gs_shaderData[] = { 1, 0, 0, 0, 8, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 83, 86, 95, 84, 65, 82, 71, 69, 84, 0, 171, 171, 83, - 72, 68, 82, 80, 4, 0, 0, 64, 0, 0, 0, 20, 1, 0, 0, + 72, 68, 82, 244, 4, 0, 0, 64, 0, 0, 0, 61, 1, 0, 0, 89, 0, 0, 4, 70, 142, 32, 0, 0, 0, 0, 0, 3, 0, 0, 0, 88, 24, 0, 4, 0, 112, 16, 0, 0, 0, 0, 0, 68, 68, 0, 0, 88, 16, 0, 4, 0, 112, 16, 0, 1, 0, 0, 0, 85, @@ -93,50 +93,61 @@ static unsigned char gs_shaderData[] = { 64, 0, 0, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 29, 0, 0, 7, 18, 0, 16, 0, 1, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, - 0, 0, 13, 0, 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 57, + 0, 0, 13, 0, 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 24, 0, 0, 8, 18, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 10, 34, 0, 16, 0, 1, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, 153, 153, 62, 154, - 153, 25, 63, 205, 204, 204, 61, 0, 0, 0, 0, 0, 0, 0, 9, - 66, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, - 128, 63, 56, 0, 0, 8, 34, 0, 16, 0, 1, 0, 0, 0, 26, - 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 50, 0, 0, 9, 226, 0, 16, 0, 1, 0, 0, - 0, 6, 9, 16, 0, 0, 0, 0, 0, 166, 10, 16, 0, 1, 0, - 0, 0, 86, 5, 16, 0, 1, 0, 0, 0, 55, 0, 0, 9, 114, - 0, 16, 0, 0, 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, - 150, 7, 16, 0, 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, - 0, 29, 0, 0, 10, 114, 0, 16, 0, 1, 0, 0, 0, 2, 64, - 0, 0, 230, 174, 37, 61, 230, 174, 37, 61, 230, 174, 37, 61, 0, - 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, - 114, 0, 16, 0, 2, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, - 0, 2, 64, 0, 0, 145, 131, 158, 61, 145, 131, 158, 61, 145, 131, - 158, 61, 0, 0, 0, 0, 0, 0, 0, 10, 114, 0, 16, 0, 0, - 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, - 174, 71, 97, 61, 174, 71, 97, 61, 174, 71, 97, 61, 0, 0, 0, - 0, 56, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 110, 167, 114, 63, 110, - 167, 114, 63, 110, 167, 114, 63, 0, 0, 0, 0, 47, 0, 0, 5, - 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, - 0, 56, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, 153, 25, 64, 154, - 153, 25, 64, 154, 153, 25, 64, 0, 0, 0, 0, 25, 0, 0, 5, - 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, - 0, 55, 0, 0, 9, 114, 32, 16, 0, 0, 0, 0, 0, 70, 2, - 16, 0, 1, 0, 0, 0, 70, 2, 16, 0, 2, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, - 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, 0, 0, 0, 33, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 4, - 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 24, 0, 0, 10, 226, 0, 16, 0, 1, 0, 0, 0, 6, 9, + 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 63, 0, 0, 128, 63, 0, 0, 0, 0, 1, 0, 0, 7, + 34, 0, 16, 0, 1, 0, 0, 0, 42, 0, 16, 0, 1, 0, 0, + 0, 26, 0, 16, 0, 1, 0, 0, 0, 1, 0, 0, 7, 34, 0, + 16, 0, 1, 0, 0, 0, 58, 0, 16, 0, 1, 0, 0, 0, 26, + 0, 16, 0, 1, 0, 0, 0, 60, 0, 0, 7, 18, 0, 16, 0, + 1, 0, 0, 0, 26, 0, 16, 0, 1, 0, 0, 0, 10, 0, 16, + 0, 1, 0, 0, 0, 16, 0, 0, 10, 34, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, + 153, 153, 62, 154, 153, 25, 63, 205, 204, 204, 61, 0, 0, 0, 0, + 0, 0, 0, 9, 66, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, + 128, 65, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, 56, 0, 0, 8, 34, 0, 16, 0, 1, + 0, 0, 0, 26, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 50, 0, 0, 9, 226, 0, 16, + 0, 1, 0, 0, 0, 6, 9, 16, 0, 0, 0, 0, 0, 166, 10, + 16, 0, 1, 0, 0, 0, 86, 5, 16, 0, 1, 0, 0, 0, 55, + 0, 0, 9, 114, 0, 16, 0, 0, 0, 0, 0, 6, 0, 16, 0, + 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 150, 7, 16, + 0, 1, 0, 0, 0, 29, 0, 0, 10, 114, 0, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, 230, 174, 37, 61, 230, 174, 37, 61, 230, + 174, 37, 61, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, + 56, 0, 0, 10, 114, 0, 16, 0, 2, 0, 0, 0, 70, 2, 16, + 0, 0, 0, 0, 0, 2, 64, 0, 0, 145, 131, 158, 61, 145, 131, + 158, 61, 145, 131, 158, 61, 0, 0, 0, 0, 52, 0, 0, 10, 114, + 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 10, 114, 0, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 174, + 71, 97, 61, 174, 71, 97, 61, 174, 71, 97, 61, 0, 0, 0, 0, + 56, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, + 0, 0, 0, 0, 0, 2, 64, 0, 0, 110, 167, 114, 63, 110, 167, + 114, 63, 110, 167, 114, 63, 0, 0, 0, 0, 47, 0, 0, 5, 114, + 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, + 56, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, + 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, 153, 25, 64, 154, 153, + 25, 64, 154, 153, 25, 64, 0, 0, 0, 0, 25, 0, 0, 5, 114, + 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, + 55, 0, 0, 9, 114, 32, 16, 0, 0, 0, 0, 0, 70, 2, 16, + 0, 1, 0, 0, 0, 70, 2, 16, 0, 2, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, 0, + 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, 1, + 83, 84, 65, 84, 116, 0, 0, 0, 38, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, + 0, 0, 0, 0, }; namespace GpBinarizedShaders diff --git a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_ICC_D3D11.cpp b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_ICC_D3D11.cpp index 668b1a9..6502bf5 100644 --- a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_ICC_D3D11.cpp +++ b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadPaletteP_ICC_D3D11.cpp @@ -1,8 +1,8 @@ static unsigned char gs_shaderData[] = { - 68, 88, 66, 67, 124, 220, 109, 55, 227, 43, 211, 66, 26, 106, 247, - 85, 84, 5, 208, 10, 1, 0, 0, 0, 208, 7, 0, 0, 5, 0, + 68, 88, 66, 67, 91, 245, 0, 26, 141, 247, 8, 90, 250, 198, 29, + 196, 50, 53, 108, 15, 1, 0, 0, 0, 76, 8, 0, 0, 5, 0, 0, 0, 52, 0, 0, 0, 172, 2, 0, 0, 4, 3, 0, 0, 56, - 3, 0, 0, 84, 7, 0, 0, 82, 68, 69, 70, 112, 2, 0, 0, + 3, 0, 0, 208, 7, 0, 0, 82, 68, 69, 70, 112, 2, 0, 0, 1, 0, 0, 0, 180, 0, 0, 0, 3, 0, 0, 0, 28, 0, 0, 0, 0, 4, 255, 255, 0, 137, 0, 0, 72, 2, 0, 0, 124, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 255, @@ -54,7 +54,7 @@ static unsigned char gs_shaderData[] = { 1, 0, 0, 0, 8, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 83, 86, 95, 84, 65, 82, 71, 69, 84, 0, 171, 171, 83, - 72, 68, 82, 20, 4, 0, 0, 64, 0, 0, 0, 5, 1, 0, 0, + 72, 68, 82, 144, 4, 0, 0, 64, 0, 0, 0, 36, 1, 0, 0, 89, 0, 0, 4, 70, 142, 32, 0, 0, 0, 0, 0, 3, 0, 0, 0, 88, 24, 0, 4, 0, 112, 16, 0, 0, 0, 0, 0, 68, 68, 0, 0, 88, 16, 0, 4, 0, 112, 16, 0, 1, 0, 0, 0, 85, @@ -93,46 +93,54 @@ static unsigned char gs_shaderData[] = { 64, 0, 0, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 29, 0, 0, 7, 18, 0, 16, 0, 1, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, - 0, 0, 13, 0, 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 57, + 0, 0, 13, 0, 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 24, 0, 0, 8, 18, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, - 0, 16, 0, 0, 10, 34, 0, 16, 0, 1, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, 153, 153, 62, 154, - 153, 25, 63, 205, 204, 204, 61, 0, 0, 0, 0, 0, 0, 0, 9, - 66, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 128, 65, 0, 0, - 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, - 128, 63, 56, 0, 0, 8, 34, 0, 16, 0, 1, 0, 0, 0, 26, - 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 50, 0, 0, 9, 226, 0, 16, 0, 1, 0, 0, - 0, 6, 9, 16, 0, 0, 0, 0, 0, 166, 10, 16, 0, 1, 0, - 0, 0, 86, 5, 16, 0, 1, 0, 0, 0, 55, 32, 0, 9, 114, - 0, 16, 0, 0, 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, - 150, 7, 16, 0, 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, - 0, 47, 0, 0, 5, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, 0, - 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, - 102, 102, 230, 63, 102, 102, 230, 63, 102, 102, 230, 63, 0, 0, 0, - 0, 25, 0, 0, 5, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, - 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, 1, - 0, 0, 0, 86, 5, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, - 150, 246, 160, 189, 43, 199, 117, 63, 40, 177, 243, 60, 0, 0, 0, - 0, 50, 0, 0, 12, 114, 0, 16, 0, 1, 0, 0, 0, 6, 0, - 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 87, 203, 136, 63, 86, - 131, 197, 60, 225, 104, 227, 58, 0, 0, 0, 0, 70, 2, 16, 0, - 1, 0, 0, 0, 50, 32, 0, 12, 114, 32, 16, 0, 0, 0, 0, - 0, 166, 10, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 5, 9, - 34, 60, 158, 151, 129, 60, 194, 240, 119, 63, 0, 0, 0, 0, 70, - 2, 16, 0, 1, 0, 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, - 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, - 1, 83, 84, 65, 84, 116, 0, 0, 0, 31, 0, 0, 0, 2, 0, - 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 14, 0, 0, 0, 4, - 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 24, 0, 0, 10, 226, 0, 16, 0, 1, 0, 0, 0, 6, 9, + 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 63, 0, 0, 128, 63, 0, 0, 0, 0, 1, 0, 0, 7, + 34, 0, 16, 0, 1, 0, 0, 0, 42, 0, 16, 0, 1, 0, 0, + 0, 26, 0, 16, 0, 1, 0, 0, 0, 1, 0, 0, 7, 34, 0, + 16, 0, 1, 0, 0, 0, 58, 0, 16, 0, 1, 0, 0, 0, 26, + 0, 16, 0, 1, 0, 0, 0, 60, 0, 0, 7, 18, 0, 16, 0, + 1, 0, 0, 0, 26, 0, 16, 0, 1, 0, 0, 0, 10, 0, 16, + 0, 1, 0, 0, 0, 16, 0, 0, 10, 34, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, + 153, 153, 62, 154, 153, 25, 63, 205, 204, 204, 61, 0, 0, 0, 0, + 0, 0, 0, 9, 66, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, + 128, 65, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, 56, 0, 0, 8, 34, 0, 16, 0, 1, + 0, 0, 0, 26, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 50, 0, 0, 9, 226, 0, 16, + 0, 1, 0, 0, 0, 6, 9, 16, 0, 0, 0, 0, 0, 166, 10, + 16, 0, 1, 0, 0, 0, 86, 5, 16, 0, 1, 0, 0, 0, 55, + 32, 0, 9, 114, 0, 16, 0, 0, 0, 0, 0, 6, 0, 16, 0, + 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 150, 7, 16, + 0, 1, 0, 0, 0, 47, 0, 0, 5, 114, 0, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, + 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 102, 102, 230, 63, 102, 102, 230, 63, 102, 102, 230, + 63, 0, 0, 0, 0, 25, 0, 0, 5, 114, 0, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, + 0, 16, 0, 1, 0, 0, 0, 86, 5, 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 150, 246, 160, 189, 43, 199, 117, 63, 40, 177, 243, + 60, 0, 0, 0, 0, 50, 0, 0, 12, 114, 0, 16, 0, 1, 0, + 0, 0, 6, 0, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 87, + 203, 136, 63, 86, 131, 197, 60, 225, 104, 227, 58, 0, 0, 0, 0, + 70, 2, 16, 0, 1, 0, 0, 0, 50, 32, 0, 12, 114, 32, 16, + 0, 0, 0, 0, 0, 166, 10, 16, 0, 0, 0, 0, 0, 2, 64, + 0, 0, 5, 9, 34, 60, 158, 151, 129, 60, 194, 240, 119, 63, 0, + 0, 0, 0, 70, 2, 16, 0, 1, 0, 0, 0, 54, 0, 0, 5, + 130, 32, 16, 0, 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, + 0, 62, 0, 0, 1, 83, 84, 65, 84, 116, 0, 0, 0, 35, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 15, + 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 3, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, + 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, }; namespace GpBinarizedShaders diff --git a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_D3D11.cpp b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_D3D11.cpp index 887a0bb..befddf0 100644 --- a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_D3D11.cpp +++ b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_D3D11.cpp @@ -1,8 +1,8 @@ static unsigned char gs_shaderData[] = { - 68, 88, 66, 67, 70, 73, 170, 202, 197, 249, 120, 87, 61, 204, 7, - 189, 64, 34, 147, 57, 1, 0, 0, 0, 144, 7, 0, 0, 5, 0, + 68, 88, 66, 67, 134, 184, 60, 11, 56, 236, 116, 213, 80, 103, 169, + 81, 62, 1, 57, 206, 1, 0, 0, 0, 52, 8, 0, 0, 5, 0, 0, 0, 52, 0, 0, 0, 124, 2, 0, 0, 212, 2, 0, 0, 8, - 3, 0, 0, 20, 7, 0, 0, 82, 68, 69, 70, 64, 2, 0, 0, + 3, 0, 0, 184, 7, 0, 0, 82, 68, 69, 70, 64, 2, 0, 0, 1, 0, 0, 0, 132, 0, 0, 0, 2, 0, 0, 0, 28, 0, 0, 0, 0, 4, 255, 255, 0, 137, 0, 0, 24, 2, 0, 0, 92, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 255, @@ -51,7 +51,7 @@ static unsigned char gs_shaderData[] = { 0, 8, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 83, 86, 95, 84, 65, 82, 71, 69, 84, 0, 171, 171, 83, 72, 68, 82, - 4, 4, 0, 0, 64, 0, 0, 0, 1, 1, 0, 0, 89, 0, 0, + 168, 4, 0, 0, 64, 0, 0, 0, 42, 1, 0, 0, 89, 0, 0, 4, 70, 142, 32, 0, 0, 0, 0, 0, 3, 0, 0, 0, 88, 24, 0, 4, 0, 112, 16, 0, 0, 0, 0, 0, 85, 85, 0, 0, 98, 16, 0, 3, 50, 16, 16, 0, 1, 0, 0, 0, 101, 0, 0, 3, @@ -85,50 +85,60 @@ static unsigned char gs_shaderData[] = { 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 29, 0, 0, 7, 18, 0, 16, 0, 1, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, 0, 13, 0, - 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 57, 0, 0, 8, 18, + 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 24, 0, 0, 8, 18, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 16, 0, 0, - 10, 34, 0, 16, 0, 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, 154, 153, 153, 62, 154, 153, 25, 63, 205, - 204, 204, 61, 0, 0, 0, 0, 0, 0, 0, 9, 66, 0, 16, 0, - 1, 0, 0, 0, 10, 128, 32, 128, 65, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 128, 63, 56, 0, - 0, 8, 34, 0, 16, 0, 1, 0, 0, 0, 26, 0, 16, 0, 1, - 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 50, 0, 0, 9, 226, 0, 16, 0, 1, 0, 0, 0, 6, 9, 16, - 0, 0, 0, 0, 0, 166, 10, 16, 0, 1, 0, 0, 0, 86, 5, - 16, 0, 1, 0, 0, 0, 55, 0, 0, 9, 114, 0, 16, 0, 0, - 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, 150, 7, 16, 0, - 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 29, 0, 0, - 10, 114, 0, 16, 0, 1, 0, 0, 0, 2, 64, 0, 0, 230, 174, - 37, 61, 230, 174, 37, 61, 230, 174, 37, 61, 0, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, - 2, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, - 0, 145, 131, 158, 61, 145, 131, 158, 61, 145, 131, 158, 61, 0, 0, - 0, 0, 0, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 174, 71, 97, 61, - 174, 71, 97, 61, 174, 71, 97, 61, 0, 0, 0, 0, 56, 0, 0, - 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, 110, 167, 114, 63, 110, 167, 114, 63, 110, - 167, 114, 63, 0, 0, 0, 0, 47, 0, 0, 5, 114, 0, 16, 0, - 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, - 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, 154, 153, 25, 64, 154, 153, 25, 64, 154, - 153, 25, 64, 0, 0, 0, 0, 25, 0, 0, 5, 114, 0, 16, 0, - 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 55, 0, 0, - 9, 114, 32, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 1, 0, - 0, 0, 70, 2, 16, 0, 2, 0, 0, 0, 70, 2, 16, 0, 0, - 0, 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, 0, 0, 0, 0, - 58, 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, - 84, 116, 0, 0, 0, 31, 0, 0, 0, 3, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 4, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 24, 0, 0, + 10, 226, 0, 16, 0, 1, 0, 0, 0, 6, 9, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, + 0, 128, 63, 0, 0, 0, 0, 1, 0, 0, 7, 34, 0, 16, 0, + 1, 0, 0, 0, 42, 0, 16, 0, 1, 0, 0, 0, 26, 0, 16, + 0, 1, 0, 0, 0, 1, 0, 0, 7, 34, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, 1, 0, 0, 0, 26, 0, 16, 0, 1, + 0, 0, 0, 60, 0, 0, 7, 18, 0, 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 1, 0, 0, 0, 10, 0, 16, 0, 1, 0, 0, + 0, 16, 0, 0, 10, 34, 0, 16, 0, 1, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, 153, 153, 62, 154, + 153, 25, 63, 205, 204, 204, 61, 0, 0, 0, 0, 0, 0, 0, 9, + 66, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 128, 65, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, + 128, 63, 56, 0, 0, 8, 34, 0, 16, 0, 1, 0, 0, 0, 26, + 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 50, 0, 0, 9, 226, 0, 16, 0, 1, 0, 0, + 0, 6, 9, 16, 0, 0, 0, 0, 0, 166, 10, 16, 0, 1, 0, + 0, 0, 86, 5, 16, 0, 1, 0, 0, 0, 55, 0, 0, 9, 114, + 0, 16, 0, 0, 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 0, 0, 0, 0, 150, 7, 16, 0, 1, 0, 0, + 0, 29, 0, 0, 10, 114, 0, 16, 0, 1, 0, 0, 0, 2, 64, + 0, 0, 230, 174, 37, 61, 230, 174, 37, 61, 230, 174, 37, 61, 0, + 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, + 114, 0, 16, 0, 2, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, + 0, 2, 64, 0, 0, 145, 131, 158, 61, 145, 131, 158, 61, 145, 131, + 158, 61, 0, 0, 0, 0, 52, 0, 0, 10, 114, 0, 16, 0, 0, + 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 2, + 0, 0, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 174, 71, 97, 61, 174, + 71, 97, 61, 174, 71, 97, 61, 0, 0, 0, 0, 56, 0, 0, 10, + 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, + 0, 2, 64, 0, 0, 110, 167, 114, 63, 110, 167, 114, 63, 110, 167, + 114, 63, 0, 0, 0, 0, 47, 0, 0, 5, 114, 0, 16, 0, 0, + 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, + 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, + 0, 2, 64, 0, 0, 154, 153, 25, 64, 154, 153, 25, 64, 154, 153, + 25, 64, 0, 0, 0, 0, 25, 0, 0, 5, 114, 0, 16, 0, 0, + 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 55, 0, 0, 9, + 114, 32, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 1, 0, 0, + 0, 70, 2, 16, 0, 2, 0, 0, 0, 70, 2, 16, 0, 0, 0, + 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, 0, 0, 0, 0, 58, + 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, 84, + 116, 0, 0, 0, 36, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 17, 0, 0, 0, 4, 0, 0, 0, 4, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, }; namespace GpBinarizedShaders diff --git a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_ICC_D3D11.cpp b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_ICC_D3D11.cpp index 7c4c9b8..a96dd63 100644 --- a/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_ICC_D3D11.cpp +++ b/GpDisplayDriver_D3D11/CompiledShaders/DrawQuadRGBP_ICC_D3D11.cpp @@ -1,8 +1,8 @@ static unsigned char gs_shaderData[] = { - 68, 88, 66, 67, 108, 52, 221, 105, 109, 174, 81, 46, 155, 29, 71, - 86, 93, 178, 121, 166, 1, 0, 0, 0, 84, 7, 0, 0, 5, 0, + 68, 88, 66, 67, 57, 37, 253, 18, 22, 100, 108, 128, 58, 208, 65, + 95, 40, 243, 207, 218, 1, 0, 0, 0, 208, 7, 0, 0, 5, 0, 0, 0, 52, 0, 0, 0, 124, 2, 0, 0, 212, 2, 0, 0, 8, - 3, 0, 0, 216, 6, 0, 0, 82, 68, 69, 70, 64, 2, 0, 0, + 3, 0, 0, 84, 7, 0, 0, 82, 68, 69, 70, 64, 2, 0, 0, 1, 0, 0, 0, 132, 0, 0, 0, 2, 0, 0, 0, 28, 0, 0, 0, 0, 4, 255, 255, 0, 137, 0, 0, 24, 2, 0, 0, 92, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 255, @@ -51,7 +51,7 @@ static unsigned char gs_shaderData[] = { 0, 8, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 83, 86, 95, 84, 65, 82, 71, 69, 84, 0, 171, 171, 83, 72, 68, 82, - 200, 3, 0, 0, 64, 0, 0, 0, 242, 0, 0, 0, 89, 0, 0, + 68, 4, 0, 0, 64, 0, 0, 0, 17, 1, 0, 0, 89, 0, 0, 4, 70, 142, 32, 0, 0, 0, 0, 0, 3, 0, 0, 0, 88, 24, 0, 4, 0, 112, 16, 0, 0, 0, 0, 0, 85, 85, 0, 0, 98, 16, 0, 3, 50, 16, 16, 0, 1, 0, 0, 0, 101, 0, 0, 3, @@ -85,46 +85,54 @@ static unsigned char gs_shaderData[] = { 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 29, 0, 0, 7, 18, 0, 16, 0, 1, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, 0, 13, 0, - 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 57, 0, 0, 8, 18, + 4, 3, 10, 0, 16, 0, 1, 0, 0, 0, 24, 0, 0, 8, 18, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 16, 0, 0, - 10, 34, 0, 16, 0, 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, 154, 153, 153, 62, 154, 153, 25, 63, 205, - 204, 204, 61, 0, 0, 0, 0, 0, 0, 0, 9, 66, 0, 16, 0, - 1, 0, 0, 0, 10, 128, 32, 128, 65, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 128, 63, 56, 0, - 0, 8, 34, 0, 16, 0, 1, 0, 0, 0, 26, 0, 16, 0, 1, - 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 50, 0, 0, 9, 226, 0, 16, 0, 1, 0, 0, 0, 6, 9, 16, - 0, 0, 0, 0, 0, 166, 10, 16, 0, 1, 0, 0, 0, 86, 5, - 16, 0, 1, 0, 0, 0, 55, 32, 0, 9, 114, 0, 16, 0, 0, - 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, 150, 7, 16, 0, - 1, 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 47, 0, 0, - 5, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, 0, 0, 0, 0, 70, - 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 102, 102, 230, 63, - 102, 102, 230, 63, 102, 102, 230, 63, 0, 0, 0, 0, 25, 0, 0, - 5, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, 16, 0, 0, 0, - 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, 1, 0, 0, 0, 86, - 5, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 150, 246, 160, 189, - 43, 199, 117, 63, 40, 177, 243, 60, 0, 0, 0, 0, 50, 0, 0, - 12, 114, 0, 16, 0, 1, 0, 0, 0, 6, 0, 16, 0, 0, 0, - 0, 0, 2, 64, 0, 0, 87, 203, 136, 63, 86, 131, 197, 60, 225, - 104, 227, 58, 0, 0, 0, 0, 70, 2, 16, 0, 1, 0, 0, 0, - 50, 32, 0, 12, 114, 32, 16, 0, 0, 0, 0, 0, 166, 10, 16, - 0, 0, 0, 0, 0, 2, 64, 0, 0, 5, 9, 34, 60, 158, 151, - 129, 60, 194, 240, 119, 63, 0, 0, 0, 0, 70, 2, 16, 0, 1, - 0, 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, 0, 0, 0, 0, - 58, 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, - 84, 116, 0, 0, 0, 29, 0, 0, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 14, 0, 0, 0, 4, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 24, 0, 0, + 10, 226, 0, 16, 0, 1, 0, 0, 0, 6, 9, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, + 0, 128, 63, 0, 0, 0, 0, 1, 0, 0, 7, 34, 0, 16, 0, + 1, 0, 0, 0, 42, 0, 16, 0, 1, 0, 0, 0, 26, 0, 16, + 0, 1, 0, 0, 0, 1, 0, 0, 7, 34, 0, 16, 0, 1, 0, + 0, 0, 58, 0, 16, 0, 1, 0, 0, 0, 26, 0, 16, 0, 1, + 0, 0, 0, 60, 0, 0, 7, 18, 0, 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 1, 0, 0, 0, 10, 0, 16, 0, 1, 0, 0, + 0, 16, 0, 0, 10, 34, 0, 16, 0, 1, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 154, 153, 153, 62, 154, + 153, 25, 63, 205, 204, 204, 61, 0, 0, 0, 0, 0, 0, 0, 9, + 66, 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 128, 65, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 64, 0, 0, 0, 0, + 128, 63, 56, 0, 0, 8, 34, 0, 16, 0, 1, 0, 0, 0, 26, + 0, 16, 0, 1, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 50, 0, 0, 9, 226, 0, 16, 0, 1, 0, 0, + 0, 6, 9, 16, 0, 0, 0, 0, 0, 166, 10, 16, 0, 1, 0, + 0, 0, 86, 5, 16, 0, 1, 0, 0, 0, 55, 32, 0, 9, 114, + 0, 16, 0, 0, 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 0, 0, 0, 0, 150, 7, 16, 0, 1, 0, 0, + 0, 47, 0, 0, 5, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, 0, + 0, 0, 0, 70, 2, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, + 102, 102, 230, 63, 102, 102, 230, 63, 102, 102, 230, 63, 0, 0, 0, + 0, 25, 0, 0, 5, 114, 0, 16, 0, 0, 0, 0, 0, 70, 2, + 16, 0, 0, 0, 0, 0, 56, 0, 0, 10, 114, 0, 16, 0, 1, + 0, 0, 0, 86, 5, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, + 150, 246, 160, 189, 43, 199, 117, 63, 40, 177, 243, 60, 0, 0, 0, + 0, 50, 0, 0, 12, 114, 0, 16, 0, 1, 0, 0, 0, 6, 0, + 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 87, 203, 136, 63, 86, + 131, 197, 60, 225, 104, 227, 58, 0, 0, 0, 0, 70, 2, 16, 0, + 1, 0, 0, 0, 50, 32, 0, 12, 114, 32, 16, 0, 0, 0, 0, + 0, 166, 10, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 5, 9, + 34, 60, 158, 151, 129, 60, 194, 240, 119, 63, 0, 0, 0, 0, 70, + 2, 16, 0, 1, 0, 0, 0, 54, 0, 0, 5, 130, 32, 16, 0, + 0, 0, 0, 0, 58, 0, 16, 0, 0, 0, 0, 0, 62, 0, 0, + 1, 83, 84, 65, 84, 116, 0, 0, 0, 33, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 4, + 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, }; namespace GpBinarizedShaders diff --git a/ShaderSrc/Functions.h b/ShaderSrc/Functions.h index 17cc3c9..00f383e 100644 --- a/ShaderSrc/Functions.h +++ b/ShaderSrc/Functions.h @@ -3,7 +3,7 @@ float SRGBToLinear(float v) if (v <= 0.04045) return v * (1.0 / 12.92); else - return pow(((v + 0.055) * (1.0 / 1.055)), 2.4); + return pow(((max(v, 0.0) + 0.055) * (1.0 / 1.055)), 2.4); } float2 SRGBToLinear(float2 v) @@ -47,8 +47,8 @@ float4 ApplyFlicker(int2 coordinate, int startThreshold, int endThreshold, float float4 ApplyDesaturation(float desaturation, float4 color) { - // This is intentionally done in gamma space - if (desaturation == 0.0) + // This is intentionally done in gamma space, and keeps solid yellow + if (desaturation == 0.0 || all(color.rgb == float3(1.0, 1.0, 0.0))) return color; float grayLevel = dot(color.rgb, float3(3.0, 6.0, 1.0) / 10.0); From 0de26b5e71474653bf0368d4e0112f75ac9b349a Mon Sep 17 00:00:00 2001 From: elasota Date: Tue, 4 May 2021 18:26:33 -0400 Subject: [PATCH 03/31] Remove header guards --- PortabilityLayer/MacBinary2.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/PortabilityLayer/MacBinary2.h b/PortabilityLayer/MacBinary2.h index 758414d..ec697f4 100644 --- a/PortabilityLayer/MacBinary2.h +++ b/PortabilityLayer/MacBinary2.h @@ -1,8 +1,5 @@ #pragma once -#ifndef __PL_MACBINARY2_H__ -#define __PL_MACBINARY2_H__ - class GpIOStream; namespace PortabilityLayer @@ -15,5 +12,3 @@ namespace PortabilityLayer MacFileMem *ReadBin(GpIOStream *stream); }; } - -#endif From b0d5673d957a5c9382e2b9961aee195658a7d3db Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:12:58 -0400 Subject: [PATCH 04/31] Add export dir to Windows --- Aerofoil/GpFileSystem_Win32.cpp | 11 ++++++++++- Aerofoil/GpFileSystem_Win32.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Aerofoil/GpFileSystem_Win32.cpp b/Aerofoil/GpFileSystem_Win32.cpp index 14e98ed..77e7be6 100644 --- a/Aerofoil/GpFileSystem_Win32.cpp +++ b/Aerofoil/GpFileSystem_Win32.cpp @@ -115,6 +115,7 @@ GpFileSystem_Win32::GpFileSystem_Win32(IGpAllocator *alloc) , m_userHousesDir(alloc) , m_userSavesDir(alloc) , m_resourcesDir(alloc) + , m_exportDir(alloc) { m_executablePath[0] = 0; } @@ -155,18 +156,23 @@ bool GpFileSystem_Win32::Init() if (!m_logsDir.Set(m_prefsDir) || !m_logsDir.Append(L"\\Logs")) return false; + if (!m_exportDir.Set(m_prefsDir) || !m_exportDir.Append(L"\\Export")) + return false; + CreateDirectoryW(m_prefsDir.Buffer(), nullptr); CreateDirectoryW(m_scoresDir.Buffer(), nullptr); CreateDirectoryW(m_userHousesDir.Buffer(), nullptr); CreateDirectoryW(m_userSavesDir.Buffer(), nullptr); CreateDirectoryW(m_logsDir.Buffer(), nullptr); + CreateDirectoryW(m_exportDir.Buffer(), nullptr); if (!m_prefsDir.Append(L"\\") || !m_scoresDir.Append(L"\\") || !m_userHousesDir.Append(L"\\") || !m_userSavesDir.Append(L"\\") || !m_logsDir.Append(L"\\") || - !m_resourcesDir.Append(L"\\")) + !m_resourcesDir.Append(L"\\") || + !m_exportDir.Append(L"\\")) return false; DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH); @@ -509,6 +515,9 @@ bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtua case PortabilityLayer::VirtualDirectories::kLogs: baseDir = m_logsDir.Buffer(); break; + case PortabilityLayer::VirtualDirectories::kSourceExport: + baseDir = m_exportDir.Buffer(); + break; default: return false; } diff --git a/Aerofoil/GpFileSystem_Win32.h b/Aerofoil/GpFileSystem_Win32.h index 8b75eb7..9e0ab79 100644 --- a/Aerofoil/GpFileSystem_Win32.h +++ b/Aerofoil/GpFileSystem_Win32.h @@ -42,6 +42,7 @@ private: GpWString m_userHousesDir; GpWString m_userSavesDir; GpWString m_resourcesDir; + GpWString m_exportDir; wchar_t m_executablePath[MAX_PATH]; IGpAllocator *m_alloc; From c3b2a7e8af906b5a2566e554b526dbef094af1df Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:14:50 -0400 Subject: [PATCH 05/31] EOL fix --- PortabilityLayer/QDPictEmitContext.h | 72 ++++++++++++++-------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/PortabilityLayer/QDPictEmitContext.h b/PortabilityLayer/QDPictEmitContext.h index f55f5fb..6d33b26 100644 --- a/PortabilityLayer/QDPictEmitContext.h +++ b/PortabilityLayer/QDPictEmitContext.h @@ -1,32 +1,32 @@ -#pragma once - -#include -#include - +#pragma once + +#include +#include + struct Rect; -class GpIOStream; - -namespace PortabilityLayer -{ - struct RGBAColor; - struct QDPictEmitScanlineParameters; - - enum QDPictBlitSourceType - { - QDPictBlitSourceType_1Bit, - QDPictBlitSourceType_Indexed1Bit, - QDPictBlitSourceType_Indexed2Bit, - QDPictBlitSourceType_Indexed4Bit, - QDPictBlitSourceType_Indexed8Bit, - QDPictBlitSourceType_RGB15, - QDPictBlitSourceType_RGB24_Interleaved, - QDPictBlitSourceType_RGB24_Multiplane, - }; - - bool QDPictBlitSourceType_IsIndexed(QDPictBlitSourceType sourceType); - - class QDPictEmitContext - { +class GpIOStream; + +namespace PortabilityLayer +{ + struct RGBAColor; + struct QDPictEmitScanlineParameters; + + enum QDPictBlitSourceType + { + QDPictBlitSourceType_1Bit, + QDPictBlitSourceType_Indexed1Bit, + QDPictBlitSourceType_Indexed2Bit, + QDPictBlitSourceType_Indexed4Bit, + QDPictBlitSourceType_Indexed8Bit, + QDPictBlitSourceType_RGB15, + QDPictBlitSourceType_RGB24_Interleaved, + QDPictBlitSourceType_RGB24_Multiplane, + }; + + bool QDPictBlitSourceType_IsIndexed(QDPictBlitSourceType sourceType); + + class QDPictEmitContext + { public: enum ErrorCode { @@ -40,14 +40,14 @@ namespace PortabilityLayer kMalformedOpcode, kUnsupportedOpcode, }; - - virtual bool SpecifyFrame(const Rect &rect) = 0; - virtual Rect ConstrainRegion(const Rect &rect) const = 0; - virtual void Start(QDPictBlitSourceType sourceType, const QDPictEmitScanlineParameters ¶ms) = 0; - virtual void BlitScanlineAndAdvance(const void *) = 0; - virtual bool EmitQTContent(GpIOStream *stream, uint32_t dataSize, bool isCompressed) = 0; + + virtual bool SpecifyFrame(const Rect &rect) = 0; + virtual Rect ConstrainRegion(const Rect &rect) const = 0; + virtual void Start(QDPictBlitSourceType sourceType, const QDPictEmitScanlineParameters ¶ms) = 0; + virtual void BlitScanlineAndAdvance(const void *) = 0; + virtual bool EmitQTContent(GpIOStream *stream, uint32_t dataSize, bool isCompressed) = 0; virtual bool AllocTempBuffers(uint8_t *&buffer1, size_t buffer1Size, uint8_t *&buffer2, size_t buffer2Size) = 0; - virtual void ReportError(int errorType, int errorSubtype) { } - }; + virtual void ReportError(int errorType, int errorSubtype) { } + }; } From 6d12b6ff1a7c70d15f431e5826cea8817a67ed95 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:16:25 -0400 Subject: [PATCH 06/31] Add house export to room editor --- GpApp/Externs.h | 2 + GpApp/GliderDefines.h | 1 + GpApp/GliderProtos.h | 1 + GpApp/HouseIO.cpp | 1283 ++++++++++++++++++++++++ GpApp/InterfaceInit.cpp | 9 +- GpApp/Menu.cpp | 33 +- GpApp/Sound.cpp | 45 +- GpCommon/GpVector.h | 67 +- PortabilityLayer/GPArchive.cpp | 3 +- PortabilityLayer/GPArchive.h | 4 +- PortabilityLayer/MacBinary2.cpp | 16 +- PortabilityLayer/MacBinary2.h | 5 + PortabilityLayer/MenuManager.cpp | 55 + PortabilityLayer/MenuManager.h | 1 + PortabilityLayer/PLQDraw.cpp | 261 ++++- PortabilityLayer/PLResourceManager.cpp | 149 ++- PortabilityLayer/QDPictHeader.cpp | 4 +- PortabilityLayer/ResourceManager.h | 19 + 18 files changed, 1883 insertions(+), 75 deletions(-) diff --git a/GpApp/Externs.h b/GpApp/Externs.h index a2c4a55..2be06cc 100644 --- a/GpApp/Externs.h +++ b/GpApp/Externs.h @@ -75,6 +75,8 @@ namespace PortabilityLayer #define iObjectWindow 20 #define iCoordinateWindow 21 +#define iExportGliderPROHouse 1 + //-------------------------------------------------------------- Structs /* typedef short SICN[16]; diff --git a/GpApp/GliderDefines.h b/GpApp/GliderDefines.h index 5e167a0..55944ff 100644 --- a/GpApp/GliderDefines.h +++ b/GpApp/GliderDefines.h @@ -187,6 +187,7 @@ #define kGameMenuID 129 #define kOptionsMenuID 130 #define kHouseMenuID 131 +#define kExportMenuID 132 #define kSplashMode 0 #define kEditMode 1 diff --git a/GpApp/GliderProtos.h b/GpApp/GliderProtos.h index a40734a..2f4aa90 100644 --- a/GpApp/GliderProtos.h +++ b/GpApp/GliderProtos.h @@ -119,6 +119,7 @@ void GenerateRetroLinks (void); void DoGoToDialog (void); void ConvertHouseVer1To2 (void); void ShiftWholeHouse (SInt16); +void ExportHouse (void); void DoHouseInfo (void); // --- HouseInfo.c diff --git a/GpApp/HouseIO.cpp b/GpApp/HouseIO.cpp index e0cb0f7..0037179 100644 --- a/GpApp/HouseIO.cpp +++ b/GpApp/HouseIO.cpp @@ -25,6 +25,14 @@ #include "PLStringCompare.h" #include "PLPasStr.h" +#include "MacFileInfo.h" +#include "GpIOStream.h" +#include "GpVector.h" +#include "MacBinary2.h" +#include "QDPictOpcodes.h" +#include "QDPixMap.h" +#include "PLStandardColors.h" + #define kSaveChangesAlert 1002 #define kSaveChanges 1 #define kDiscardChanges 2 @@ -50,6 +58,7 @@ extern short numberRooms, housesFound; extern Boolean noRoomAtAll, quitting, wardBitSet; extern Boolean phoneBitSet, bannerStarCountOn; +bool ParseAndConvertSoundChecked(const THandle &handle, void const*& outDataContents, size_t &outDataSize); //============================================================== Functions @@ -2316,3 +2325,1277 @@ THandle LoadHouseResource(const PortabilityLayer::ResTypeID &resTypeID, in return PortabilityLayer::ResourceManager::GetInstance()->GetAppResource(resTypeID, resID); } + +//-------------------------------------------------------------- ExportHouse + +namespace ExportHouseResults +{ + enum ExportHouseResult + { + kOK, + + kStreamFailed, + kIOError, + kMemError, + kResourceError, + kInternalError, + }; +} + +typedef ExportHouseResults::ExportHouseResult ExportHouseResult_t; + +struct SimpleResource +{ + PortabilityLayer::ResTypeID m_resType; + int m_resourceID; + PortabilityLayer::PascalStr<255> m_name; + size_t m_offsetInResData; + uint8_t m_attributes; +}; + +static bool AppendRaw(GpVector &bytes, const void *data, size_t size) +{ + for (size_t i = 0; i < size; i++) + { + if (!bytes.Append(static_cast(data)[i])) + return false; + } + + return true; +} + +template +static bool AppendRawStruct(GpVector &bytes, const T &value) +{ + return AppendRaw(bytes, &value, sizeof(T)); +} + +static ExportHouseResult_t TryExportSound(GpVector &resData, const THandle &resHandle) +{ + const void *dataContents = nullptr; + size_t dataSize = 0; + if (!ParseAndConvertSoundChecked(resHandle, dataContents, dataSize)) + return ExportHouseResults::kResourceError; + + // Don't ask... + const uint8_t commandStreamPrefix[20] = { 0, 1, 0, 1, 0, 5, 0, 0, 0, 0xa0, 0, 1, 0x80, 0x51, 0, 0, 0, 0, 0, 0x14 }; + + struct BufferHeader + { + BEUInt32_t m_samplePtr; + BEUInt32_t m_length; + BEFixed32_t m_sampleRate; + BEUInt32_t m_loopStart; + BEUInt32_t m_loopEnd; + uint8_t m_encoding; + uint8_t m_baseFrequency; + }; + + BufferHeader bufferHeader; + bufferHeader.m_samplePtr = 0; + bufferHeader.m_length = static_cast(dataSize); + bufferHeader.m_sampleRate.m_intPart = 0x56ee; + bufferHeader.m_sampleRate.m_fracPart = 0x8ba3; + bufferHeader.m_loopStart = static_cast(dataSize - 2); + bufferHeader.m_loopEnd = static_cast(dataSize - 1); + bufferHeader.m_encoding = 0; + bufferHeader.m_baseFrequency = 0x3c; + + if (!resData.Resize(sizeof(bufferHeader) + sizeof(commandStreamPrefix) + dataSize)) + return ExportHouseResults::kMemError; + + memcpy(&resData[0], commandStreamPrefix, sizeof(commandStreamPrefix)); + memcpy(&resData[sizeof(commandStreamPrefix)], &bufferHeader, sizeof(bufferHeader)); + + if (dataSize > 0) + memcpy(&resData[sizeof(commandStreamPrefix) + sizeof(bufferHeader)], dataContents, dataSize); + + return ExportHouseResults::kOK; +} + +static void BitSwap4(GpVector &vec, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + uint8_t v = vec[i]; + v = (((v >> 4) & 0xf) | ((v << 4) & 0xf)); + vec[i] = v; + } +} + +static void BitSwap2(GpVector &vec, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + uint8_t v = vec[i]; + v = (((v >> 2) & 0x33) | ((v << 2) & 0xcc)); + vec[i] = v; + } +} + +static void BitSwap1(GpVector &vec, size_t count) +{ + for (size_t i = 0; i < count; i++) + { + uint8_t v = vec[i]; + v = (((v >> 1) & 0x55) | ((v << 1) & 0xaa)); + vec[i] = v; + } +} + +namespace RLEEncoder +{ + static const size_t kMaxRepeat = 129; + static const size_t kMaxLiteral = 128; + + bool EmitSymbol(GpVector &compressedData, uint8_t sym) + { + return compressedData.Append(sym); + } + + bool EmitSymbol(GpVector &compressedData, uint16_t sym) + { + return compressedData.Append((sym >> 8) & 0xff) && compressedData.Append(sym & 0xff); + } + + template + bool EmitLiterals(GpVector &compressedData, const T *symbols, size_t length) + { + if (length == 0) + return true; + + assert(length <= kMaxLiteral); + if (!compressedData.Append(static_cast(length - 1))) + return false; + + for (size_t i = 0; i < length; i++) + { + if (!EmitSymbol(compressedData, symbols[i])) + return false; + } + + return true; + } + + template + bool EmitRepeat(GpVector &compressedData, const T &symbol, size_t length) + { + if (length < 2) + return EmitLiterals(compressedData, &symbol, length); + + assert(length <= kMaxRepeat); + if (!compressedData.Append(static_cast(257 - length))) + return false; + + if (!EmitSymbol(compressedData, symbol)) + return false; + + return true; + } + + + template + bool PackRLE(GpVector &compressedData, const GpVector &uncompressedData) + { + size_t numUncompressed = uncompressedData.Count(); + const T *uncompressedSymbols = uncompressedData.Buffer(); + + if (!compressedData.Resize(0)) + return false; + + size_t literalStartLoc = 0; + size_t repeatStartLoc = 0; + size_t readPos = 0; + + // Loop/exit invariants: + // repeatStartLoc - literalStartLoc <= kMaxLiteral + // i - repeatStartLoc < kMaxRepeat + for (size_t i = 0; i < numUncompressed; i++) + { + T b = uncompressedSymbols[i]; + if (b != uncompressedSymbols[repeatStartLoc]) + { + // Run terminates at i + const size_t repeatLength = i - repeatStartLoc; + const size_t literalLength = repeatStartLoc - literalStartLoc; + + // Determine if we should flush the repeat or fold it into the literal span. + // There are several situations that can happen here: + // Repeat length is 1: + // Literal span is at limit: + // Emit literal span, start new literal span at repeatStartLoc + // Literal span is below limit: + // Do nothing + // Repeat length is 2: + // Literal span is 0: + // Emit repeat + // Literal span is non-zero and appending repeat to literal span would be at or exceed limit: + // Emit literal span and repeat + // Otherwise: + // Do nothing + // Repeat length is 3+: + // Emit literal span and repeat + if (repeatLength == 1) + { + if (literalLength == kMaxLiteral) + { + if (!EmitLiterals(compressedData, uncompressedSymbols + literalStartLoc, literalLength)) + return false; + + literalStartLoc = repeatStartLoc; + } + } + else if (repeatLength == 2) + { + if (literalLength == 0 || (literalLength + repeatLength >= kMaxLiteral)) + { + if (literalLength != 0) + { + if (!EmitLiterals(compressedData, uncompressedSymbols + literalStartLoc, literalLength)) + return false; + } + + if (!EmitRepeat(compressedData, uncompressedSymbols[repeatStartLoc], repeatLength)) + return false; + + literalStartLoc = i; + } + } + else if (repeatLength >= 3) + { + if (literalLength != 0) + { + if (!EmitLiterals(compressedData, uncompressedSymbols + literalStartLoc, literalLength)) + return false; + } + + if (!EmitRepeat(compressedData, uncompressedSymbols[repeatStartLoc], repeatLength)) + return false; + + literalStartLoc = i; + } + + repeatStartLoc = i; + } + else + { + // i is a repeat character + const size_t repeatLength = i + 1 - repeatStartLoc; + const size_t literalLength = repeatStartLoc - literalStartLoc; + + if (repeatLength == kMaxRepeat) + { + if (literalLength != 0) + { + if (!EmitLiterals(compressedData, uncompressedSymbols + literalStartLoc, literalLength)) + return false; + } + + if (!EmitRepeat(compressedData, uncompressedSymbols[repeatStartLoc], repeatLength)) + return false; + + literalStartLoc = i + 1; + repeatStartLoc = i + 1; + } + } + } + + // Final flush + size_t repeatLength = numUncompressed - repeatStartLoc; + size_t literalLength = repeatStartLoc - literalStartLoc; + + if (repeatLength == 1) + { + if (literalLength < kMaxLiteral) + { + literalLength++; + repeatLength = 0; + } + } + + if (literalLength != 0) + { + if (!EmitLiterals(compressedData, uncompressedSymbols + literalStartLoc, literalLength)) + return false; + } + + if (repeatLength == 1) + { + if (!EmitLiterals(compressedData, uncompressedSymbols + repeatStartLoc, 1)) + return false; + } + else if (repeatLength >= 2) + { + if (!EmitRepeat(compressedData, uncompressedSymbols[repeatStartLoc], repeatLength)) + return false; + } + + return true; + } +} + +static ExportHouseResult_t TryExportPictFromSurface(GpVector &resData, DrawSurface *surface) +{ + bool couldBe16Bit = true; + bool couldBe8Bit = true; + int numUniqueColors = 0; + PortabilityLayer::RGBAColor uniqueColors[256]; + for (int i = 0; i < 256; i++) + uniqueColors[i] = PortabilityLayer::RGBAColor::Create(0, 0, 0, 255); + + const Rect rect = surface->m_port.GetRect(); + + const size_t width = rect.Width(); + const size_t height = rect.Height(); + + THandle pixMapHdl = surface->m_port.GetPixMap(); + const PixMap *pixMap = *pixMapHdl; + const uint8_t *imageData = static_cast(pixMap->m_data); + const size_t pixelDataPitch = pixMap->m_pitch; + + assert(pixMap->m_pixelFormat == GpPixelFormats::kRGB32); + + + for (size_t row = 0; row < height; row++) + { + const uint8_t *rowData = imageData + pixMap->m_pitch * row; + + if (!couldBe8Bit && !couldBe16Bit) + break; + + for (size_t col = 0; col < width; col++) + { + const uint8_t *pixelData = rowData + col * 4; + if (couldBe16Bit) + { + for (int ch = 0; ch < 3; ch++) + { + uint8_t channelData = pixelData[ch]; + if ((channelData >> 2) != (channelData & 0x7)) + { + couldBe16Bit = false; + break; + } + } + } + + if (couldBe8Bit) + { + PortabilityLayer::RGBAColor rgbaColor = PortabilityLayer::RGBAColor::Create(pixelData[0], pixelData[1], pixelData[2], pixelData[3]); + + bool matchedColor = false; + for (int i = 0; i < numUniqueColors; i++) + { + if (uniqueColors[i] == rgbaColor) + { + matchedColor = true; + break; + } + } + + if (!matchedColor) + { + if (numUniqueColors == 256) + couldBe8Bit = false; + else + uniqueColors[numUniqueColors++] = rgbaColor; + } + } + } + } + + bool isBWBitmap = false; + + if (numUniqueColors <= 2) + { + isBWBitmap = true; + for (int c = 0; c < numUniqueColors; c++) + { + if (uniqueColors[c] != StdColors::Black() && uniqueColors[c] != StdColors::White()) + isBWBitmap = false; + } + + if (isBWBitmap) + { + numUniqueColors = 2; + uniqueColors[0] = StdColors::White(); + uniqueColors[1] = StdColors::Black(); + } + } + + int bpp = 0; + if (isBWBitmap) + bpp = 1; + else if (couldBe8Bit) + { + if (numUniqueColors <= 2) + bpp = 1; + else if (numUniqueColors <= 4) + bpp = 2; + else if (numUniqueColors <= 16) + bpp = 4; + else + bpp = 8; + } + else if (couldBe16Bit) + bpp = 16; + else + bpp = 32; + + // The typical structure of a PICT is header, ClipRegion, then a raster op. + // We use V1 pict for 1bpp and V2 for all others. + struct PictHeader + { + uint8_t m_size[2]; + + BERect m_rect; + }; + + BERect beRect; + beRect.top = beRect.left = 0; + beRect.right = static_cast(width); + beRect.bottom = static_cast(height); + + PictHeader pictHeader; + pictHeader.m_size[0] = 0; + pictHeader.m_size[1] = 0; + pictHeader.m_rect = beRect; + + if (!AppendRawStruct(resData, pictHeader)) + return ExportHouseResults::kMemError; + + int pictVersion = 1; + if (isBWBitmap) + { + const uint8_t versionTag[2] = { 0x11, 0x01 }; + if (!AppendRaw(resData, versionTag, 2)) + return ExportHouseResults::kMemError; + } + else + { + pictVersion = 2; + + struct PictV2Header + { + BEUInt16_t m_versionTag; + BEUInt16_t m_versionOp; + BEUInt16_t m_headerOp; + BEInt16_t m_v2Version; + BEInt16_t m_reserved1; + BEFixed32_t m_top; + BEFixed32_t m_left; + BEFixed32_t m_bottom; + BEFixed32_t m_right; + BEUInt32_t m_reserved2; + }; + + GP_STATIC_ASSERT(sizeof(PictV2Header) == 30); + + PictV2Header v2Header; + v2Header.m_versionTag = 0x0011; + v2Header.m_versionOp = 0x02ff; + v2Header.m_headerOp = 0x0c00; + v2Header.m_v2Version = -1; + v2Header.m_reserved1 = -1; + v2Header.m_top.m_intPart = beRect.top; + v2Header.m_top.m_fracPart = 0; + v2Header.m_left.m_intPart = beRect.left; + v2Header.m_left.m_fracPart = 0; + v2Header.m_bottom.m_intPart = beRect.bottom; + v2Header.m_bottom.m_fracPart = 0; + v2Header.m_right.m_intPart = beRect.right; + v2Header.m_right.m_fracPart = 0; + + if (!AppendRawStruct(resData, v2Header)) + return ExportHouseResults::kMemError; + } + + // Emit ClipRgn opcode + if (pictVersion == 1) + { + const uint8_t clipRgnOpcode[1] = { PortabilityLayer::QDOpcodes::kClipRegion }; + if (!AppendRaw(resData, clipRgnOpcode, 1)) + return ExportHouseResults::kMemError; + } + else if (pictVersion == 2) + { + const uint8_t clipRgnOpcode[2] = { 0, PortabilityLayer::QDOpcodes::kClipRegion }; + if (!AppendRaw(resData, clipRgnOpcode, 2)) + return ExportHouseResults::kMemError; + } + + struct ClipRgnData + { + BEUInt16_t m_structureSize; + BERect m_rect; + }; + + GP_STATIC_ASSERT(sizeof(ClipRgnData) == 10); + + ClipRgnData clipRgnData; + clipRgnData.m_structureSize = sizeof(ClipRgnData); + clipRgnData.m_rect = beRect; + + if (!AppendRawStruct(resData, clipRgnData)) + return ExportHouseResults::kMemError; + + // Emit image + const size_t bitsPerRow = width * bpp; + const size_t bytesPerRow = (bitsPerRow + 7) / 8; + const size_t expansionCapacity = bytesPerRow + (bytesPerRow / 128) + 16; // Worst-case scenario for RLE failure to compress + + uint16_t bitmapOpcode = 0; + int packType = 0; + bool isDirect = false; + if (bpp <= 8) + { + if (bytesPerRow < 8) + { + packType = 1; + bitmapOpcode = PortabilityLayer::QDOpcodes::kBitsRect; + } + else + { + packType = 0; + bitmapOpcode = PortabilityLayer::QDOpcodes::kPackBitsRect; + } + } + else + { + isDirect = true; + bitmapOpcode = PortabilityLayer::QDOpcodes::kDirectBitsRect; + + if (bpp == 16) + packType = 3; + else if (bpp == 32) + packType = 4; + else + return ExportHouseResults::kInternalError; + } + + if (pictVersion == 1) + { + const uint8_t opcode = bitmapOpcode; + if (!AppendRaw(resData, &opcode, 1)) + return ExportHouseResults::kMemError; + } + else if (pictVersion == 2) + { + const BEUInt16_t opcode(bitmapOpcode); + if (!AppendRaw(resData, &opcode, 2)) + return ExportHouseResults::kMemError; + } + + // Write prelude + const bool isPixmap = !isBWBitmap; + { + if (isDirect) + { + struct DirectPrelude + { + BEUInt32_t m_baseAddress; + BEUInt16_t m_rowSize; + }; + + DirectPrelude prelude; + prelude.m_baseAddress = 0; + prelude.m_rowSize = static_cast(0x8000 | bytesPerRow); + + if (!AppendRawStruct(resData, prelude)) + return ExportHouseResults::kMemError; + } + else + { + uint16_t rowSize = bytesPerRow; + if (!isBWBitmap) + rowSize |= 0x8000; + + BEUInt16_t rowSizeBE(rowSize); + + if (!AppendRawStruct(resData, rowSizeBE)) + return ExportHouseResults::kMemError; + } + } + + // Do actual image packing, we need to do this now so we have the pack size available + GpVector packedImage(PLDrivers::GetAlloc()); + + GpVector uncompressedRowData8(PLDrivers::GetAlloc()); + GpVector uncompressedRowData16(PLDrivers::GetAlloc()); + GpVector compressedRowData(PLDrivers::GetAlloc()); + + if (packType == 4) + { + if (!uncompressedRowData8.Resize(bytesPerRow)) + return ExportHouseResults::kMemError; + } + else + { + if (!uncompressedRowData16.Resize(bytesPerRow / 2)) + return ExportHouseResults::kMemError; + } + + if (!compressedRowData.Resize(expansionCapacity)) + return ExportHouseResults::kMemError; + + for (size_t row = 0; row < height; row++) + { + if (!uncompressedRowData8.Resize(0)) + return ExportHouseResults::kMemError; + + if (!uncompressedRowData16.Resize(0)) + return ExportHouseResults::kMemError; + + const uint8_t *srcRowStart = imageData + pixelDataPitch * row; + + if (packType == 4) + { + // RGB24 images + for (size_t ch = 0; ch < 3; ch++) + { + for (size_t col = 0; col < width; col++) + { + const uint8_t *srcPixelStart = srcRowStart + col * 4; + if (!uncompressedRowData8.Append(srcPixelStart[ch])) + return ExportHouseResults::kMemError; + } + } + } + else if (couldBe16Bit) + { + assert(packType == 3); + for (size_t col = 0; col < width; col++) + { + const uint8_t *srcPixelStart = srcRowStart + col * 4; + uint16_t packed = ((srcPixelStart[0] << 7) & 0x7c00) | ((srcPixelStart[1] << 2) & 0x3e0) | ((srcPixelStart[2] >> 3) & 0x1f); + if (!uncompressedRowData16.Append(packed)) + return ExportHouseResults::kMemError; + } + } + else + { + assert(couldBe8Bit); + + int numBitsSpooled = 0; + uint8_t spooledBits = 0; + for (size_t col = 0; col < width; col++) + { + const uint8_t *srcPixelStart = srcRowStart + col * 4; + PortabilityLayer::RGBAColor color = PortabilityLayer::RGBAColor::Create(srcPixelStart[0], srcPixelStart[1], srcPixelStart[2], srcPixelStart[3]); + int colorIndex = -1; + for (int ci = 0; ci < numUniqueColors; ci++) + { + if (color == uniqueColors[ci]) + { + colorIndex = ci; + break; + } + } + + assert(colorIndex >= 0); + + spooledBits <<= bpp; + spooledBits |= colorIndex; + numBitsSpooled += bpp; + + if (numBitsSpooled == 8) + { + if (!uncompressedRowData8.Append(spooledBits)) + return ExportHouseResults::kMemError; + + numBitsSpooled = 0; + spooledBits = 0; + } + } + + if (numBitsSpooled != 0) + { + spooledBits <<= (8 - numBitsSpooled); + if (!uncompressedRowData8.Append(spooledBits)) + return ExportHouseResults::kMemError; + } + } + + if (!compressedRowData.Resize(0)) + return ExportHouseResults::kMemError; + + bool needsLengthMarker = false; + switch (packType) + { + case 0: + case 4: + // 8-bit RLE + if (!RLEEncoder::PackRLE(compressedRowData, uncompressedRowData8)) + return ExportHouseResults::kMemError; + + needsLengthMarker = true; + break; + case 1: + // Uncompressed + if (!compressedRowData.Resize(bytesPerRow)) + return ExportHouseResults::kMemError; + + for (size_t i = 0; i < bytesPerRow; i++) + compressedRowData[i] = uncompressedRowData8[i]; + + needsLengthMarker = false; + break; + case 3: + // 16-bit RLE + if (!RLEEncoder::PackRLE(compressedRowData, uncompressedRowData16)) + return ExportHouseResults::kMemError; + needsLengthMarker = true; + break; + default: + assert(false); + return ExportHouseResults::kInternalError; + }; + + const size_t compressedSize = compressedRowData.Count(); + if (needsLengthMarker) + { + if (bytesPerRow > 250) + packedImage.Append((compressedSize >> 8) & 0xff); + packedImage.Append(compressedSize & 0xff); + } + + for (size_t i = 0; i < compressedSize; i++) + packedImage.Append(compressedRowData[i]); + } + + + // Write BitMap/PixMap + { + if (isBWBitmap) + { + struct BitMapData + { + BEBitMap m_bitMap; + BERect m_srcRect; + BERect m_destRect; + BEUInt16_t m_transferMode; + }; + + BitMapData bmData; + bmData.m_bitMap.m_bounds = beRect; + bmData.m_srcRect = beRect; + bmData.m_destRect = beRect; + bmData.m_transferMode = 0; + + if (!AppendRawStruct(resData, bmData)) + return ExportHouseResults::kMemError; + } + else + { + BEPixMap pixMap; + pixMap.m_bounds = beRect; + pixMap.m_version = 0; + pixMap.m_packType = packType; + pixMap.m_packSize = static_cast(packedImage.Count()); + pixMap.m_hRes = 0x480000; + pixMap.m_vRes = 0x480000; + pixMap.m_pixelType = (isDirect ? 16 : 0); + pixMap.m_pixelSize = bpp; + pixMap.m_componentCount = isDirect ? 3 : 1; + + if (bpp == 32) + pixMap.m_componentSize = 8; + else if (bpp == 16) + pixMap.m_componentSize = 5; + else + pixMap.m_componentSize = bpp; + + pixMap.m_planeSizeBytes = 0; + pixMap.m_clutHandle = 0; + pixMap.m_unused = 0; + + if (!AppendRawStruct(resData, pixMap)) + return ExportHouseResults::kMemError; + + if (isDirect) + { + } + else + { + BEColorTableHeader clutHeader; + clutHeader.m_resourceID = 0; + clutHeader.m_flags = 0; + clutHeader.m_numItemsMinusOne = numUniqueColors - 1; + + if (!AppendRawStruct(resData, clutHeader)) + return ExportHouseResults::kMemError; + + for (int i = 0; i < numUniqueColors; i++) + { + BEColorTableItem item; + item.m_index = i; + item.m_red[0] = item.m_red[1] = uniqueColors[i].r; + item.m_green[0] = item.m_green[1] = uniqueColors[i].g; + item.m_blue[0] = item.m_blue[1] = uniqueColors[i].b; + + if (!AppendRawStruct(resData, item)) + return ExportHouseResults::kMemError; + } + } + + struct TransferData + { + BERect m_srcRect; + BERect m_destRect; + BEUInt16_t m_transferMode; + }; + + TransferData transferData; + transferData.m_srcRect = beRect; + transferData.m_destRect = beRect; + transferData.m_transferMode = 0; + + if (!AppendRawStruct(resData, transferData)) + return ExportHouseResults::kMemError; + } + } + + // Write image contents + if (!AppendRaw(resData, &packedImage[0], packedImage.Count())) + return ExportHouseResults::kMemError; + + // Write pad byte (??) + if (!isBWBitmap && (resData.Count() & 1) != 0) + { + if (!resData.Append(0)) + return ExportHouseResults::kMemError; + } + + // Emit EOP opcode + if (pictVersion == 1) + { + const uint8_t eopOpcode[1] = { PortabilityLayer::QDOpcodes::kEndOfPicture }; + if (!AppendRaw(resData, eopOpcode, 1)) + return ExportHouseResults::kMemError; + } + else if (pictVersion == 2) + { + const uint8_t eopOpcode[2] = { 0, PortabilityLayer::QDOpcodes::kEndOfPicture }; + if (!AppendRaw(resData, eopOpcode, 2)) + return ExportHouseResults::kMemError; + } + + return ExportHouseResults::kOK; +} + +static ExportHouseResult_t TryExportPICT(GpVector &resData, const THandle &resHandle) +{ + // Parse bitmap header + const THandle bmpHandle = resHandle.StaticCast(); + const BitmapImage *bmp = *bmpHandle; + + const Rect rect = bmp->GetRect(); + DrawSurface *surface = nullptr; + if (NewGWorld(&surface, GpPixelFormats::kRGB32, &rect, nullptr) != PLErrors::kNone) + return ExportHouseResults::kMemError; + + surface->DrawPicture(bmpHandle, rect, false); + + ExportHouseResult_t result = TryExportPictFromSurface(resData, surface); + + DisposeGWorld(surface); + + return result; +} + +static ExportHouseResult_t TryExportResource(GpVector &resData, PortabilityLayer::IResourceArchive *resArchive, const PortabilityLayer::ResTypeID &resTypeID, int16_t resID) +{ + THandle resHandle = resArchive->LoadResource(resTypeID, resID); + if (!resHandle) + return ExportHouseResults::kMemError; + + if (resTypeID == PortabilityLayer::ResTypeID('PICT')) + { + ExportHouseResult_t exportResult = TryExportPICT(resData, resHandle); + resHandle.Dispose(); + return exportResult; + } + + if (resTypeID == PortabilityLayer::ResTypeID('snd ')) + { + ExportHouseResult_t exportResult = TryExportSound(resData, resHandle); + resHandle.Dispose(); + return exportResult; + } + + const size_t size = resHandle.MMBlock()->m_size; + if (!resData.Resize(size)) + { + resHandle.Dispose(); + return ExportHouseResults::kMemError; + } + + if (size > 0) + memcpy(&resData[0], *resHandle, size); + + resHandle.Dispose(); + + return ExportHouseResults::kOK; +} + +ExportHouseResult_t TryExportResources(GpIOStream *stream, PortabilityLayer::IResourceArchive *resArchive) +{ + if (!resArchive) + return ExportHouseResults::kOK; + + IGpAllocator *alloc = PLDrivers::GetAlloc(); + + GpVector resources(alloc); + + GpUFilePos_t resForkStart = stream->Tell(); + + PortabilityLayer::IResourceIterator *iterator = resArchive->EnumerateResources(); + if (!iterator) + return ExportHouseResults::kMemError; + + const GpUFilePos_t resForkHeaderPos = stream->Tell(); + + GpUFilePos_t resForkDataStart = 0; + + PortabilityLayer::ResTypeID resTypeID; + int16_t resID = 0; + bool isFirstResource = true; + while (iterator->GetOne(resTypeID, resID)) + { + if (resTypeID != PortabilityLayer::ResTypeID('PICT') && resTypeID != PortabilityLayer::ResTypeID('snd ')) + continue; + + if (isFirstResource) + { + // Seems to want this much scratch space... + uint8_t headerData[256]; + memset(headerData, 0, sizeof(headerData)); + if (!stream->WriteExact(headerData, sizeof(headerData))) + return ExportHouseResults::kIOError; + + resForkDataStart = stream->Tell(); + isFirstResource = false; + } + + SimpleResource res; + + bool isPurgeable = true; + + res.m_name.Set(0, nullptr); + res.m_resourceID = resID; + res.m_resType = resTypeID; + res.m_attributes = 0; + res.m_offsetInResData = stream->Tell() - resForkDataStart; + + if (isPurgeable) + res.m_attributes |= (1 << 5); + + if (!resources.Append(static_cast(res))) + { + iterator->Destroy(); + return ExportHouseResults::kMemError; + } + + GpVector resData(alloc); + ExportHouseResult_t exportResResult = TryExportResource(resData, resArchive, resTypeID, resID); + if (exportResResult != ExportHouseResults::kOK) + return exportResResult; + + BEUInt32_t packedLen(static_cast(resData.Count())); + + if (!stream->WriteExact(&packedLen, sizeof(packedLen))) + { + iterator->Destroy(); + return ExportHouseResults::kIOError; + } + + if (resData.Count() > 0) + { + if (!stream->WriteExact(&resData[0], resData.Count())) + { + iterator->Destroy(); + return ExportHouseResults::kIOError; + } + } + + const unsigned int unpaddedExcess = ((stream->Tell() - resForkStart) & 0x3); + if (unpaddedExcess > 0) + { + uint8_t padding[4] = { 0, 0, 0, 0 }; + if (!stream->WriteExact(padding, 4 - unpaddedExcess)) + return ExportHouseResults::kIOError; + } + } + + iterator->Destroy(); + + if (!resources.Count()) + return ExportHouseResults::kOK; + + GpVector uniqueResTypes(alloc); + GpVector resTypeCounts(alloc); + + // Generate res map + for (size_t i = 0; i < resources.Count(); i++) + { + const SimpleResource &res = resources[i]; + + size_t uniqueResTypeIndex = uniqueResTypes.Count(); + + for (size_t uri = 0; uri < uniqueResTypes.Count(); uri++) + { + if (uniqueResTypes[uri] == res.m_resType) + { + uniqueResTypeIndex = uri; + break; + } + } + + if (uniqueResTypeIndex == uniqueResTypes.Count()) + { + if (!uniqueResTypes.Append(res.m_resType)) + return ExportHouseResults::kMemError; + + if (!resTypeCounts.Append(1)) + return ExportHouseResults::kMemError; + } + else + resTypeCounts[uniqueResTypeIndex]++; + } + + const GpUFilePos_t resMapPos = stream->Tell(); + const GpUFilePos_t resDataSize = resMapPos - resForkDataStart; + + // Reserved space for resource header copy (16), handle to next res map (4), file ref number (2) + { + char resHeaderCopy[22]; + memset(resHeaderCopy, 0, sizeof(resHeaderCopy)); + + if (!stream->WriteExact(resHeaderCopy, sizeof(resHeaderCopy))) + return ExportHouseResults::kIOError; + } + + uint16_t resForkAttributes = 0; // We don't use any of these + + const size_t typeListEntrySize = 8; + const size_t refListEntrySize = 12; + + const size_t resourceTypeListStartLoc = 28; + const size_t resourceTypeListSize = 2 + uniqueResTypes.Count() * typeListEntrySize; + const size_t resourceRefListStartLoc = resourceTypeListStartLoc + resourceTypeListSize; + const size_t resourceNameListStartLoc = resourceRefListStartLoc + resources.Count() * refListEntrySize; + + struct ResForkHeaderData + { + BEUInt16_t m_attributes; + BEUInt16_t m_resourceTypeListStartLoc; + BEUInt16_t m_resourceNameListStartLoc; + BEUInt16_t m_numResTypesMinusOne; + }; + + ResForkHeaderData headerData; + headerData.m_attributes = resForkAttributes; + headerData.m_resourceTypeListStartLoc = resourceTypeListStartLoc; + headerData.m_resourceNameListStartLoc = resourceNameListStartLoc; + headerData.m_numResTypesMinusOne = uniqueResTypes.Count() - 1; + + if (!stream->WriteExact(&headerData, sizeof(headerData))) + return ExportHouseResults::kIOError; + + GpVector refListStartForType(alloc); + if (!refListStartForType.Resize(resTypeCounts.Count())) + return ExportHouseResults::kMemError; + + if (resTypeCounts.Count() > 0) + { + refListStartForType[0] = 0; + for (size_t i = 1; i < refListStartForType.Count(); i++) + refListStartForType[i] = refListStartForType[i - 1] + resTypeCounts[i - 1]; + } + + struct ResTypeData + { + char m_resType[4]; + BEUInt16_t m_resCountMinusOne; + BEUInt16_t m_refListStart; + }; + + // Write resource type list + for (size_t i = 0; i < uniqueResTypes.Count(); i++) + { + ResTypeData resTypeData; + uniqueResTypes[i].ExportAsChars(resTypeData.m_resType); + resTypeData.m_resCountMinusOne = resTypeCounts[i] - 1; + resTypeData.m_refListStart = static_cast(refListStartForType[i] * refListEntrySize + resourceTypeListSize); + + if (!stream->WriteExact(&resTypeData, sizeof(resTypeData))) + return ExportHouseResults::kIOError; + } + + struct RefListEntry + { + BEInt16_t m_resID; + BEInt16_t m_nameOffset; + uint8_t m_attribs; + uint8_t m_resDataStart[3]; + BEUInt32_t m_reserved; + }; + + // Write reference lists + for (size_t ti = 0; ti < uniqueResTypes.Count(); ti++) + { + PortabilityLayer::ResTypeID resType = uniqueResTypes[ti]; + + for (size_t i = 0; i < resources.Count(); i++) + { + const SimpleResource &res = resources[i]; + if (res.m_resType != resType) + continue; + + RefListEntry refListEntry; + refListEntry.m_resID = static_cast(res.m_resourceID); + refListEntry.m_nameOffset = -1; + refListEntry.m_attribs = res.m_attributes; + + const size_t resDataStart = res.m_offsetInResData; + + refListEntry.m_resDataStart[0] = static_cast((resDataStart >> 16) & 0xff); + refListEntry.m_resDataStart[1] = static_cast((resDataStart >> 8) & 0xff); + refListEntry.m_resDataStart[2] = static_cast((resDataStart >> 0) & 0xff); + refListEntry.m_reserved = 0; + + if (!stream->WriteExact(&refListEntry, sizeof(refListEntry))) + return ExportHouseResults::kIOError; + } + } + + const GpUFilePos_t resForkEnd = stream->Tell(); + const GpUFilePos_t resMapSize = resForkEnd - resMapPos; + + struct ResForkHeader + { + BEUInt32_t m_resForkDataStart; + BEUInt32_t m_resMapPos; + BEUInt32_t m_resDataSize; + BEUInt32_t m_resMapSize; + }; + + ResForkHeader header; + header.m_resForkDataStart = static_cast(resForkDataStart - resForkStart); + header.m_resMapPos = static_cast(resMapPos - resForkStart); + header.m_resDataSize = static_cast(resDataSize); + header.m_resMapSize = static_cast(resMapSize); + + // Write header at the start of the file + if (!stream->SeekStart(resForkHeaderPos)) + return ExportHouseResults::kIOError; + + if (!stream->WriteExact(&header, sizeof(header))) + return ExportHouseResults::kIOError; + + // Write header at the start of the resource map + if (!stream->SeekStart(resMapPos)) + return ExportHouseResults::kIOError; + + if (!stream->WriteExact(&header, sizeof(header))) + return ExportHouseResults::kIOError; + + // Return to the end of the file + if (!stream->SeekStart(resForkEnd)) + return ExportHouseResults::kIOError; + + return ExportHouseResults::kOK; +} + +ExportHouseResult_t TryExportHouseToStream(GpIOStream *stream) +{ + uint8_t mb2Header[PortabilityLayer::MacBinary2::kHeaderSize]; + memset(mb2Header, 0, sizeof(mb2Header)); + + // Write MacBinary header + if (!stream->WriteExact(mb2Header, sizeof(mb2Header))) + return ExportHouseResults::kIOError; + + houseType *house = *thisHouse; + const size_t houseSize = thisHouse.MMBlock()->m_size; + const size_t nRooms = house->nRooms; + const size_t houseDataSize = houseType::kBinaryDataSize + sizeof(roomType) * nRooms; + ByteSwapHouse(house, houseSize, true); + + if (!stream->WriteExact(house, houseType::kBinaryDataSize)) + return ExportHouseResults::kIOError; + + if (!stream->WriteExact(house->rooms, sizeof(roomType) * nRooms)) + return ExportHouseResults::kIOError; + + ByteSwapHouse(house, houseSize, false); + + char padding[128]; + memset(padding, 0, sizeof(padding)); + + const GpUFilePos_t dataAlignExcess = stream->Tell() % 128; + if (dataAlignExcess != 0) + { + if (!stream->WriteExact(padding, 128 - dataAlignExcess)) + return ExportHouseResults::kIOError; + } + + const GpUFilePos_t resForkPos = stream->Tell(); + + // Serialize resources + if (houseResFork != nullptr) + { + ExportHouseResult_t resExportResult = TryExportResources(stream, houseResFork); + if (resExportResult != ExportHouseResults::kOK) + return resExportResult; + } + + const GpUFilePos_t resForkSize = stream->Tell() - resForkPos; + + const GpUFilePos_t resAlignExcess = resForkSize % 128; + if (resForkSize != 0) + { + if (!stream->WriteExact(padding, 128 - resAlignExcess)) + return ExportHouseResults::kIOError; + } + + PortabilityLayer::MacFileInfo fileInfo; + fileInfo.m_fileName.Set(thisHouseName[0], reinterpret_cast(thisHouseName + 1)); + fileInfo.m_commentSize = 0; + fileInfo.m_dataForkSize = houseDataSize; + fileInfo.m_resourceForkSize = resForkSize; + memcpy(fileInfo.m_properties.m_fileType, "gliH", 4); + memcpy(fileInfo.m_properties.m_fileCreator, "ozm5", 4); + fileInfo.m_properties.m_xPos = 0; + fileInfo.m_properties.m_yPos = 0; + fileInfo.m_properties.m_finderFlags = 0; + fileInfo.m_properties.m_protected = 0; + fileInfo.m_properties.m_createdTimeMacEpoch = fileInfo.m_properties.m_modifiedTimeMacEpoch = PLDrivers::GetSystemServices()->GetTime(); + + PortabilityLayer::MacBinary2::SerializeHeader(mb2Header, fileInfo); + + if (!stream->SeekStart(0)) + return ExportHouseResults::kIOError; + + if (!stream->WriteExact(mb2Header, PortabilityLayer::MacBinary2::kHeaderSize)) + return ExportHouseResults::kIOError; + + return ExportHouseResults::kOK; +} + +ExportHouseResult_t TryExportHouse(void) +{ + GpIOStream *stream = nullptr; + if (PortabilityLayer::FileManager::GetInstance()->OpenNonCompositeFile(PortabilityLayer::VirtualDirectories::kSourceExport, thisHouseName, ".bin", PortabilityLayer::EFilePermission_Write, GpFileCreationDispositions::kCreateOrOverwrite, stream)) + return ExportHouseResults::kStreamFailed; + + ExportHouseResult_t result = TryExportHouseToStream(stream); + stream->Close(); + + return result; +} + +void ExportHouse(void) +{ + TryExportHouse(); +} diff --git a/GpApp/InterfaceInit.cpp b/GpApp/InterfaceInit.cpp index 19e9779..c1296de 100644 --- a/GpApp/InterfaceInit.cpp +++ b/GpApp/InterfaceInit.cpp @@ -32,7 +32,7 @@ extern WindowPtr mapWindow, toolsWindow, linkWindow; extern Rect boardSrcRect, localRoomsDest[]; extern IGpCursor *handCursor, *vertCursor, *horiCursor; extern IGpCursor *diagCursor; -extern MenuHandle appleMenu, gameMenu, optionsMenu, houseMenu; +extern MenuHandle appleMenu, gameMenu, optionsMenu, houseMenu, exportMenu; extern long incrementModeTime; extern UInt32 doubleTime; extern short fadeInSequence[], idleMode; @@ -50,6 +50,8 @@ extern Boolean twoPlayerGame, paused, hasMirror, splashDrawn; void InitializeMenus (void) { + PortabilityLayer::MenuManager *mm = PortabilityLayer::MenuManager::GetInstance(); + appleMenu = GetMenu(kAppleMenuID); if (appleMenu == nil) RedAlert(kErrFailedResourceLoad); @@ -70,12 +72,15 @@ void InitializeMenus (void) if (!thisMac.isTouchscreen) { menusUp = true; - PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(true); + mm->SetMenuVisible(true); } houseMenu = GetMenu(kHouseMenuID); if (houseMenu == nil) RedAlert(kErrFailedResourceLoad); + + exportMenu = mm->CreateMenu(PSTR("Export"), kExportMenuID, true, 100, 16, 0); + mm->AppendMenuItem(exportMenu, 0, 0, 0, 0, true, false, PSTR("Export Glider PRO\xaa House...")); UpdateMenus(false); } diff --git a/GpApp/Menu.cpp b/GpApp/Menu.cpp index 4521450..6b5d8da 100644 --- a/GpApp/Menu.cpp +++ b/GpApp/Menu.cpp @@ -32,7 +32,7 @@ void UpdateMenusHouseClosed (void); void HeyYourPissingAHighScore (void); -MenuHandle appleMenu, gameMenu, optionsMenu, houseMenu; +MenuHandle appleMenu, gameMenu, optionsMenu, houseMenu, exportMenu; Boolean menusUp, resumedSavedGame; @@ -141,6 +141,11 @@ void UpdateMenusHouseOpen (void) EnableMenuItem(houseMenu, iSendBack); } } + + if (houseUnlocked) + EnableMenuItem(exportMenu, iExportGliderPROHouse); + else + DisableMenuItem(exportMenu, iExportGliderPROHouse); } //-------------------------------------------------------------- UpdateMenusHouseClosed @@ -159,6 +164,8 @@ void UpdateMenusHouseClosed (void) DisableMenuItem(houseMenu, iPaste); DisableMenuItem(houseMenu, iClear); DisableMenuItem(houseMenu, iDuplicate); + + DisableMenuItem(exportMenu, iExportGliderPROHouse); } //-------------------------------------------------------------- UpdateClipboardMenus @@ -254,12 +261,19 @@ void UpdateMenus (Boolean newMode) { PortabilityLayer::MenuManager *mm = PortabilityLayer::MenuManager::GetInstance(); if (theMode == kEditMode) + { InsertMenu(houseMenu, 0); + InsertMenu(exportMenu, 0); + } else { THandle houseMenu = mm->GetMenuByID(kHouseMenuID); if (houseMenu) mm->RemoveMenu(houseMenu); + + THandle exportMenu = mm->GetMenuByID(kExportMenuID); + if (exportMenu) + mm->RemoveMenu(exportMenu); } } @@ -465,6 +479,19 @@ void DoOptionsMenu (short theItem) //-------------------------------------------------------------- DoHouseMenu // Handle the user selecting an item from the House menu (only in Edit mode). +void DoExportMenu(short theItem) +{ + switch (theItem) + { + case iExportGliderPROHouse: + ExportHouse(); + break; + }; +} + +//-------------------------------------------------------------- DoHouseMenu +// Handle the user selecting an item from the House menu (only in Edit mode). + void DoHouseMenu (short theItem) { #ifndef COMPILEDEMO @@ -647,6 +674,10 @@ void DoMenuChoice (long menuChoice) case kHouseMenuID: DoHouseMenu(theItem); break; + + case kExportMenuID: + DoExportMenu(theItem); + break; } } diff --git a/GpApp/Sound.cpp b/GpApp/Sound.cpp index 8475d31..5ac7e74 100644 --- a/GpApp/Sound.cpp +++ b/GpApp/Sound.cpp @@ -404,23 +404,23 @@ void TellHerNoSounds (void) //-------------------------------------------------------------- ParseAndConvertSound -IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle &handle) +bool ParseAndConvertSoundChecked(const THandle &handle, void const*& outDataContents, size_t &outDataSize) { const uint8_t *dataStart = static_cast(*handle); const size_t size = handle.MMBlock()->m_size; if (size < sizeof(PortabilityLayer::RIFFTag)) - return nullptr; + return false; PortabilityLayer::RIFFTag mainRiffTag; memcpy(&mainRiffTag, dataStart, sizeof(PortabilityLayer::RIFFTag)); if (mainRiffTag.m_tag != PortabilityLayer::WaveConstants::kRiffChunkID) - return nullptr; + return false; const uint32_t riffSize = mainRiffTag.m_chunkSize; if (riffSize < 4 || riffSize - 4 > size - sizeof(PortabilityLayer::RIFFTag)) - return nullptr; + return false; const uint8_t *riffStart = dataStart + sizeof(PortabilityLayer::RIFFTag); const uint8_t *riffEnd = riffStart + riffSize; @@ -432,7 +432,7 @@ IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle &handle) memcpy(&waveMarker, riffStart, 4); if (waveMarker != PortabilityLayer::WaveConstants::kWaveChunkID) - return nullptr; + return false; const uint8_t *tagSearchLoc = riffStart + 4; @@ -440,7 +440,7 @@ IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle &handle) while (tagSearchLoc != riffEnd) { if (riffEnd - tagSearchLoc < sizeof(PortabilityLayer::RIFFTag)) - return nullptr; + return false; PortabilityLayer::RIFFTag riffTag; memcpy(&riffTag, tagSearchLoc, sizeof(PortabilityLayer::RIFFTag)); @@ -453,20 +453,20 @@ IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle &handle) const uint32_t riffTagSizeUnpadded = riffTag.m_chunkSize; if (riffTagSizeUnpadded == 0xffffffffU) - return nullptr; + return false; const uint32_t riffTagSizePadded = riffTagSizeUnpadded + (riffTagSizeUnpadded & 1); tagSearchLoc += sizeof(PortabilityLayer::RIFFTag); if (riffEnd - tagSearchLoc < riffTagSizePadded) - return nullptr; + return false; tagSearchLoc += riffTagSizePadded; } if (formatTagLoc == nullptr || dataTagLoc == nullptr) - return nullptr; + return false; PortabilityLayer::RIFFTag fmtTag; memcpy(&fmtTag, formatTagLoc, sizeof(PortabilityLayer::RIFFTag)); @@ -500,7 +500,7 @@ IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle &handle) copyableSize = sizeof(PortabilityLayer::WaveFormatChunkV1); } else - return nullptr; + return false; memcpy(&formatChunkV3, formatContents, copyableSize); @@ -508,23 +508,22 @@ IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle &handle) const PortabilityLayer::WaveFormatChunkV1 formatChunkV1 = formatChunkV2.m_v1; if (formatChunkV1.m_bitsPerSample != 8) - return nullptr; + return false; if (formatChunkV1.m_formatCode != PortabilityLayer::WaveConstants::kFormatPCM || formatChunkV1.m_numChannels != 1 || formatChunkV1.m_blockAlignmentBytes != 1 || formatChunkV1.m_bitsPerSample != 8) - return nullptr; + return false; uint32_t dataSize = dataTag.m_chunkSize; if (dataSize > 0x1000000 || dataSize < 1) - return nullptr; + return false; - IGpAudioDriver *audioDriver = PLDrivers::GetAudioDriver(); - if (!audioDriver) - return nullptr; + outDataContents = dataContents; + outDataSize = dataSize; - return audioDriver->CreateBuffer(dataContents, dataSize); + return true; } IGpAudioBuffer *ParseAndConvertSound(const THandle &handle) @@ -532,6 +531,14 @@ IGpAudioBuffer *ParseAndConvertSound(const THandle &handle) if (!handle) return nullptr; - IGpAudioBuffer *buffer = ParseAndConvertSoundChecked(handle); - return buffer; + IGpAudioDriver *audioDriver = PLDrivers::GetAudioDriver(); + if (!audioDriver) + return nullptr; + + const void *dataContents = nullptr; + size_t dataSize = 0; + if (!ParseAndConvertSoundChecked(handle, dataContents, dataSize)) + return nullptr; + + return audioDriver->CreateBuffer(dataContents, dataSize); } diff --git a/GpCommon/GpVector.h b/GpCommon/GpVector.h index 1472363..05f30eb 100644 --- a/GpCommon/GpVector.h +++ b/GpCommon/GpVector.h @@ -37,8 +37,12 @@ public: const T &operator[](size_t index) const; bool Resize(size_t newSize); + bool Reserve(size_t newSize); bool ResizeNoConstruct(size_t newSize); + bool Append(const T &item); + bool Append(T &&item); + T *Buffer(); const T *Buffer() const; @@ -148,7 +152,6 @@ const T &GpVector::operator[](size_t index) const return m_elements[index]; } - template bool GpVector::Resize(size_t newSize) { @@ -163,6 +166,21 @@ bool GpVector::Resize(size_t newSize) return true; } + + +template +bool GpVector::Reserve(size_t newSize) +{ + const size_t oldCount = m_count; + + if (!ResizeNoConstruct(newSize)) + return false; + + m_count = oldCount; + + return true; +} + template bool GpVector::ResizeNoConstruct(size_t newSize) { @@ -211,6 +229,53 @@ bool GpVector::ResizeNoConstruct(size_t newSize) return true; } +template +bool GpVector::Append(const T &item) +{ + const size_t oldCount = m_count; + + if (m_count == m_capacity) + { + size_t newCapacity = m_capacity * 2; + if (newCapacity < 8) + newCapacity = 8; + + if (!Reserve(newCapacity)) + return false; + } + + if (!ResizeNoConstruct(oldCount + 1)) + return false; + + new (m_elements + oldCount) T(item); + + return true; +} + +template +bool GpVector::Append(T &&item) +{ + const size_t oldCount = m_count; + + if (m_count == m_capacity) + { + size_t newCapacity = m_capacity * 2; + if (newCapacity < 8) + newCapacity = 8; + + if (!Reserve(newCapacity)) + return false; + } + + if (!ResizeNoConstruct(oldCount + 1)) + return false; + + new (m_elements + oldCount) T(static_cast(item)); + + return true; +} + + template const size_t GpVector::Count() const { diff --git a/PortabilityLayer/GPArchive.cpp b/PortabilityLayer/GPArchive.cpp index 9dae6d1..b39428b 100644 --- a/PortabilityLayer/GPArchive.cpp +++ b/PortabilityLayer/GPArchive.cpp @@ -91,9 +91,8 @@ namespace PortabilityLayer return output; } - bool GpArcResourceTypeTag::Load(const char *str) + bool GpArcResourceTypeTag::Load(const char *str, size_t l) { - size_t l = strlen(str); if (l < sizeof(m_id)) { memcpy(m_id, str, l); diff --git a/PortabilityLayer/GPArchive.h b/PortabilityLayer/GPArchive.h index 16915ee..253bbca 100644 --- a/PortabilityLayer/GPArchive.h +++ b/PortabilityLayer/GPArchive.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace PortabilityLayer { class ResTypeID; @@ -10,7 +12,7 @@ namespace PortabilityLayer static GpArcResourceTypeTag Encode(const ResTypeID &tag); - bool Load(const char *str); + bool Load(const char *str, size_t strLen); bool Decode(ResTypeID &outTag); }; } diff --git a/PortabilityLayer/MacBinary2.cpp b/PortabilityLayer/MacBinary2.cpp index 61b3c3f..b43f81d 100644 --- a/PortabilityLayer/MacBinary2.cpp +++ b/PortabilityLayer/MacBinary2.cpp @@ -40,13 +40,9 @@ namespace namespace PortabilityLayer { - void MacBinary2::WriteBin(const MacFileMem *file, GpIOStream *stream) + void MacBinary2::SerializeHeader(unsigned char *mb2Header, const MacFileInfo &fileInfo) { - const MacFileInfo &fileInfo = file->FileInfo(); - - uint8_t mb2Header[128]; - - memset(mb2Header, 0, sizeof(mb2Header)); + memset(mb2Header, 0, kHeaderSize); mb2Header[MB2FileOffsets::Version] = 0; @@ -87,7 +83,15 @@ namespace PortabilityLayer mb2Header[MB2FileOffsets::MinVersion] = 129; BytePack::BigUInt16(mb2Header + MB2FileOffsets::Checksum, XModemCRC(mb2Header, 124, 0)); + } + void MacBinary2::WriteBin(const MacFileMem *file, GpIOStream *stream) + { + const MacFileInfo &fileInfo = file->FileInfo(); + + uint8_t mb2Header[128]; + + SerializeHeader(mb2Header, fileInfo); stream->Write(mb2Header, 128); uint8_t *padding = mb2Header; diff --git a/PortabilityLayer/MacBinary2.h b/PortabilityLayer/MacBinary2.h index ec697f4..bcb6bdb 100644 --- a/PortabilityLayer/MacBinary2.h +++ b/PortabilityLayer/MacBinary2.h @@ -5,9 +5,14 @@ class GpIOStream; namespace PortabilityLayer { class MacFileMem; + struct MacFileInfo; namespace MacBinary2 { + static const int kHeaderSize = 128; + + void SerializeHeader(unsigned char *headerBytes, const MacFileInfo &macFileInfo); + void WriteBin(const MacFileMem *file, GpIOStream *stream); MacFileMem *ReadBin(GpIOStream *stream); }; diff --git a/PortabilityLayer/MenuManager.cpp b/PortabilityLayer/MenuManager.cpp index 7ba0c94..2a59969 100644 --- a/PortabilityLayer/MenuManager.cpp +++ b/PortabilityLayer/MenuManager.cpp @@ -128,6 +128,7 @@ namespace PortabilityLayer virtual void Init() override; virtual void Shutdown() override; + THandle CreateMenu(const PLPasStr &title, uint16_t menuID, bool enabled, uint16_t width, uint16_t height, uint16_t commandID) const override; THandle DeserializeMenu(const void *resData) const override; THandle GetMenuByID(int id) const override; @@ -294,6 +295,60 @@ namespace PortabilityLayer // GP TODO: Dispose of menus properly } + THandle MenuManagerImpl::CreateMenu(const PLPasStr &title, uint16_t menuID, bool enabled, uint16_t width, uint16_t height, uint16_t commandID) const + { + PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); + + const uint8_t titleLength = title.Length(); + + size_t stringDataLength = 1 + titleLength; + size_t numMenuItems = 0; + + MMHandleBlock *stringData = mm->AllocHandle(stringDataLength); + if (!stringData) + { + mm->ReleaseHandle(stringData); + return nullptr; + } + + MMHandleBlock *menuData = mm->AllocHandle(sizeof(Menu) + sizeof(MenuItem) * (numMenuItems - 1)); + if (!menuData) + { + mm->ReleaseHandle(stringData); + return nullptr; + } + + Menu *menu = static_cast(menuData->m_contents); + menu->menuID = menuID; + menu->width = width; + menu->height = height; + menu->commandID = commandID; + menu->enabled = true; + menu->menuIndex = 0; + menu->cumulativeOffset = 0; + menu->unpaddedTitleWidth = 0; + menu->isIcon = false; + menu->haveMenuLayout = false; + + uint8_t *stringDataStart = static_cast(stringData->m_contents); + uint8_t *stringDest = stringDataStart; + stringDest[0] = title.Length(); + memcpy(stringDest + 1, title.UChars(), title.Length()); + + menu->numMenuItems = numMenuItems; + menu->stringBlobHandle = stringData; + menu->prevMenu = nullptr; + menu->nextMenu = nullptr; + menu->layoutHintHorizontalOffset = 0; + menu->layoutWidth = 0; + menu->layoutBaseHeight = 0; + menu->layoutFinalHeight = 0; + menu->bottomItemsTruncated = 0; + menu->topItemsTruncated = 0; + + return THandle(menuData); + } + THandle MenuManagerImpl::DeserializeMenu(const void *resData) const { PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); diff --git a/PortabilityLayer/MenuManager.h b/PortabilityLayer/MenuManager.h index 638cc34..f3d93e5 100644 --- a/PortabilityLayer/MenuManager.h +++ b/PortabilityLayer/MenuManager.h @@ -23,6 +23,7 @@ namespace PortabilityLayer virtual void Init() = 0; virtual void Shutdown() = 0; + virtual THandle CreateMenu(const PLPasStr &title, uint16_t menuID, bool enabled, uint16_t width, uint16_t height, uint16_t commandID) const = 0; virtual THandle DeserializeMenu(const void *resData) const = 0; virtual THandle GetMenuByID(int id) const = 0; diff --git a/PortabilityLayer/PLQDraw.cpp b/PortabilityLayer/PLQDraw.cpp index 0ca50f8..2a3199c 100644 --- a/PortabilityLayer/PLQDraw.cpp +++ b/PortabilityLayer/PLQDraw.cpp @@ -493,6 +493,71 @@ static void RedistributeError(int16_t *errorDiffusionNextRow, int16_t *errorDiff } } +namespace PortabilityLayer +{ + bool FindBitSpan(uint32_t mask, int &outLowBit, int &outHighBit) + { + bool haveAnyBits = false; + for (int i = 0; i < 32; i++) + { + if (mask & (1 << i)) + { + if (!haveAnyBits) + { + haveAnyBits = true; + outLowBit = i; + } + outHighBit = i; + } + } + + return haveAnyBits; + } + + int DecodeMaskRShift1(uint32_t mask) + { + int lowBit, highBit; + if (!FindBitSpan(mask, lowBit, highBit)) + return 0; + + return lowBit; + } + + int DecodeMaskRShift2(uint32_t mask) + { + int lowBit, highBit; + if (!FindBitSpan(mask, lowBit, highBit)) + return 0; + + int numBits = highBit - lowBit + 1; + + int expandedBits = numBits; + while (expandedBits < 8) + expandedBits += numBits; + + return expandedBits - 8; + } + + int DecodeMaskMultiplier(uint32_t mask) + { + int lowBit, highBit; + if (!FindBitSpan(mask, lowBit, highBit)) + return 0; + + int numBits = highBit - lowBit + 1; + + int expandedBits = numBits; + int expansionFactor = 1; + while (expandedBits < 8) + { + expandedBits += numBits; + expansionFactor = (expansionFactor << numBits) | 1; + } + + return expansionFactor; + } +} + void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, bool errorDiffusion) { if (!pictHdl) @@ -572,9 +637,9 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, memcpy(&fileHeader, bmpBytes, sizeof(fileHeader)); memcpy(&infoHeader, bmpBytes + sizeof(fileHeader), sizeof(infoHeader)); - const uint16_t bpp = infoHeader.m_bitsPerPixel; + uint16_t bpp = infoHeader.m_bitsPerPixel; - if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24) + if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) return; uint32_t numColors = infoHeader.m_numColors; @@ -584,6 +649,18 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, if (numColors == 0 && bpp <= 8) numColors = (1 << bpp); + LEUInt32_t masks[4]; + int maskRShift1[4]; + int maskRShift2[4]; + int maskMultiplier[4]; + bool haveMasks = false; + if (infoHeader.m_thisStructureSize >= sizeof(PortabilityLayer::BitmapInfoHeader) + sizeof(uint32_t) * 4) + { + const uint8_t *masksLoc = bmpBytes + sizeof(fileHeader) + sizeof(PortabilityLayer::BitmapInfoHeader); + memcpy(masks, masksLoc, 16); + haveMasks = true; + } + const uint8_t *ctabLoc = bmpBytes + sizeof(fileHeader) + infoHeader.m_thisStructureSize; const size_t ctabSize = numColors * sizeof(PortabilityLayer::BitmapColorTableEntry); @@ -592,6 +669,57 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, if (ctabSize > availCTabBytes) return; + const uint32_t compressionCode = static_cast(infoHeader.m_compression); + if (bpp == 16) + { + if (compressionCode == 0) + { + haveMasks = true; + masks[0] = (0x1f << 10); + masks[1] = (0x1f << 5); + masks[2] = (0x1f << 0); + masks[3] = (1 << 15); + } + else if (compressionCode == 3) + { + if (!haveMasks) + return; + } + else + return; + } + else if (bpp == 32) + { + if (compressionCode == 0) + { + haveMasks = true; + masks[0] = (0xff << 16); + masks[1] = (0xff << 8); + masks[2] = (0xff << 0); + masks[3] = (0xff << 24); + } + if (compressionCode == 3) + { + if (!haveMasks) + return; + } + } + else + { + if (compressionCode != 0) + return; + } + + if (haveMasks) + { + for (int mi = 0; mi < 4; mi++) + { + maskRShift1[mi] = PortabilityLayer::DecodeMaskRShift1(masks[mi]); + maskRShift2[mi] = PortabilityLayer::DecodeMaskRShift2(masks[mi]); + maskMultiplier[mi] = PortabilityLayer::DecodeMaskMultiplier(masks[mi]); + } + } + if (bpp <= 8) { // Perform palette mapping @@ -672,7 +800,7 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, int16_t *errorDiffusionNextRow = nullptr; int16_t *errorDiffusionCurrentRow = nullptr; - if ((bpp == 16 || bpp == 24) && errorDiffusion) + if ((bpp == 16 || bpp == 24 || bpp == 32) && errorDiffusion) { errorDiffusionBuffer = static_cast(memManager->Alloc(sizeof(int16_t) * numCopyCols * 2 * 3)); if (!errorDiffusionBuffer) @@ -739,12 +867,13 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, const uint8_t srcLow = currentSourceRow[srcColIndex * 2 + 0]; const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; - const unsigned int combinedValue = srcLow | (srcHigh << 8); - const unsigned int b = (combinedValue & 0x1f); - const unsigned int g = ((combinedValue >> 5) & 0x1f); - const unsigned int r = ((combinedValue >> 10) & 0x1f); + const uint32_t combinedValue = srcLow | (srcHigh << 8); - if (r + g + b > 46) + uint8_t rgb[3]; + for (unsigned int ch = 0; ch < 3; ch++) + rgb[ch] = (((combinedValue & masks[ch]) >> maskRShift1[ch]) * maskMultiplier[ch]) >> maskRShift2[ch]; + + if (rgb[0] + rgb[1] + rgb[2] > 382) currentDestRow[destColIndex] = 0; else currentDestRow[destColIndex] = 1; @@ -763,15 +892,12 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; const unsigned int combinedValue = srcLow | (srcHigh << 8); - const unsigned int b = (combinedValue & 0x1f); - const unsigned int g = ((combinedValue >> 5) & 0x1f); - const unsigned int r = ((combinedValue >> 10) & 0x1f); - const unsigned int xr = (r << 5) | (r >> 2); - const unsigned int xg = (g << 5) | (g >> 2); - const unsigned int xb = (b << 5) | (b >> 2); + uint8_t rgb[3]; + for (unsigned int ch = 0; ch < 3; ch++) + rgb[ch] = (((combinedValue & masks[ch]) >> maskRShift1[ch]) * maskMultiplier[ch]) >> maskRShift2[ch]; - uint8_t colorIndex = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(xr, xg, xb, 255)); + uint8_t colorIndex = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(rgb[0], rgb[1], rgb[2], 255)); currentDestRow[destColIndex] = colorIndex; } @@ -787,15 +913,12 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; const unsigned int combinedValue = srcLow | (srcHigh << 8); - const unsigned int b = (combinedValue & 0x1f); - const unsigned int g = ((combinedValue >> 5) & 0x1f); - const unsigned int r = ((combinedValue >> 10) & 0x1f); - const unsigned int xr = (r << 5) | (r >> 2); - const unsigned int xg = (g << 5) | (g >> 2); - const unsigned int xb = (b << 5) | (b >> 2); + uint8_t rgb[3]; + for (unsigned int ch = 0; ch < 3; ch++) + rgb[ch] = (((combinedValue & masks[ch]) >> maskRShift1[ch]) * maskMultiplier[ch]) >> maskRShift2[ch]; - ErrorDiffusionWorkPixel wp = ApplyErrorDiffusion(errorDiffusionCurrentRow, xr, xg, xb, col, numCopyCols); + ErrorDiffusionWorkPixel wp = ApplyErrorDiffusion(errorDiffusionCurrentRow, rgb[0], rgb[1], rgb[2], col, numCopyCols); uint8_t colorIndex = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(wp.m_8[0], wp.m_8[1], wp.m_8[2], 255)); PortabilityLayer::RGBAColor resultColor = stdPalette->GetColors()[colorIndex]; @@ -816,15 +939,11 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, const size_t srcColIndex = col + firstSourceCol; const size_t destColIndex = col + firstDestCol; - const uint8_t srcLow = currentSourceRow[srcColIndex * 2 + 0]; - const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; + const uint8_t r = currentSourceRow[srcColIndex * 3 + 2]; + const uint8_t g = currentSourceRow[srcColIndex * 3 + 1]; + const uint8_t b = currentSourceRow[srcColIndex * 3 + 0]; - const unsigned int combinedValue = srcLow | (srcHigh << 8); - const unsigned int b = (combinedValue & 0x1f); - const unsigned int g = ((combinedValue >> 5) & 0x1f); - const unsigned int r = ((combinedValue >> 10) & 0x1f); - - if (r + g + b > 46) + if (r + g + b > 382) currentDestRow[destColIndex] = 0; else currentDestRow[destColIndex] = 1; @@ -867,6 +986,62 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, } } } + else if (bpp == 32) + { + if (destFormat == GpPixelFormats::kBW1) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const uint8_t r = currentSourceRow[srcColIndex * 4 + 2]; + const uint8_t g = currentSourceRow[srcColIndex * 4 + 1]; + const uint8_t b = currentSourceRow[srcColIndex * 4 + 0]; + + if (r + g + b > 382) + currentDestRow[destColIndex] = 0; + else + currentDestRow[destColIndex] = 1; + } + } + else + { + if (!errorDiffusion) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + const uint8_t r = currentSourceRow[srcColIndex * 4 + 2]; + const uint8_t g = currentSourceRow[srcColIndex * 4 + 1]; + const uint8_t b = currentSourceRow[srcColIndex * 4 + 0]; + + uint8_t colorIndex = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(r, g, b, 255)); + + currentDestRow[destColIndex] = colorIndex; + } + } + else + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + ErrorDiffusionWorkPixel wp = ApplyErrorDiffusion(errorDiffusionCurrentRow, currentSourceRow[srcColIndex * 4 + 2], currentSourceRow[srcColIndex * 4 + 1], currentSourceRow[srcColIndex * 4 + 0], col, numCopyCols); + + uint8_t colorIndex = stdPalette->MapColorLUT(PortabilityLayer::RGBAColor::Create(wp.m_8[0], wp.m_8[1], wp.m_8[2], 255)); + PortabilityLayer::RGBAColor resultColor = stdPalette->GetColors()[colorIndex]; + + RedistributeError(errorDiffusionNextRow, errorDiffusionCurrentRow, wp.m_16[0], wp.m_16[1], wp.m_16[2], resultColor.r, resultColor.g, resultColor.b, col, numCopyCols); + + currentDestRow[destColIndex] = colorIndex; + } + } + } + } currentSourceRow -= sourcePitch; currentDestRow += destPitch; @@ -907,7 +1082,7 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, const size_t destColIndex = col + firstDestCol; const unsigned int srcIndex = (currentSourceRow[srcColIndex / 8] >> (8 - ((srcColIndex & 7) + 1))) & 0x01; - currentDestRow32[destColIndex] = srcIndex ? blackColor32 : whiteColor32; + currentDestRow32[destColIndex] = unpackedColors[srcIndex]; } } else if (bpp == 4) @@ -943,17 +1118,10 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, const uint8_t srcHigh = currentSourceRow[srcColIndex * 2 + 1]; const unsigned int combinedValue = srcLow | (srcHigh << 8); - const unsigned int b = (combinedValue & 0x1f); - const unsigned int g = ((combinedValue >> 5) & 0x1f); - const unsigned int r = ((combinedValue >> 10) & 0x1f); - const unsigned int xr = (r << 5) | (r >> 2); - const unsigned int xg = (g << 5) | (g >> 2); - const unsigned int xb = (b << 5) | (b >> 2); + for (unsigned int ch = 0; ch < 3; ch++) + currentDestRowBytes[destColIndex * 4 + ch] = (((combinedValue & masks[ch]) >> maskRShift1[ch]) * maskMultiplier[ch]) >> maskRShift2[ch]; - currentDestRowBytes[destColIndex * 4 + 0] = xr; - currentDestRowBytes[destColIndex * 4 + 1] = xg; - currentDestRowBytes[destColIndex * 4 + 2] = xb; currentDestRowBytes[destColIndex * 4 + 3] = 255; } } @@ -970,6 +1138,19 @@ void DrawSurface::DrawPicture(THandle pictHdl, const Rect &bounds, currentDestRowBytes[destColIndex * 4 + 3] = 255; } } + else if (bpp == 32) + { + for (size_t col = 0; col < numCopyCols; col++) + { + const size_t srcColIndex = col + firstSourceCol; + const size_t destColIndex = col + firstDestCol; + + currentDestRowBytes[destColIndex * 4 + 0] = currentSourceRow[srcColIndex * 4 + 2]; + currentDestRowBytes[destColIndex * 4 + 1] = currentSourceRow[srcColIndex * 4 + 1]; + currentDestRowBytes[destColIndex * 4 + 2] = currentSourceRow[srcColIndex * 4 + 0]; + currentDestRowBytes[destColIndex * 4 + 3] = 255; + } + } currentSourceRow -= sourcePitch; currentDestRowBytes += destPitch; diff --git a/PortabilityLayer/PLResourceManager.cpp b/PortabilityLayer/PLResourceManager.cpp index bd685dc..71ff27a 100644 --- a/PortabilityLayer/PLResourceManager.cpp +++ b/PortabilityLayer/PLResourceManager.cpp @@ -40,6 +40,61 @@ static const char *kPICTExtension = ".bmp"; typedef ResourceValidationRules::ResourceValidationRule ResourceValidationRule_t; +namespace PortabilityLayer +{ + class ResourceArchiveZipFileIterator : public IResourceIterator + { + public: + explicit ResourceArchiveZipFileIterator(PortabilityLayer::ZipFileProxy *proxy); + + void Destroy() override; + bool GetOne(ResTypeID &resTypeID, int16_t &outID) override; + + private: + ~ResourceArchiveZipFileIterator(); + + PortabilityLayer::ZipFileProxy *m_proxy; + size_t m_numFiles; + size_t m_currentIndex; + }; +} + + +PortabilityLayer::ResourceArchiveZipFileIterator::ResourceArchiveZipFileIterator(PortabilityLayer::ZipFileProxy *proxy) + : m_proxy(proxy) + , m_numFiles(proxy->NumFiles()) + , m_currentIndex(0) +{ +} + +void PortabilityLayer::ResourceArchiveZipFileIterator::Destroy() +{ + this->~ResourceArchiveZipFileIterator(); + PortabilityLayer::MemoryManager::GetInstance()->Release(this); +} + +bool PortabilityLayer::ResourceArchiveZipFileIterator::GetOne(ResTypeID &resTypeID, int16_t &outID) +{ + while (m_currentIndex != m_numFiles) + { + const size_t index = m_currentIndex++; + + const char *name = nullptr; + size_t nameLength = 0; + m_proxy->GetFileName(index, name, nameLength); + + const bool isParseable = ResourceArchiveZipFile::ParseResFromName(name, nameLength, resTypeID, outID); + if (isParseable) + return true; + } + + return false; +} + +PortabilityLayer::ResourceArchiveZipFileIterator::~ResourceArchiveZipFileIterator() +{ +} + namespace { // Validation here is only intended to be minimal, to ensure later checks can determine the format size and do certain operations @@ -433,6 +488,93 @@ namespace PortabilityLayer return haveAny; } + IResourceIterator *ResourceArchiveZipFile::EnumerateResources() const + { + PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); + void *storage = mm->Alloc(sizeof(ResourceArchiveZipFileIterator)); + if (!storage) + return nullptr; + + return new (storage) ResourceArchiveZipFileIterator(m_zipFileProxy); + } + + bool ResourceArchiveZipFile::ParseResFromName(const char *name, size_t nameLength, ResTypeID &outResTypeID, int16_t &outID) + { + size_t slashPos = nameLength; + for (size_t i = 0; i < nameLength; i++) + { + if (name[i] == '/') + { + slashPos = i; + break; + } + } + + if (slashPos == nameLength) + return false; + + GpArcResourceTypeTag resTag; + if (!resTag.Load(name, slashPos)) + return false; + + if (!resTag.Decode(outResTypeID)) + return false; + + int validationRule = 0; + const char *expectedExtension = GetFileExtensionForResType(outResTypeID, validationRule); + + const size_t idStart = slashPos + 1; + if (idStart == nameLength) + return false; + + bool isNegative = false; + size_t digitsStart = idStart; + + if (name[idStart] == '-') + { + isNegative = true; + digitsStart++; + } + + size_t digitsEnd = nameLength; + int32_t resID = 0; + for (size_t i = digitsStart; i < nameLength; i++) + { + if (name[i] == '.') + { + digitsEnd = i; + break; + } + else + { + char digit = name[i]; + if (digit < '0' || digit > '9') + return false; + + int32_t digitNumber = static_cast(digit) - '0'; + resID *= 10; + if (isNegative) + resID -= digitNumber; + else + resID += digitNumber; + + if (resID < -32768 || resID > 32767) + return false; + } + } + + outID = static_cast(resID); + + const size_t extAvailable = nameLength - digitsEnd; + if (strlen(expectedExtension) != extAvailable) + return false; + + if (memcmp(name + digitsEnd, expectedExtension, extAvailable) != 0) + return false; + + return true; + } + bool ResourceArchiveZipFile::IndexResource(const ResTypeID &resTypeID, int id, size_t &outIndex, int &outValidationRule) const { const char *extension = GetFileExtensionForResType(resTypeID, outValidationRule); @@ -461,6 +603,11 @@ namespace PortabilityLayer handle = ref->m_handle; else { + const size_t resSize = m_zipFileProxy->GetFileSize(index); + + if (resSize > kMaxResourceSize) + return THandle(); + handle = MemoryManager::GetInstance()->AllocHandle(0); if (!handle) return THandle(); @@ -468,7 +615,7 @@ namespace PortabilityLayer handle->m_rmSelfRef = ref; ref->m_handle = handle; ref->m_resID = static_cast(id); - ref->m_size = m_zipFileProxy->GetFileSize(index); + ref->m_size = resSize; } if (handle->m_contents == nullptr && load) diff --git a/PortabilityLayer/QDPictHeader.cpp b/PortabilityLayer/QDPictHeader.cpp index d30abcd..fd27226 100644 --- a/PortabilityLayer/QDPictHeader.cpp +++ b/PortabilityLayer/QDPictHeader.cpp @@ -55,9 +55,9 @@ namespace PortabilityLayer memcpy(&v2Version, v2Header + 4, 2); // In version 2 header, v2Version == -1 - // Followed by fixed-point bounding rectangle (16 bytes) and 4 reserved + // Followed by 2-byte reserved (usually -1), fixed-point bounding rectangle (16 bytes) and 4 reserved (usually 0) // In ext. version 2 header, v2Version == -2 - // Followed by 2-byte reserved, horizontal DPI (fixed point, 4 bytes), vertical DPI (fixed point, 4 bytes) optimal source rect (8 bytes), and 2 reserved + // Followed by 2-byte reserved (0), horizontal DPI (fixed point, 4 bytes), vertical DPI (fixed point, 4 bytes) optimal source rect (8 bytes), and 2 reserved } else return false; diff --git a/PortabilityLayer/ResourceManager.h b/PortabilityLayer/ResourceManager.h index 95f0546..f6b884b 100644 --- a/PortabilityLayer/ResourceManager.h +++ b/PortabilityLayer/ResourceManager.h @@ -27,6 +27,12 @@ namespace PortabilityLayer int16_t m_resID; }; + struct IResourceIterator + { + virtual void Destroy() = 0; + virtual bool GetOne(ResTypeID &resTypeID, int16_t &outID) = 0; + }; + struct IResourceArchive { virtual void Destroy() = 0; @@ -35,6 +41,8 @@ namespace PortabilityLayer virtual bool HasAnyResourcesOfType(const ResTypeID &resTypeID) const = 0; virtual bool FindFirstResourceOfType(const ResTypeID &resTypeID, int16_t &outID) const = 0; + + virtual IResourceIterator *EnumerateResources() const = 0; }; class ResourceArchiveBase : public IResourceArchive @@ -43,9 +51,13 @@ namespace PortabilityLayer static const char *GetFileExtensionForResType(const ResTypeID &resTypeID, int &outValidationRule); }; + class ResourceArchiveZipFileIterator; + class ResourceArchiveZipFile final : public ResourceArchiveBase { public: + friend class ResourceArchiveZipFileIterator; + static ResourceArchiveZipFile *Create(ZipFileProxy *zipFileProxy, bool proxyIsShared, GpIOStream *stream); void Destroy() override; @@ -54,7 +66,14 @@ namespace PortabilityLayer bool HasAnyResourcesOfType(const ResTypeID &resTypeID) const override; bool FindFirstResourceOfType(const ResTypeID &resTypeID, int16_t &outID) const override; + IResourceIterator *EnumerateResources() const override; + + static bool ParseResFromName(const char *name, size_t nameLength, ResTypeID &outResTypeID, int16_t &outID); + + private: + static const size_t kMaxResourceSize = 32 * 1024 * 1024; + ResourceArchiveZipFile(ZipFileProxy *zipFileProxy, bool proxyIsShared, GpIOStream *stream, ResourceArchiveRef *resourceHandles); ~ResourceArchiveZipFile(); From c6aa82db3527e45a2f02c0e108efe6c35327b48d Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:26:10 -0400 Subject: [PATCH 07/31] Adjust credits --- ApplicationResourcePatches/DITL/2000.json | 4 +-- GpApp/About.cpp | 40 +++++++++++++---------- GpCommon/GpBuildVersion.h | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/ApplicationResourcePatches/DITL/2000.json b/ApplicationResourcePatches/DITL/2000.json index 17357ac..3e6d6da 100644 --- a/ApplicationResourcePatches/DITL/2000.json +++ b/ApplicationResourcePatches/DITL/2000.json @@ -4,7 +4,7 @@ { "name" : "Okay", "itemType" : "Button", - "pos" : [ 376, 240 ], + "pos" : [ 376, 288 ], "size" : [ 58, 20 ], "id" : 1, "enabled" : true @@ -12,7 +12,7 @@ { "name" : "Third Party/Licensing Info...", "itemType" : "Button", - "pos" : [ 176, 240 ], + "pos" : [ 176, 288 ], "size" : [ 190, 20 ], "id" : 1, "enabled" : true diff --git a/GpApp/About.cpp b/GpApp/About.cpp index eaa2c9d..42e8194 100644 --- a/GpApp/About.cpp +++ b/GpApp/About.cpp @@ -309,7 +309,7 @@ void DoAboutFramework (void) static const int kAboutFrameworkDialogTemplateID = 2000; static const int kAboutOpenSourceButton = 2; - const Rect windowRect = Rect::Create(0, 0, 272, 450); + const Rect windowRect = Rect::Create(0, 0, 320, 450); PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(windowRect, PortabilityLayer::WindowStyleFlags::kAlert, true, 0, 0, PSTR("")); @@ -319,6 +319,7 @@ void DoAboutFramework (void) int16_t verticalPoint = 16 + font->GetMetrics().m_ascent; int16_t horizontalOffset = 16; + int16_t creditsHorizontalOffset = 80; const int16_t spacing = 12; PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance(); @@ -333,23 +334,28 @@ void DoAboutFramework (void) Window *window = dialog->GetWindow(); DrawSurface *surface = window->GetDrawSurface(); - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 0), PSTR(GP_APPLICATION_NAME " " GP_APPLICATION_VERSION_STRING " \xa9" GP_APPLICATION_COPYRIGHT_STRING), blackColor, font); - - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 2), PSTR(GP_APPLICATION_NAME " is an unoffical third-party port of Glider PRO."), blackColor, font); - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 4), PSTR("This software is not maintained by, supported by, endorsed by, or"), blackColor, font); - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 5), PSTR("otherwise associated with the authors or publishers of Glider PRO."), blackColor, font); - - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 7), PSTR("Please do not contact any of them regarding issues that you have"), blackColor, font); - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 8), PSTR("with " GP_APPLICATION_NAME "."), blackColor, font); - - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 10), PSTR("If you would like to contribute to this project, visit:"), blackColor, font); - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 11), PSTR(GP_APPLICATION_WEBSITE_STRING), blackColor, font); - - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 13), PSTR("To report a problem or request support, submit an issue via"), blackColor, font); - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 14), PSTR("the website above."), blackColor, font); - - surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * 16), PSTR("For more information, please see the accompanying documentation."), blackColor, font); + int lineNum = 0; + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR(GP_APPLICATION_NAME " " GP_APPLICATION_VERSION_STRING " \xa9" GP_APPLICATION_COPYRIGHT_STRING), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum)), PSTR("Credits:"), blackColor, font); + surface->DrawString(Point::Create(creditsHorizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("Eric Lasota - Programming, admin"), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR(GP_APPLICATION_NAME " is an unoffical third-party port of Glider PRO."), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("This software is not maintained by, supported by, endorsed by, or"), blackColor, font); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("otherwise associated with the authors or publishers of Glider PRO."), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("Please do not contact any of them regarding issues that you have"), blackColor, font); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("with " GP_APPLICATION_NAME "."), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("If you would like to contribute to this project, visit:"), blackColor, font); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR(GP_APPLICATION_WEBSITE_STRING), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("To report a problem or request support, submit an issue via"), blackColor, font); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("the website above."), blackColor, font); + (lineNum++); + surface->DrawString(Point::Create(horizontalOffset, verticalPoint + spacing * (lineNum++)), PSTR("For more information, please see the accompanying documentation."), blackColor, font); surface->DrawString(Point::Create(horizontalOffset, windowRect.bottom - 16), PSTR("Build: " __DATE__ " " __TIME__ " " ABOUT_DIALOG_CONFIGURATION_TAG), blackColor, fontLight); diff --git a/GpCommon/GpBuildVersion.h b/GpCommon/GpBuildVersion.h index e832d25..f17f9fa 100644 --- a/GpCommon/GpBuildVersion.h +++ b/GpCommon/GpBuildVersion.h @@ -5,5 +5,5 @@ #define GP_BUILD_VERSION_UPDATE 0 #define GP_APPLICATION_VERSION_STRING "1.1.0" -#define GP_APPLICATION_COPYRIGHT_STRING "2019-2021 Eric Lasota" +#define GP_APPLICATION_COPYRIGHT_STRING "2019-2021 Gale Force Games" #define GP_APPLICATION_WEBSITE_STRING "https://github.com/elasota/Aerofoil" From 9510aaee32071877bca824a7535ed95e462e8286 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:30:20 -0400 Subject: [PATCH 08/31] Re-enable initial launch disclaimer --- GpApp/Main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GpApp/Main.cpp b/GpApp/Main.cpp index e229e82..f731985 100644 --- a/GpApp/Main.cpp +++ b/GpApp/Main.cpp @@ -599,7 +599,7 @@ int AppStartup() FlushResolutionChange(); } - //ShowInitialLaunchDisclaimer(); + ShowInitialLaunchDisclaimer(); } if (thisMac.isResolutionDirty) From ac15c26bef148f13c32d8115ccfdc0b436624a1d Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:52:28 -0400 Subject: [PATCH 09/31] Update installer manufacturer ID --- ReleasePackageInstaller/Product.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReleasePackageInstaller/Product.wxs b/ReleasePackageInstaller/Product.wxs index c97cfad..642c4cb 100644 --- a/ReleasePackageInstaller/Product.wxs +++ b/ReleasePackageInstaller/Product.wxs @@ -19,7 +19,7 @@ --> - + From f32866510e09bc623d00a661d2e9fbfa610c99c9 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 02:59:30 -0400 Subject: [PATCH 10/31] EOL fix --- AerofoilSDL/GpInputDriver_SDL_Gamepad.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/AerofoilSDL/GpInputDriver_SDL_Gamepad.cpp b/AerofoilSDL/GpInputDriver_SDL_Gamepad.cpp index 7c5119c..f9d18ae 100644 --- a/AerofoilSDL/GpInputDriver_SDL_Gamepad.cpp +++ b/AerofoilSDL/GpInputDriver_SDL_Gamepad.cpp @@ -197,7 +197,7 @@ void GpInputDriverSDLGamepad::ProcessSDLEvent(const SDL_Event &msg) IGpVOSEventQueue *evtQueue = m_properties.m_eventQueue; switch (msg.type) - { + { case SDL_CONTROLLERAXISMOTION: { const SDL_ControllerAxisEvent &axisMsg = msg.caxis; @@ -231,8 +231,8 @@ void GpInputDriverSDLGamepad::ProcessSDLEvent(const SDL_Event &msg) m_pendingEvents.push_back(evt); } - break; - case SDL_CONTROLLERBUTTONDOWN: + break; + case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: { const bool isDown = (msg.type == SDL_CONTROLLERBUTTONDOWN); @@ -287,22 +287,22 @@ void GpInputDriverSDLGamepad::ProcessSDLEvent(const SDL_Event &msg) m_pendingEvents.push_back(evt); } - break; + break; case SDL_CONTROLLERDEVICEADDED: HandleDeviceAdded(msg.cdevice.which); - break; + break; case SDL_CONTROLLERDEVICEREMOVED: HandleDeviceRemoved(msg.cdevice.which); - break; + break; case SDL_CONTROLLERDEVICEREMAPPED: // Not really sure what to do here, just re-add it HandleDeviceRemoved(msg.cdevice.which); HandleDeviceAdded(msg.cdevice.which); - break; - } + break; + } } IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties) { - return GpInputDriverSDLGamepad::Create(properties); + return GpInputDriverSDLGamepad::Create(properties); } From a2ca1725fa26516810fd241305cbcbf3f73a655d Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 03:02:30 -0400 Subject: [PATCH 11/31] Improve export house errors --- GpApp/HouseIO.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/GpApp/HouseIO.cpp b/GpApp/HouseIO.cpp index 0037179..1982d16 100644 --- a/GpApp/HouseIO.cpp +++ b/GpApp/HouseIO.cpp @@ -3597,5 +3597,24 @@ ExportHouseResult_t TryExportHouse(void) void ExportHouse(void) { - TryExportHouse(); + ExportHouseResult_t result = TryExportHouse(); + + switch (result) + { + case ExportHouseResults::kOK: + break; + case ExportHouseResults::kMemError: + YellowAlert(kYellowNoMemory, 0); + break; + case ExportHouseResults::kInternalError: + YellowAlert(kYellowUnaccounted, 0); + break; + case ExportHouseResults::kIOError: + case ExportHouseResults::kStreamFailed: + YellowAlert(kYellowFailedWrite, 0); + break; + case ExportHouseResults::kResourceError: + YellowAlert(kYellowFailedResOpen, 0); + break; + } } From 5e060279afee278a787d01fa6990f6680f920032 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 10:59:19 -0400 Subject: [PATCH 12/31] Clean up warnings --- GpApp/HouseIO.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/GpApp/HouseIO.cpp b/GpApp/HouseIO.cpp index 1982d16..966b9b7 100644 --- a/GpApp/HouseIO.cpp +++ b/GpApp/HouseIO.cpp @@ -69,8 +69,6 @@ void OpenHouseMovie (void) #ifdef COMPILEQT VFileSpec theSpec; Handle spaceSaver; - short movieRefNum; - Boolean dataRefWasChanged; if (thisMac.hasQT) { @@ -107,9 +105,7 @@ void OpenHouseMovie (void) void CloseHouseMovie (void) { -#ifdef COMPILEQT - PLError_t theErr; - +#ifdef COMPILEQT if ((thisMac.hasQT) && (hasMovie)) { AnimationManager::GetInstance()->RemovePlayer(&theMovie); @@ -1123,8 +1119,8 @@ static bool LegalizeTransport(houseType *house, size_t roomNum, size_t objectNum transport->tall = static_cast(((objRect.Width() / 4) << 8) + objRect.Height() / 4); else if (obj->what == kInvisTrans) { - transport->wide = objRect.Width(); - transport->tall = objRect.Height(); + transport->wide = static_cast(objRect.Width()); + transport->tall = static_cast(objRect.Height()); } } @@ -1946,8 +1942,6 @@ static bool LegalizeHouse(houseType *house, bool &anyRepairs) Boolean ReadHouse (GpIOStream *houseStream, bool untrusted) { - long byteCount; - PLError_t theErr; short whichRoom; // There should be no padding remaining the house type @@ -1959,7 +1953,7 @@ Boolean ReadHouse (GpIOStream *houseStream, bool untrusted) return (false); } - byteCount = houseStream->Size(); + const GpUFilePos_t byteCount = houseStream->Size(); #ifdef COMPILEDEMO if (byteCount != 16526L) @@ -2190,8 +2184,6 @@ Boolean WriteHouse (Boolean checkIt) Boolean CloseHouse (void) { - PLError_t theErr; - if (!houseOpen) return (true); @@ -2875,7 +2867,7 @@ static ExportHouseResult_t TryExportPictFromSurface(GpVector &resData, if (pictVersion == 1) { - const uint8_t opcode = bitmapOpcode; + const uint8_t opcode = static_cast(bitmapOpcode); if (!AppendRaw(resData, &opcode, 1)) return ExportHouseResults::kMemError; } @@ -2906,7 +2898,7 @@ static ExportHouseResult_t TryExportPictFromSurface(GpVector &resData, } else { - uint16_t rowSize = bytesPerRow; + uint16_t rowSize = static_cast(bytesPerRow); if (!isBWBitmap) rowSize |= 0x8000; @@ -3395,9 +3387,9 @@ ExportHouseResult_t TryExportResources(GpIOStream *stream, PortabilityLayer::IRe ResForkHeaderData headerData; headerData.m_attributes = resForkAttributes; - headerData.m_resourceTypeListStartLoc = resourceTypeListStartLoc; - headerData.m_resourceNameListStartLoc = resourceNameListStartLoc; - headerData.m_numResTypesMinusOne = uniqueResTypes.Count() - 1; + headerData.m_resourceTypeListStartLoc = static_cast(resourceTypeListStartLoc); + headerData.m_resourceNameListStartLoc = static_cast(resourceNameListStartLoc); + headerData.m_numResTypesMinusOne = static_cast(uniqueResTypes.Count() - 1); if (!stream->WriteExact(&headerData, sizeof(headerData))) return ExportHouseResults::kIOError; @@ -3562,7 +3554,7 @@ ExportHouseResult_t TryExportHouseToStream(GpIOStream *stream) PortabilityLayer::MacFileInfo fileInfo; fileInfo.m_fileName.Set(thisHouseName[0], reinterpret_cast(thisHouseName + 1)); fileInfo.m_commentSize = 0; - fileInfo.m_dataForkSize = houseDataSize; + fileInfo.m_dataForkSize = static_cast(houseDataSize); fileInfo.m_resourceForkSize = resForkSize; memcpy(fileInfo.m_properties.m_fileType, "gliH", 4); memcpy(fileInfo.m_properties.m_fileCreator, "ozm5", 4); From d6ce07685e014dd888c6f7572522d6bca54286b0 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 10:59:31 -0400 Subject: [PATCH 13/31] Clean up vector use --- PortabilityLayer/FileManager.cpp | 2 +- PortabilityLayer/QDPictDecoder.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/PortabilityLayer/FileManager.cpp b/PortabilityLayer/FileManager.cpp index 0ffdf85..9bc0987 100644 --- a/PortabilityLayer/FileManager.cpp +++ b/PortabilityLayer/FileManager.cpp @@ -16,7 +16,7 @@ #include "PLErrorCodes.h" #include "PLSysCalls.h" -#include +#include #include namespace PortabilityLayer diff --git a/PortabilityLayer/QDPictDecoder.cpp b/PortabilityLayer/QDPictDecoder.cpp index c391dfe..7b15b97 100644 --- a/PortabilityLayer/QDPictDecoder.cpp +++ b/PortabilityLayer/QDPictDecoder.cpp @@ -9,7 +9,6 @@ #include "RGBAColor.h" #include "Vec2i.h" -#include #include struct QDPictDecodeState From a7cf9d48e354ab2c0c873904793bcb65180bd528 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 13:29:45 -0400 Subject: [PATCH 14/31] Fix double GP_RESTRICT definition --- Common/CoreDefs.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Common/CoreDefs.h b/Common/CoreDefs.h index d74ccae..17e685d 100644 --- a/Common/CoreDefs.h +++ b/Common/CoreDefs.h @@ -13,7 +13,6 @@ #define GP_ALIGNED(n) __declspec(align(n)) #else #define GP_ALIGNED(n) __attribute__((aligned(n))) -#define GP_RESTRICT #endif #if GP_IS_CPP11 From 08c6fd5108e7c8b41f07ba441c8faa6bb2a06697 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 20:11:58 -0400 Subject: [PATCH 15/31] EOL fix --- AerofoilPortable/GpAllocator_C.h | 4 ++-- GpCommon/IGpAllocator.h | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/AerofoilPortable/GpAllocator_C.h b/AerofoilPortable/GpAllocator_C.h index 8325f31..ab6967b 100644 --- a/AerofoilPortable/GpAllocator_C.h +++ b/AerofoilPortable/GpAllocator_C.h @@ -3,8 +3,8 @@ #include "IGpAllocator.h" class GpAllocator_C final : public IGpAllocator -{ -public: +{ +public: void *Realloc(void *buf, size_t newSize) override; static GpAllocator_C *GetInstance(); diff --git a/GpCommon/IGpAllocator.h b/GpCommon/IGpAllocator.h index 9cc0703..a7eede0 100644 --- a/GpCommon/IGpAllocator.h +++ b/GpCommon/IGpAllocator.h @@ -1,12 +1,12 @@ -#pragma once - -#include -#include - -struct IGpAllocator -{ +#pragma once + +#include +#include + +struct IGpAllocator +{ virtual void *Realloc(void *buf, size_t newSize) = 0; - inline void *Alloc(size_t size) { return this->Realloc(nullptr, size); } - inline void Release(void *ptr) { this->Realloc(ptr, 0); } -}; + inline void *Alloc(size_t size) { return this->Realloc(nullptr, size); } + inline void Release(void *ptr) { this->Realloc(ptr, 0); } +}; From a012c6d3e765f528e1b6eec20a944599a94fadc3 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 20:12:41 -0400 Subject: [PATCH 16/31] Fix web build and add export path --- AerofoilWeb/BuildAerofoilPortable.bat | 11 +++++++++++ AerofoilWeb/BuildAerofoilWeb.bat | 6 +++++- AerofoilWeb/GpFileSystem_Web.cpp | 26 ++++++++++++++++++-------- AerofoilWeb/GpFileSystem_Web.h | 1 + AerofoilWeb/GpMain_SDL_Web.cpp | 12 ++++++++++-- AerofoilWeb/Link.bat | 8 ++++++-- 6 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 AerofoilWeb/BuildAerofoilPortable.bat diff --git a/AerofoilWeb/BuildAerofoilPortable.bat b/AerofoilWeb/BuildAerofoilPortable.bat new file mode 100644 index 0000000..6badad6 --- /dev/null +++ b/AerofoilWeb/BuildAerofoilPortable.bat @@ -0,0 +1,11 @@ +set INPUT_DIR=../AerofoilPortable +set OUTPUT_DIR=obj + +rem set DEBUG_LEVEL_FLAGS=-g4 -O0 +set DEBUG_LEVEL_FLAGS=-O3 + +set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../Common/ -s ASYNCIFY %DEBUG_LEVEL_FLAGS% -DGP_DEBUG_CONFIG=0 + +emcc -c %INPUT_DIR%/GpAllocator_C.cpp -o %OUTPUT_DIR%/AerofoilPortable_Combined.o %FLAGS% + +pause diff --git a/AerofoilWeb/BuildAerofoilWeb.bat b/AerofoilWeb/BuildAerofoilWeb.bat index 56e6b65..f072b72 100644 --- a/AerofoilWeb/BuildAerofoilWeb.bat +++ b/AerofoilWeb/BuildAerofoilWeb.bat @@ -1,6 +1,10 @@ set INPUT_DIR=. set OUTPUT_DIR=obj -set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../PortabilityLayer/ -I../Common/ -I../GpShell/ -s ASYNCIFY -O3 -DGP_DEBUG_CONFIG=0 + +rem set DEBUG_LEVEL_FLAGS=-g4 -O0 +set DEBUG_LEVEL_FLAGS=-O3 + +set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../PortabilityLayer/ -I../Common/ -I../AerofoilPortable/ -I../GpShell/ -s ASYNCIFY %DEBUG_LEVEL_FLAGS% -DGP_DEBUG_CONFIG=0 emcc -c %INPUT_DIR%/AerofoilWeb_Combined.cpp -o %OUTPUT_DIR%/AerofoilWeb_Combined.o %FLAGS% diff --git a/AerofoilWeb/GpFileSystem_Web.cpp b/AerofoilWeb/GpFileSystem_Web.cpp index a5da4b6..b823a12 100644 --- a/AerofoilWeb/GpFileSystem_Web.cpp +++ b/AerofoilWeb/GpFileSystem_Web.cpp @@ -386,7 +386,8 @@ bool GpFileSystem_Web::ms_fsStateDirty; bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution) { - const char *prefsAppend = nullptr; + const char *pathAppend = nullptr; + const std::string *rootPath = nullptr; std::string unsanitized; switch (virtualDirectory) @@ -401,24 +402,32 @@ bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualD unsanitized = std::string("Resources"); break; case PortabilityLayer::VirtualDirectories::kHighScores: - prefsAppend = "HighScores"; + pathAppend = "HighScores"; + rootPath = &m_basePath; break; case PortabilityLayer::VirtualDirectories::kUserData: - prefsAppend = "Houses"; + pathAppend = "Houses"; + rootPath = &m_basePath; break; case PortabilityLayer::VirtualDirectories::kUserSaves: - prefsAppend = "SavedGames"; + pathAppend = "SavedGames"; + rootPath = &m_basePath; break; case PortabilityLayer::VirtualDirectories::kPrefs: - prefsAppend = "Prefs"; + pathAppend = "Prefs"; + rootPath = &m_basePath; + break; + case PortabilityLayer::VirtualDirectories::kSourceExport: + pathAppend = "Export"; + rootPath = &m_exportPath; break; default: return false; }; - if (prefsAppend) + if (pathAppend) { - unsanitized = prefsAppend; + unsanitized = pathAppend; for (size_t i = 0; i < numPaths; i++) { @@ -448,7 +457,7 @@ bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualD } } - resolution = m_prefsPath + "/" + sanitized; + resolution = (*rootPath) + "/" + sanitized; } else { @@ -478,6 +487,7 @@ GpFileSystem_Web::~GpFileSystem_Web() void GpFileSystem_Web::Init() { m_prefsPath = "/aerofoil"; + m_exportPath = "/aerofoil_memfs"; char *baseDir = SDL_GetBasePath(); m_basePath = baseDir; diff --git a/AerofoilWeb/GpFileSystem_Web.h b/AerofoilWeb/GpFileSystem_Web.h index 3eb7b81..f0ae197 100644 --- a/AerofoilWeb/GpFileSystem_Web.h +++ b/AerofoilWeb/GpFileSystem_Web.h @@ -60,6 +60,7 @@ private: std::string m_prefsPath; std::string m_basePath; + std::string m_exportPath; static bool ms_fsStateDirty; static GpFileSystem_Web ms_instance; diff --git a/AerofoilWeb/GpMain_SDL_Web.cpp b/AerofoilWeb/GpMain_SDL_Web.cpp index 6ca001c..9ef6412 100644 --- a/AerofoilWeb/GpMain_SDL_Web.cpp +++ b/AerofoilWeb/GpMain_SDL_Web.cpp @@ -2,6 +2,7 @@ #include "SDL_main.h" #include "GpMain.h" +#include "GpAllocator_C.h" #include "GpAudioDriverFactory.h" #include "GpDisplayDriverFactory.h" #include "GpGlobalConfig.h" @@ -28,9 +29,12 @@ IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &pr IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties); EM_JS(void, InitFileSystem, (), { - Asyncify.handleSleep(wakeUp => { - FS.mkdir('/aerofoil'); + Asyncify.handleSleep(wakeUp => { + FS.mkdir('/aerofoil'); + //FS.mkdir('/aerofoil_memfs'); FS.mount(IDBFS, {}, '/aerofoil'); + //FS.mount(MEMFS, {}, '/aerofoil_memfs'); + //FS.mkdir('/aerofoil_memfs/Export'); FS.syncfs(true, function (err) { assert(!err); wakeUp(); @@ -40,6 +44,8 @@ EM_JS(void, InitFileSystem, (), { int main(int argc, char* argv[]) { + IGpAllocator *alloc = GpAllocator_C::GetInstance(); + InitFileSystem(); GpLogDriver_Web::Init(); @@ -65,6 +71,7 @@ int main(int argc, char* argv[]) drivers->SetDriver(GpFileSystem_Web::GetInstance()); drivers->SetDriver(GpSystemServices_Web::GetInstance()); drivers->SetDriver(GpLogDriver_Web::GetInstance()); + drivers->SetDriver(alloc); g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2; @@ -83,6 +90,7 @@ int main(int argc, char* argv[]) g_gpGlobalConfig.m_osGlobals = &g_gpXGlobals; g_gpGlobalConfig.m_logger = logger; g_gpGlobalConfig.m_systemServices = GpSystemServices_Web::GetInstance(); + g_gpGlobalConfig.m_allocator = alloc; GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2); GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL); diff --git a/AerofoilWeb/Link.bat b/AerofoilWeb/Link.bat index 5ea6d17..39524b1 100644 --- a/AerofoilWeb/Link.bat +++ b/AerofoilWeb/Link.bat @@ -1,4 +1,8 @@ set INPUT_DIR=. set OUTPUT_DIR=bin -set FLAGS=-flto -O3 -s USE_SDL=2 -s USE_ZLIB=1 -s ASYNCIFY -s ASYNCIFY_IGNORE_INDIRECT -s INITIAL_MEMORY=33554432 -s ASYNCIFY_ADVISE -lidbfs.js -s ASYNCIFY_IMPORTS=['InitFileSystem','FlushFileSystem'] --shell-file shell_minimal.html -emcc obj/AerofoilWeb_Combined.o obj/AerofoilWeb_Resources.o obj/GpShell_Combined.o obj/AerofoilSDL_Combined.o obj/GpApp_Combined.o obj/PortabilityLayer_Combined.o obj/MacRomanConversion.o -o %OUTPUT_DIR%/aerofoil.html %FLAGS% + +rem set DEBUG_LEVEL_FLAGS=-g4 -O0 +set DEBUG_LEVEL_FLAGS=-O3 + +set FLAGS=-flto %DEBUG_LEVEL_FLAGS% -s USE_SDL=2 -s USE_ZLIB=1 -s ASYNCIFY -s ASYNCIFY_IGNORE_INDIRECT -s INITIAL_MEMORY=33554432 -s ASYNCIFY_ADVISE -lidbfs.js -s ASYNCIFY_IMPORTS=['InitFileSystem','FlushFileSystem'] --shell-file shell_minimal.html +emcc obj/AerofoilWeb_Combined.o obj/AerofoilWeb_Resources.o obj/GpShell_Combined.o obj/AerofoilSDL_Combined.o obj/AerofoilPortable_Combined.o obj/GpApp_Combined.o obj/PortabilityLayer_Combined.o obj/MacRomanConversion.o -o %OUTPUT_DIR%/aerofoil.html %FLAGS% From 1ac8032411a6f0ce10c18ec0882934f1dae0bf16 Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 23:08:29 -0400 Subject: [PATCH 17/31] Log to stdout --- AerofoilWeb/GpLogDriver_Web.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AerofoilWeb/GpLogDriver_Web.cpp b/AerofoilWeb/GpLogDriver_Web.cpp index 973174e..c42eb97 100644 --- a/AerofoilWeb/GpLogDriver_Web.cpp +++ b/AerofoilWeb/GpLogDriver_Web.cpp @@ -58,8 +58,8 @@ void GpLogDriver_Web::VPrintf(Category category, const char *fmt, va_list args) vsnprintf(charBuff, formattedSize + 1, fmt, args); - fprintf(stderr, "%s%s%s\n", timestampBuffer, debugTag, charBuff); - fflush(stderr); + fprintf(stdout, "%s%s%s\n", timestampBuffer, debugTag, charBuff); + fflush(stdout); free(charBuff); } From fb7b9b02d909c31c810159c62281aecefb918c4e Mon Sep 17 00:00:00 2001 From: elasota Date: Fri, 7 May 2021 23:09:35 -0400 Subject: [PATCH 18/31] Web save mechanism --- .gitmodules | 4 + AerofoilWeb/FileSaverDotJS | 1 + AerofoilWeb/GpFileSystem_Web.cpp | 1673 +++++++++++++++--------------- AerofoilWeb/GpFileSystem_Web.h | 3 +- AerofoilWeb/GpMain_SDL_Web.cpp | 215 ++-- AerofoilWeb/Link.bat | 2 + AerofoilWeb/shell_minimal.html | 3 +- 7 files changed, 977 insertions(+), 924 deletions(-) create mode 100644 .gitmodules create mode 160000 AerofoilWeb/FileSaverDotJS diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..75d6a2d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "AerofoilWeb/FileSaverDotJS"] + path = AerofoilWeb/FileSaverDotJS + url = https://github.com/eligrey/FileSaver.js.git + branch = master diff --git a/AerofoilWeb/FileSaverDotJS b/AerofoilWeb/FileSaverDotJS new file mode 160000 index 0000000..b5e61ec --- /dev/null +++ b/AerofoilWeb/FileSaverDotJS @@ -0,0 +1 @@ +Subproject commit b5e61ec88969461ce0504658af07c2b56650ee8c diff --git a/AerofoilWeb/GpFileSystem_Web.cpp b/AerofoilWeb/GpFileSystem_Web.cpp index b823a12..ef760f2 100644 --- a/AerofoilWeb/GpFileSystem_Web.cpp +++ b/AerofoilWeb/GpFileSystem_Web.cpp @@ -1,817 +1,862 @@ -#define _LARGEFILE64_SOURCE -#include "GpFileSystem_Web.h" -#include "GpIOStream.h" -#include "IGpDirectoryCursor.h" -#include "IGpSystemServices.h" -#include "IGpMutex.h" -#include "VirtualDirectory.h" - -#include "PLDrivers.h" - -#include "SDL2/SDL.h" -#include "SDL2/SDL_rwops.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "UTF8.h" - -#if defined(__CYGWIN__) || defined(__EMSCRIPTEN__) -typedef off_t off64_t; -#define fstat64 fstat -#define fseek64 fseek -#define ftruncate64 ftruncate -#define stat64 stat -#endif - -EM_JS(void, FlushFileSystem, (), { - Asyncify.handleSleep(wakeUp => { - FS.syncfs(false, function (err) { - assert(!err); - wakeUp(); - }); - }); -}); - - -class GpDirectoryCursor_Web final : public IGpDirectoryCursor -{ -public: - explicit GpDirectoryCursor_Web(DIR *dir, const std::string &prefix); - ~GpDirectoryCursor_Web(); - - bool GetNext(const char *&outFileName) override; - void Destroy() override; - -private: - DIR *m_dir; - std::string m_prefix; - std::string m_decodedFileName; -}; - -GpDirectoryCursor_Web::GpDirectoryCursor_Web(DIR *dir, const std::string &prefix) - : m_dir(dir) - , m_prefix(prefix) -{ -} - -GpDirectoryCursor_Web::~GpDirectoryCursor_Web() -{ - closedir(m_dir); -} - -bool GpDirectoryCursor_Web::GetNext(const char *&outFileName) -{ - const size_t prefixLength = m_prefix.size(); - - for (;;) - { - struct dirent *dir = readdir(m_dir); - if (!dir) - return false; - - const char *fname = dir->d_name; - - const size_t fnameLen = strlen(fname); - if (fnameLen > prefixLength && (prefixLength == 0 || !memcmp(&m_prefix[0], fname, prefixLength))) - { - const char *encodedResult = fname + prefixLength; - - m_decodedFileName.clear(); - for (size_t i = 0; encodedResult[i] != 0; i++) - { - char c = encodedResult[i]; - if (c == '%') - { - char highNibble = encodedResult[i + 1]; - if ((highNibble >= '0' && highNibble <= '9') || (highNibble >= 'a' && highNibble <= 'f') || (highNibble >= 'A' && highNibble <= 'F')) - { - char lowNibble = encodedResult[i + 2]; - - if ((lowNibble >= '0' && lowNibble <= '9') || (lowNibble >= 'a' && lowNibble <= 'f') || (lowNibble >= 'A' && lowNibble <= 'F')) - { - bool failedNibble = false; - char nibbles[2] = { highNibble, lowNibble }; - int decNibbles[2]; - for (int ni = 0; ni < 2; ni++) - { - char nc = nibbles[ni]; - if (nc >= '0' && nc <= '9') - decNibbles[ni] = nc - '0'; - else if (nc >= 'a' && nc <= 'f') - decNibbles[ni] = 0xa + (nc - 'a'); - else if (nc >= 'A' && nc <= 'F') - decNibbles[ni] = 0xa + (nc - 'A'); - else - failedNibble = true; - } - - if (!failedNibble) - { - c = static_cast((decNibbles[0] << 4) + decNibbles[1]); - i += 2; - } - } - } - } - - m_decodedFileName += c; - } - - outFileName = m_decodedFileName.c_str(); - return true; - } - } - return true; -} - -void GpDirectoryCursor_Web::Destroy() -{ - delete this; -} - -class GpFileStream_Web_StaticMemFile final : public GpIOStream -{ -public: - GpFileStream_Web_StaticMemFile(const unsigned char *bytes, size_t size); - ~GpFileStream_Web_StaticMemFile(); - - size_t Read(void *bytesOut, size_t size) override; - size_t Write(const void *bytes, size_t size) override; - bool IsSeekable() const override; - bool IsReadOnly() const override; - bool IsWriteOnly() const override; - bool SeekStart(GpUFilePos_t loc) override; - bool SeekCurrent(GpFilePos_t loc) override; - bool SeekEnd(GpUFilePos_t loc) override; - GpUFilePos_t Size() const override; - GpUFilePos_t Tell() const override; - void GP_ASYNCIFY_PARANOID_NAMED(Close)() override; - void Flush() override; - -private: - const unsigned char *m_bytes; - size_t m_offset; - size_t m_size; -}; - -GpFileStream_Web_StaticMemFile::GpFileStream_Web_StaticMemFile(const unsigned char *bytes, size_t size) - : m_bytes(bytes) - , m_size(size) - , m_offset(0) -{ -} - -GpFileStream_Web_StaticMemFile::~GpFileStream_Web_StaticMemFile() -{ -} - -size_t GpFileStream_Web_StaticMemFile::Read(void *bytesOut, size_t size) -{ - size_t available = m_size - m_offset; - size = std::min(size, available); - - memcpy(bytesOut, m_bytes + m_offset, size); - m_offset += size; - return size; -} - -size_t GpFileStream_Web_StaticMemFile::Write(const void *bytes, size_t size) -{ - return 0; -} - -bool GpFileStream_Web_StaticMemFile::IsSeekable() const -{ - return true; -} - -bool GpFileStream_Web_StaticMemFile::IsReadOnly() const -{ - return true; -} - -bool GpFileStream_Web_StaticMemFile::IsWriteOnly() const -{ - return false; -} - -bool GpFileStream_Web_StaticMemFile::SeekStart(GpUFilePos_t loc) -{ - if (loc > m_size) - return false; - - m_offset = static_cast(loc); - return true; -} - -bool GpFileStream_Web_StaticMemFile::SeekCurrent(GpFilePos_t loc) -{ - GpFilePos_t minOffset = -static_cast(m_offset); - GpFilePos_t maxOffset = static_cast(m_size - m_offset); - - if (loc < minOffset || loc > maxOffset) - return false; - - m_offset = static_cast(static_cast(m_offset) + loc); - return true; -} - -bool GpFileStream_Web_StaticMemFile::SeekEnd(GpUFilePos_t loc) -{ - if (loc > m_size) - return false; - - m_offset = m_size - loc; - return true; -} - -GpUFilePos_t GpFileStream_Web_StaticMemFile::Size() const -{ - return m_size; -} - -GpUFilePos_t GpFileStream_Web_StaticMemFile::Tell() const -{ - return m_offset; -} - -void GpFileStream_Web_StaticMemFile::GP_ASYNCIFY_PARANOID_NAMED(Close)() -{ - delete this; -} - -void GpFileStream_Web_StaticMemFile::Flush() -{ -} - - -class GpFileStream_Web_File final : public GpIOStream -{ -public: - GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly, bool synchronizeOnClose); - ~GpFileStream_Web_File(); - - size_t Read(void *bytesOut, size_t size) override; - size_t Write(const void *bytes, size_t size) override; - bool IsSeekable() const override; - bool IsReadOnly() const override; - bool IsWriteOnly() const override; - bool SeekStart(GpUFilePos_t loc) override; - bool SeekCurrent(GpFilePos_t loc) override; - bool SeekEnd(GpUFilePos_t loc) override; - GpUFilePos_t Size() const override; - GpUFilePos_t Tell() const override; - void GP_ASYNCIFY_PARANOID_NAMED(Close)() override; - void Flush() override; - -private: - FILE *m_f; - bool m_seekable; - bool m_isReadOnly; - bool m_isWriteOnly; - bool m_synchronizeOnClose; -}; - - -GpFileStream_Web_File::GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly, bool synchronizeOnClose) - : m_f(f) - , m_isReadOnly(readOnly) - , m_isWriteOnly(writeOnly) - , m_synchronizeOnClose(synchronizeOnClose) -{ - m_seekable = (fseek(m_f, 0, SEEK_CUR) == 0); -} - -GpFileStream_Web_File::~GpFileStream_Web_File() -{ - fclose(m_f); - - if (m_synchronizeOnClose) - GpFileSystem_Web::MarkFSStateDirty(); -} - -size_t GpFileStream_Web_File::Read(void *bytesOut, size_t size) -{ - if (m_isWriteOnly) - return 0; - return fread(bytesOut, 1, size, m_f); -} - -size_t GpFileStream_Web_File::Write(const void *bytes, size_t size) -{ - if (m_isReadOnly) - return 0; - return fwrite(bytes, 1, size, m_f); -} - -bool GpFileStream_Web_File::IsSeekable() const -{ - return m_seekable; -} - -bool GpFileStream_Web_File::IsReadOnly() const -{ - return m_isReadOnly; -} - -bool GpFileStream_Web_File::IsWriteOnly() const -{ - return m_isWriteOnly; -} - -bool GpFileStream_Web_File::SeekStart(GpUFilePos_t loc) -{ - if (!m_seekable) - return false; - - fflush(m_f); - return fseek64(m_f, static_cast(loc), SEEK_SET) >= 0; -} - -bool GpFileStream_Web_File::SeekCurrent(GpFilePos_t loc) -{ - if (!m_seekable) - return false; - - fflush(m_f); - return fseek64(m_f, static_cast(loc), SEEK_CUR) >= 0; -} - -bool GpFileStream_Web_File::SeekEnd(GpUFilePos_t loc) -{ - if (!m_seekable) - return false; - - fflush(m_f); - return fseek64(m_f, -static_cast(loc), SEEK_END) >= 0; -} - -GpUFilePos_t GpFileStream_Web_File::Size() const -{ - fflush(m_f); - - struct stat64 s; - if (fstat64(fileno(m_f), &s) < 0) - return 0; - - return static_cast(s.st_size); -} - -GpUFilePos_t GpFileStream_Web_File::Tell() const -{ - return static_cast(ftell(m_f)); -} - -void GpFileStream_Web_File::GP_ASYNCIFY_PARANOID_NAMED(Close)() -{ - this->~GpFileStream_Web_File(); - free(this); -} - -void GpFileStream_Web_File::Flush() -{ - fflush(m_f); -} - - -bool GpFileSystem_Web::ms_fsStateDirty; - - -bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution) -{ +#define _LARGEFILE64_SOURCE +#include "GpFileSystem_Web.h" +#include "GpIOStream.h" +#include "IGpDirectoryCursor.h" +#include "IGpSystemServices.h" +#include "IGpMutex.h" +#include "VirtualDirectory.h" + +#include "PLDrivers.h" + +#include "SDL2/SDL.h" +#include "SDL2/SDL_rwops.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UTF8.h" + +#if defined(__CYGWIN__) || defined(__EMSCRIPTEN__) +typedef off_t off64_t; +#define fstat64 fstat +#define fseek64 fseek +#define ftruncate64 ftruncate +#define stat64 stat +#endif + +EM_JS(void, FlushFileSystem, (), { + Asyncify.handleSleep(wakeUp => { + FS.syncfs(false, function (err) { + assert(!err); + wakeUp(); + }); + }); +}); + +EM_JS(void, DownloadAndDeleteFile, (const char *fileNamePtr, const char *prettyNamePtr), { + var fileName = UTF8ToString(fileNamePtr); + var prettyName = UTF8ToString(prettyNamePtr); + console.log("Flush download of file " + fileName + " as " + prettyName); + + var mimeType = "application/octet-stream"; + if (prettyName.endsWith(".bin")) + mimeType = "application/macbinary"; + else if (prettyName.endsWith(".gpf")) + mimeType = "application/zip"; + + var byteArray = FS.readFile(fileName, { encoding: "binary" }); + var blob = new Blob([byteArray], { type: mimeType }); + saveAs(blob, prettyName); +}); + + +class GpDirectoryCursor_Web final : public IGpDirectoryCursor +{ +public: + explicit GpDirectoryCursor_Web(DIR *dir, const std::string &prefix); + ~GpDirectoryCursor_Web(); + + bool GetNext(const char *&outFileName) override; + void Destroy() override; + +private: + DIR *m_dir; + std::string m_prefix; + std::string m_decodedFileName; +}; + +GpDirectoryCursor_Web::GpDirectoryCursor_Web(DIR *dir, const std::string &prefix) + : m_dir(dir) + , m_prefix(prefix) +{ +} + +GpDirectoryCursor_Web::~GpDirectoryCursor_Web() +{ + closedir(m_dir); +} + +bool GpDirectoryCursor_Web::GetNext(const char *&outFileName) +{ + const size_t prefixLength = m_prefix.size(); + + for (;;) + { + struct dirent *dir = readdir(m_dir); + if (!dir) + return false; + + const char *fname = dir->d_name; + + const size_t fnameLen = strlen(fname); + if (fnameLen > prefixLength && (prefixLength == 0 || !memcmp(&m_prefix[0], fname, prefixLength))) + { + const char *encodedResult = fname + prefixLength; + + m_decodedFileName.clear(); + for (size_t i = 0; encodedResult[i] != 0; i++) + { + char c = encodedResult[i]; + if (c == '%') + { + char highNibble = encodedResult[i + 1]; + if ((highNibble >= '0' && highNibble <= '9') || (highNibble >= 'a' && highNibble <= 'f') || (highNibble >= 'A' && highNibble <= 'F')) + { + char lowNibble = encodedResult[i + 2]; + + if ((lowNibble >= '0' && lowNibble <= '9') || (lowNibble >= 'a' && lowNibble <= 'f') || (lowNibble >= 'A' && lowNibble <= 'F')) + { + bool failedNibble = false; + char nibbles[2] = { highNibble, lowNibble }; + int decNibbles[2]; + for (int ni = 0; ni < 2; ni++) + { + char nc = nibbles[ni]; + if (nc >= '0' && nc <= '9') + decNibbles[ni] = nc - '0'; + else if (nc >= 'a' && nc <= 'f') + decNibbles[ni] = 0xa + (nc - 'a'); + else if (nc >= 'A' && nc <= 'F') + decNibbles[ni] = 0xa + (nc - 'A'); + else + failedNibble = true; + } + + if (!failedNibble) + { + c = static_cast((decNibbles[0] << 4) + decNibbles[1]); + i += 2; + } + } + } + } + + m_decodedFileName += c; + } + + outFileName = m_decodedFileName.c_str(); + return true; + } + } + return true; +} + +void GpDirectoryCursor_Web::Destroy() +{ + delete this; +} + +class GpFileStream_Web_StaticMemFile final : public GpIOStream +{ +public: + GpFileStream_Web_StaticMemFile(const unsigned char *bytes, size_t size); + ~GpFileStream_Web_StaticMemFile(); + + size_t Read(void *bytesOut, size_t size) override; + size_t Write(const void *bytes, size_t size) override; + bool IsSeekable() const override; + bool IsReadOnly() const override; + bool IsWriteOnly() const override; + bool SeekStart(GpUFilePos_t loc) override; + bool SeekCurrent(GpFilePos_t loc) override; + bool SeekEnd(GpUFilePos_t loc) override; + GpUFilePos_t Size() const override; + GpUFilePos_t Tell() const override; + void GP_ASYNCIFY_PARANOID_NAMED(Close)() override; + void Flush() override; + +private: + const unsigned char *m_bytes; + size_t m_offset; + size_t m_size; +}; + +GpFileStream_Web_StaticMemFile::GpFileStream_Web_StaticMemFile(const unsigned char *bytes, size_t size) + : m_bytes(bytes) + , m_size(size) + , m_offset(0) +{ +} + +GpFileStream_Web_StaticMemFile::~GpFileStream_Web_StaticMemFile() +{ +} + +size_t GpFileStream_Web_StaticMemFile::Read(void *bytesOut, size_t size) +{ + size_t available = m_size - m_offset; + size = std::min(size, available); + + memcpy(bytesOut, m_bytes + m_offset, size); + m_offset += size; + return size; +} + +size_t GpFileStream_Web_StaticMemFile::Write(const void *bytes, size_t size) +{ + return 0; +} + +bool GpFileStream_Web_StaticMemFile::IsSeekable() const +{ + return true; +} + +bool GpFileStream_Web_StaticMemFile::IsReadOnly() const +{ + return true; +} + +bool GpFileStream_Web_StaticMemFile::IsWriteOnly() const +{ + return false; +} + +bool GpFileStream_Web_StaticMemFile::SeekStart(GpUFilePos_t loc) +{ + if (loc > m_size) + return false; + + m_offset = static_cast(loc); + return true; +} + +bool GpFileStream_Web_StaticMemFile::SeekCurrent(GpFilePos_t loc) +{ + GpFilePos_t minOffset = -static_cast(m_offset); + GpFilePos_t maxOffset = static_cast(m_size - m_offset); + + if (loc < minOffset || loc > maxOffset) + return false; + + m_offset = static_cast(static_cast(m_offset) + loc); + return true; +} + +bool GpFileStream_Web_StaticMemFile::SeekEnd(GpUFilePos_t loc) +{ + if (loc > m_size) + return false; + + m_offset = m_size - loc; + return true; +} + +GpUFilePos_t GpFileStream_Web_StaticMemFile::Size() const +{ + return m_size; +} + +GpUFilePos_t GpFileStream_Web_StaticMemFile::Tell() const +{ + return m_offset; +} + +void GpFileStream_Web_StaticMemFile::GP_ASYNCIFY_PARANOID_NAMED(Close)() +{ + delete this; +} + +void GpFileStream_Web_StaticMemFile::Flush() +{ +} + + +class GpFileStream_Web_File final : public GpIOStream +{ +public: + GpFileStream_Web_File(FILE *f, const std::string &filePath, const std::string &prettyName, bool readOnly, bool writeOnly, bool synchronizeOnClose, bool isIDB); + ~GpFileStream_Web_File(); + + size_t Read(void *bytesOut, size_t size) override; + size_t Write(const void *bytes, size_t size) override; + bool IsSeekable() const override; + bool IsReadOnly() const override; + bool IsWriteOnly() const override; + bool SeekStart(GpUFilePos_t loc) override; + bool SeekCurrent(GpFilePos_t loc) override; + bool SeekEnd(GpUFilePos_t loc) override; + GpUFilePos_t Size() const override; + GpUFilePos_t Tell() const override; + void GP_ASYNCIFY_PARANOID_NAMED(Close)() override; + void Flush() override; + +private: + FILE *m_f; + std::string m_filePath; + std::string m_prettyName; + bool m_seekable; + bool m_isReadOnly; + bool m_isWriteOnly; + bool m_synchronizeOnClose; + bool m_isIDB; +}; + + +GpFileStream_Web_File::GpFileStream_Web_File(FILE *f, const std::string &filePath, const std::string &prettyName, bool readOnly, bool writeOnly, bool synchronizeOnClose, bool isIDB) + : m_f(f) + , m_isReadOnly(readOnly) + , m_isWriteOnly(writeOnly) + , m_synchronizeOnClose(synchronizeOnClose) + , m_isIDB(isIDB) + , m_filePath(filePath) + , m_prettyName(prettyName) +{ + m_seekable = (fseek(m_f, 0, SEEK_CUR) == 0); +} + +GpFileStream_Web_File::~GpFileStream_Web_File() +{ + fclose(m_f); + + if (m_synchronizeOnClose) + { + if (m_isIDB) + GpFileSystem_Web::MarkFSStateDirty(); + else + GpFileSystem_Web::SyncDownloadFile(m_filePath, m_prettyName); + } +} + +size_t GpFileStream_Web_File::Read(void *bytesOut, size_t size) +{ + if (m_isWriteOnly) + return 0; + return fread(bytesOut, 1, size, m_f); +} + +size_t GpFileStream_Web_File::Write(const void *bytes, size_t size) +{ + if (m_isReadOnly) + return 0; + return fwrite(bytes, 1, size, m_f); +} + +bool GpFileStream_Web_File::IsSeekable() const +{ + return m_seekable; +} + +bool GpFileStream_Web_File::IsReadOnly() const +{ + return m_isReadOnly; +} + +bool GpFileStream_Web_File::IsWriteOnly() const +{ + return m_isWriteOnly; +} + +bool GpFileStream_Web_File::SeekStart(GpUFilePos_t loc) +{ + if (!m_seekable) + return false; + + fflush(m_f); + return fseek64(m_f, static_cast(loc), SEEK_SET) >= 0; +} + +bool GpFileStream_Web_File::SeekCurrent(GpFilePos_t loc) +{ + if (!m_seekable) + return false; + + fflush(m_f); + return fseek64(m_f, static_cast(loc), SEEK_CUR) >= 0; +} + +bool GpFileStream_Web_File::SeekEnd(GpUFilePos_t loc) +{ + if (!m_seekable) + return false; + + fflush(m_f); + return fseek64(m_f, -static_cast(loc), SEEK_END) >= 0; +} + +GpUFilePos_t GpFileStream_Web_File::Size() const +{ + fflush(m_f); + + struct stat64 s; + if (fstat64(fileno(m_f), &s) < 0) + return 0; + + return static_cast(s.st_size); +} + +GpUFilePos_t GpFileStream_Web_File::Tell() const +{ + return static_cast(ftell(m_f)); +} + +void GpFileStream_Web_File::GP_ASYNCIFY_PARANOID_NAMED(Close)() +{ + this->~GpFileStream_Web_File(); + free(this); +} + +void GpFileStream_Web_File::Flush() +{ + fflush(m_f); +} + + +bool GpFileSystem_Web::ms_fsStateDirty; + + +bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution, bool &outIsIDB) +{ const char *pathAppend = nullptr; - const std::string *rootPath = nullptr; - std::string unsanitized; - - switch (virtualDirectory) - { - case PortabilityLayer::VirtualDirectories::kApplicationData: - unsanitized = std::string("Packaged"); - break; - case PortabilityLayer::VirtualDirectories::kGameData: - unsanitized = std::string("Packaged/Houses"); - break; - case PortabilityLayer::VirtualDirectories::kFonts: - unsanitized = std::string("Resources"); - break; - case PortabilityLayer::VirtualDirectories::kHighScores: + const std::string *rootPath = nullptr; + std::string unsanitized; + bool isIDB = false; + + switch (virtualDirectory) + { + case PortabilityLayer::VirtualDirectories::kApplicationData: + unsanitized = std::string("Packaged"); + break; + case PortabilityLayer::VirtualDirectories::kGameData: + unsanitized = std::string("Packaged/Houses"); + break; + case PortabilityLayer::VirtualDirectories::kFonts: + unsanitized = std::string("Resources"); + break; + case PortabilityLayer::VirtualDirectories::kHighScores: pathAppend = "HighScores"; - rootPath = &m_basePath; - break; - case PortabilityLayer::VirtualDirectories::kUserData: - pathAppend = "Houses"; - rootPath = &m_basePath; - break; - case PortabilityLayer::VirtualDirectories::kUserSaves: - pathAppend = "SavedGames"; - rootPath = &m_basePath; - break; - case PortabilityLayer::VirtualDirectories::kPrefs: - pathAppend = "Prefs"; - rootPath = &m_basePath; - break; - case PortabilityLayer::VirtualDirectories::kSourceExport: + rootPath = &m_basePath; + isIDB = true; + break; + case PortabilityLayer::VirtualDirectories::kUserData: + pathAppend = "Houses"; + rootPath = &m_basePath; + isIDB = true; + break; + case PortabilityLayer::VirtualDirectories::kUserSaves: + pathAppend = "SavedGames"; + rootPath = &m_basePath; + isIDB = true; + break; + case PortabilityLayer::VirtualDirectories::kPrefs: + pathAppend = "Prefs"; + rootPath = &m_basePath; + isIDB = true; + break; + case PortabilityLayer::VirtualDirectories::kSourceExport: pathAppend = "Export"; - rootPath = &m_exportPath; - break; - default: - return false; - }; - - if (pathAppend) - { - unsanitized = pathAppend; - - for (size_t i = 0; i < numPaths; i++) - { - unsanitized += "/"; - unsanitized += paths[i]; - } - - if (trailingSlash) - unsanitized += "/"; - - std::string sanitized; - for (size_t i = 0; i < unsanitized.size(); i++) - { - char c = unsanitized[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') - sanitized += c; - else - { - const char *nibbles = "0123456789abcdef"; - char subPath[4]; - subPath[0] = '%'; - subPath[1] = nibbles[(c >> 4) & 0xf]; - subPath[2] = nibbles[c & 0xf]; - subPath[3] = 0; - - sanitized += subPath; - } - } - - resolution = (*rootPath) + "/" + sanitized; - } - else - { - std::string sanitized = m_basePath + unsanitized; - - for (size_t i = 0; i < numPaths; i++) - { - sanitized += "/"; - sanitized += paths[i]; - } - - resolution = sanitized; - } - - return true; -} - -GpFileSystem_Web::GpFileSystem_Web() - : m_delayCallback(nullptr) -{ -} - -GpFileSystem_Web::~GpFileSystem_Web() -{ -} - -void GpFileSystem_Web::Init() -{ - m_prefsPath = "/aerofoil"; - m_exportPath = "/aerofoil_memfs"; - - char *baseDir = SDL_GetBasePath(); - m_basePath = baseDir; - SDL_free(baseDir); - - char baseDirSeparator = m_basePath[m_basePath.size() - 1]; - if (m_basePath.size() >= 4 && m_basePath.substr(m_basePath.size() - 4, 3) == "bin") - m_basePath = m_basePath.substr(0, m_basePath.size() - 4) + "lib" + baseDirSeparator + "aerofoil" + baseDirSeparator; -} - -bool GpFileSystem_Web::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) -{ - if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) - { - for (size_t i = 0; i < catalog->m_numEntries; i++) - { - const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i]; - if (!strcmp(path, entry.m_fileName)) - return true; - } - - return false; - } - - std::string resolvedPath; - if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath)) - return false; - - struct stat s; - return stat(resolvedPath.c_str(), &s) == 0; -} - -bool GpFileSystem_Web::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) -{ - if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) - { - for (size_t i = 0; i < catalog->m_numEntries; i++) - { - const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i]; - if (!strcmp(path, entry.m_fileName)) - { - exists = true; - return true; - } - } - - exists = false; - return false; - } - - std::string resolvedPath; - if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath)) - { - if (exists) - exists = false; - return false; - } - - int permissions = access(resolvedPath.c_str(), W_OK | F_OK); - exists = ((permissions & F_OK) != 0); - return ((permissions & W_OK) != 0); -} - -GpIOStream *GpFileSystem_Web::OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) -{ - if (numSubPaths == 1) - { - if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) - { - for (size_t i = 0; i < catalog->m_numEntries; i++) - { - const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i]; - if (!strcmp(subPaths[0], entry.m_fileName)) - return new GpFileStream_Web_StaticMemFile(entry.m_data, entry.m_size); - } - - return nullptr; - } - } - - const char *mode = nullptr; - bool canWrite = false; - bool needResetPosition = false; - - switch (createDisposition) - { - case GpFileCreationDispositions::kCreateOrOverwrite: - mode = "wb"; - break; - case GpFileCreationDispositions::kCreateNew: - mode = "x+b"; - break; - case GpFileCreationDispositions::kCreateOrOpen: - mode = "a+b"; - needResetPosition = true; - break; - case GpFileCreationDispositions::kOpenExisting: - mode = writeAccess ? "r+b" : "rb"; - break; - case GpFileCreationDispositions::kOverwriteExisting: - mode = "r+b"; - break; - default: - return nullptr; - }; - - if (virtualDirectory == PortabilityLayer::VirtualDirectories::kSourceExport) - return nullptr; - - std::string resolvedPath; - if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, false, resolvedPath)) - return nullptr; - - void *objStorage = malloc(sizeof(GpFileStream_Web_File)); - if (!objStorage) - return nullptr; - - FILE *f = fopen(resolvedPath.c_str(), mode); - if (!f) - { - free(objStorage); - return nullptr; - } - - if (needResetPosition) - fseek(f, 0, SEEK_SET); - - if (createDisposition == GpFileCreationDispositions::kOverwriteExisting) - { - if (ftruncate64(fileno(f), 0) < 0) - { - free(objStorage); - fclose(f); - return nullptr; - } - } - - return new (objStorage) GpFileStream_Web_File(f, !writeAccess, false, writeAccess); -} - -bool GpFileSystem_Web::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) -{ - if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) - return false; - - std::string resolvedPath; - if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath)) - { - existed = false; - return false; - } - - if (unlink(resolvedPath.c_str()) < 0) - { - existed = (errno != ENOENT); - if (existed) - FlushFileSystem(); - - return false; - } - existed = true; - return true; -} - -bool GpFileSystem_Web::ValidateFilePath(const char *path, size_t length) const -{ - for (size_t i = 0; i < length; i++) - { - const char c = path[i]; - if (c >= '0' && c <= '9') - continue; - - if (c == '_' || c == '.' || c == '\'' || c == '!') - continue; - - if (c == ' ' && i != 0 && i != length - 1) - continue; - - if (c >= 'a' && c <= 'z') - continue; - - if (c >= 'A' && c <= 'Z') - continue; - - return false; - } - - return true; -} - -bool GpFileSystem_Web::ValidateFilePathUnicodeChar(uint32_t c) const -{ - if (c >= '0' && c <= '9') - return true; - - if (c == '_' || c == '\'') - return true; - - if (c == ' ') - return true; - - if (c >= 'a' && c <= 'z') - return true; - - if (c >= 'A' && c <= 'Z') - return true; - - return false; -} - -void GpFileSystem_Web::SetDelayCallback(DelayCallback_t delayCallback) -{ - m_delayCallback = delayCallback; -} - -GpFileSystem_Web *GpFileSystem_Web::GetInstance() -{ - return &ms_instance; -} - -class GpDirectoryCursor_StringList final : public IGpDirectoryCursor -{ -public: - explicit GpDirectoryCursor_StringList(std::vector &paths); - ~GpDirectoryCursor_StringList(); - - bool GetNext(const char *&outFileName) override; - void Destroy() override; - -private: - std::vector m_paths; - size_t m_index; -}; - -GpDirectoryCursor_StringList::GpDirectoryCursor_StringList(std::vector &paths) - : m_index(0) -{ - std::swap(paths, m_paths); -} - -GpDirectoryCursor_StringList::~GpDirectoryCursor_StringList() -{ -} - -bool GpDirectoryCursor_StringList::GetNext(const char *&outFileName) -{ - if (m_index == m_paths.size()) - return false; - outFileName = m_paths[m_index].c_str(); - m_index++; - return true; -} - -void GpDirectoryCursor_StringList::Destroy() -{ - delete this; -} - - -IGpDirectoryCursor *GpFileSystem_Web::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) -{ - if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) - return ScanCatalog(*catalog); - - std::string resolvedPrefix; - if (!ResolvePath(virtualDirectory, paths, numPaths, true, resolvedPrefix)) - return nullptr; - - std::string trimmedPrefix = resolvedPrefix.substr(m_prefsPath.size() + 1); - - DIR *d = opendir(m_prefsPath.c_str()); - if (!d) - return nullptr; - - return new GpDirectoryCursor_Web(d, trimmedPrefix); -} - -const GpFileSystem_Web_Resources::FileCatalog *GpFileSystem_Web::GetCatalogForVirtualDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory) -{ - if (virtualDirectory == PortabilityLayer::VirtualDirectories::kApplicationData) - return &GpFileSystem_Web_Resources::ApplicationData::GetCatalog(); - - if (virtualDirectory == PortabilityLayer::VirtualDirectories::kGameData) - return &GpFileSystem_Web_Resources::GameData::GetCatalog(); - - return nullptr; -} - -IGpDirectoryCursor *GpFileSystem_Web::ScanCatalog(const GpFileSystem_Web_Resources::FileCatalog &catalog) -{ - std::vector paths; - for (size_t i = 0; i < catalog.m_numEntries; i++) - paths.push_back(std::string(catalog.m_entries[i].m_fileName)); - - return new GpDirectoryCursor_StringList(paths); -} - -void GpFileSystem_Web::MarkFSStateDirty() -{ - ms_fsStateDirty = true; -} - -void GpFileSystem_Web::FlushFS() -{ - if (ms_fsStateDirty) - { - ms_fsStateDirty = false; - FlushFileSystem(); - } -} - - -#if GP_ASYNCIFY_PARANOID -void GpIOStream::Close() -{ - this->GP_ASYNCIFY_PARANOID_NAMED(Close)(); - GpFileSystem_Web::FlushFS(); -} - -bool IGpFileSystem::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) -{ - return static_cast(this)->DeleteFile(virtualDirectory, path, existed); -} - -#endif - -GpFileSystem_Web GpFileSystem_Web::ms_instance; + rootPath = &m_exportPath; + isIDB = false; + break; + default: + return false; + }; + + if (pathAppend) + { + unsanitized = pathAppend; + + for (size_t i = 0; i < numPaths; i++) + { + unsanitized += "/"; + unsanitized += paths[i]; + } + + if (trailingSlash) + unsanitized += "/"; + + std::string sanitized; + for (size_t i = 0; i < unsanitized.size(); i++) + { + char c = unsanitized[i]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') + sanitized += c; + else + { + const char *nibbles = "0123456789abcdef"; + char subPath[4]; + subPath[0] = '%'; + subPath[1] = nibbles[(c >> 4) & 0xf]; + subPath[2] = nibbles[c & 0xf]; + subPath[3] = 0; + + sanitized += subPath; + } + } + + resolution = (*rootPath) + "/" + sanitized; + } + else + { + std::string sanitized = m_basePath + unsanitized; + + for (size_t i = 0; i < numPaths; i++) + { + sanitized += "/"; + sanitized += paths[i]; + } + + resolution = sanitized; + } + + outIsIDB = isIDB; + return true; +} + +GpFileSystem_Web::GpFileSystem_Web() + : m_delayCallback(nullptr) +{ +} + +GpFileSystem_Web::~GpFileSystem_Web() +{ +} + +void GpFileSystem_Web::Init() +{ + m_prefsPath = "/aerofoil"; + m_exportPath = "/aerofoil_memfs"; + + char *baseDir = SDL_GetBasePath(); + m_basePath = baseDir; + SDL_free(baseDir); + + char baseDirSeparator = m_basePath[m_basePath.size() - 1]; + if (m_basePath.size() >= 4 && m_basePath.substr(m_basePath.size() - 4, 3) == "bin") + m_basePath = m_basePath.substr(0, m_basePath.size() - 4) + "lib" + baseDirSeparator + "aerofoil" + baseDirSeparator; +} + +bool GpFileSystem_Web::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) +{ + if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) + { + for (size_t i = 0; i < catalog->m_numEntries; i++) + { + const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i]; + if (!strcmp(path, entry.m_fileName)) + return true; + } + + return false; + } + + std::string resolvedPath; + bool isIDB = false; + if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath, isIDB)) + return false; + + struct stat s; + return stat(resolvedPath.c_str(), &s) == 0; +} + +bool GpFileSystem_Web::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) +{ + if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) + { + for (size_t i = 0; i < catalog->m_numEntries; i++) + { + const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i]; + if (!strcmp(path, entry.m_fileName)) + { + exists = true; + return true; + } + } + + exists = false; + return false; + } + + std::string resolvedPath; + bool isIDB = false; + if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath, isIDB)) + { + if (exists) + exists = false; + return false; + } + + int permissions = access(resolvedPath.c_str(), W_OK | F_OK); + exists = ((permissions & F_OK) != 0); + return ((permissions & W_OK) != 0); +} + +GpIOStream *GpFileSystem_Web::OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) +{ + if (numSubPaths == 1) + { + if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) + { + for (size_t i = 0; i < catalog->m_numEntries; i++) + { + const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i]; + if (!strcmp(subPaths[0], entry.m_fileName)) + return new GpFileStream_Web_StaticMemFile(entry.m_data, entry.m_size); + } + + return nullptr; + } + } + + const char *mode = nullptr; + bool canWrite = false; + bool needResetPosition = false; + + switch (createDisposition) + { + case GpFileCreationDispositions::kCreateOrOverwrite: + mode = "wb"; + break; + case GpFileCreationDispositions::kCreateNew: + mode = "x+b"; + break; + case GpFileCreationDispositions::kCreateOrOpen: + mode = "a+b"; + needResetPosition = true; + break; + case GpFileCreationDispositions::kOpenExisting: + mode = writeAccess ? "r+b" : "rb"; + break; + case GpFileCreationDispositions::kOverwriteExisting: + mode = "r+b"; + break; + default: + return nullptr; + }; + + std::string resolvedPath; + bool isIDB = false; + if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, false, resolvedPath, isIDB)) + return nullptr; + + void *objStorage = malloc(sizeof(GpFileStream_Web_File)); + if (!objStorage) + return nullptr; + + FILE *f = fopen(resolvedPath.c_str(), mode); + if (!f) + { + free(objStorage); + return nullptr; + } + + if (needResetPosition) + fseek(f, 0, SEEK_SET); + + if (createDisposition == GpFileCreationDispositions::kOverwriteExisting) + { + if (ftruncate64(fileno(f), 0) < 0) + { + free(objStorage); + fclose(f); + return nullptr; + } + } + + std::string prettyName; + if (numSubPaths > 0) + prettyName = subPaths[numSubPaths - 1]; + + return new (objStorage) GpFileStream_Web_File(f, resolvedPath, prettyName, !writeAccess, false, writeAccess, isIDB); +} + +bool GpFileSystem_Web::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) +{ + if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) + return false; + + std::string resolvedPath; + bool isIDB = false; + if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath, isIDB)) + { + existed = false; + return false; + } + + if (unlink(resolvedPath.c_str()) < 0) + { + existed = (errno != ENOENT); + if (existed && isIDB) + FlushFileSystem(); + + return false; + } + existed = true; + return true; +} + +bool GpFileSystem_Web::ValidateFilePath(const char *path, size_t length) const +{ + for (size_t i = 0; i < length; i++) + { + const char c = path[i]; + if (c >= '0' && c <= '9') + continue; + + if (c == '_' || c == '.' || c == '\'' || c == '!') + continue; + + if (c == ' ' && i != 0 && i != length - 1) + continue; + + if (c >= 'a' && c <= 'z') + continue; + + if (c >= 'A' && c <= 'Z') + continue; + + return false; + } + + return true; +} + +bool GpFileSystem_Web::ValidateFilePathUnicodeChar(uint32_t c) const +{ + if (c >= '0' && c <= '9') + return true; + + if (c == '_' || c == '\'') + return true; + + if (c == ' ') + return true; + + if (c >= 'a' && c <= 'z') + return true; + + if (c >= 'A' && c <= 'Z') + return true; + + return false; +} + +void GpFileSystem_Web::SetDelayCallback(DelayCallback_t delayCallback) +{ + m_delayCallback = delayCallback; +} + +GpFileSystem_Web *GpFileSystem_Web::GetInstance() +{ + return &ms_instance; +} + +class GpDirectoryCursor_StringList final : public IGpDirectoryCursor +{ +public: + explicit GpDirectoryCursor_StringList(std::vector &paths); + ~GpDirectoryCursor_StringList(); + + bool GetNext(const char *&outFileName) override; + void Destroy() override; + +private: + std::vector m_paths; + size_t m_index; +}; + +GpDirectoryCursor_StringList::GpDirectoryCursor_StringList(std::vector &paths) + : m_index(0) +{ + std::swap(paths, m_paths); +} + +GpDirectoryCursor_StringList::~GpDirectoryCursor_StringList() +{ +} + +bool GpDirectoryCursor_StringList::GetNext(const char *&outFileName) +{ + if (m_index == m_paths.size()) + return false; + outFileName = m_paths[m_index].c_str(); + m_index++; + return true; +} + +void GpDirectoryCursor_StringList::Destroy() +{ + delete this; +} + + +IGpDirectoryCursor *GpFileSystem_Web::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) +{ + if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory)) + return ScanCatalog(*catalog); + + std::string resolvedPrefix; + bool isIDB = false; + if (!ResolvePath(virtualDirectory, paths, numPaths, true, resolvedPrefix, isIDB)) + return nullptr; + + std::string trimmedPrefix = resolvedPrefix.substr(m_prefsPath.size() + 1); + + DIR *d = opendir(m_prefsPath.c_str()); + if (!d) + return nullptr; + + return new GpDirectoryCursor_Web(d, trimmedPrefix); +} + +const GpFileSystem_Web_Resources::FileCatalog *GpFileSystem_Web::GetCatalogForVirtualDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory) +{ + if (virtualDirectory == PortabilityLayer::VirtualDirectories::kApplicationData) + return &GpFileSystem_Web_Resources::ApplicationData::GetCatalog(); + + if (virtualDirectory == PortabilityLayer::VirtualDirectories::kGameData) + return &GpFileSystem_Web_Resources::GameData::GetCatalog(); + + return nullptr; +} + +IGpDirectoryCursor *GpFileSystem_Web::ScanCatalog(const GpFileSystem_Web_Resources::FileCatalog &catalog) +{ + std::vector paths; + for (size_t i = 0; i < catalog.m_numEntries; i++) + paths.push_back(std::string(catalog.m_entries[i].m_fileName)); + + return new GpDirectoryCursor_StringList(paths); +} + +void GpFileSystem_Web::MarkFSStateDirty() +{ + ms_fsStateDirty = true; +} + +void GpFileSystem_Web::SyncDownloadFile(const std::string &filePath, const std::string &prettyName) +{ + DownloadAndDeleteFile(filePath.c_str(), prettyName.c_str()); +} + +void GpFileSystem_Web::FlushFS() +{ + if (ms_fsStateDirty) + { + ms_fsStateDirty = false; + FlushFileSystem(); + } +} + + +#if GP_ASYNCIFY_PARANOID +void GpIOStream::Close() +{ + this->GP_ASYNCIFY_PARANOID_NAMED(Close)(); + GpFileSystem_Web::FlushFS(); +} + +bool IGpFileSystem::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) +{ + return static_cast(this)->DeleteFile(virtualDirectory, path, existed); +} + +#endif + +GpFileSystem_Web GpFileSystem_Web::ms_instance; diff --git a/AerofoilWeb/GpFileSystem_Web.h b/AerofoilWeb/GpFileSystem_Web.h index f0ae197..2885719 100644 --- a/AerofoilWeb/GpFileSystem_Web.h +++ b/AerofoilWeb/GpFileSystem_Web.h @@ -30,6 +30,7 @@ public: void SetDelayCallback(DelayCallback_t delayCallback) override; static void MarkFSStateDirty(); + static void SyncDownloadFile(const std::string &filePath, const std::string &prettyName); static void FlushFS(); static GpFileSystem_Web *GetInstance(); @@ -54,7 +55,7 @@ private: static IGpDirectoryCursor *ScanCatalog(const GpFileSystem_Web_Resources::FileCatalog &catalog); - bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution); + bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution, bool &outIsIDB); DelayCallback_t m_delayCallback; diff --git a/AerofoilWeb/GpMain_SDL_Web.cpp b/AerofoilWeb/GpMain_SDL_Web.cpp index 9ef6412..05c87eb 100644 --- a/AerofoilWeb/GpMain_SDL_Web.cpp +++ b/AerofoilWeb/GpMain_SDL_Web.cpp @@ -1,110 +1,109 @@ -#include -#include "SDL_main.h" - -#include "GpMain.h" -#include "GpAllocator_C.h" -#include "GpAudioDriverFactory.h" -#include "GpDisplayDriverFactory.h" -#include "GpGlobalConfig.h" -#include "GpFileSystem_Web.h" -#include "GpLogDriver_Web.h" -#include "GpFontHandlerFactory.h" -#include "GpInputDriverFactory.h" -#include "GpAppInterface.h" -#include "GpSystemServices_Web.h" -#include "GpVOSEvent.h" -#include "GpX.h" - -#include "IGpFileSystem.h" -#include "IGpThreadEvent.h" -#include "IGpVOSEventQueue.h" - -#include -#include - -GpXGlobals g_gpXGlobals; - -IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties); -IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties); -IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties); - -EM_JS(void, InitFileSystem, (), { +#include +#include "SDL_main.h" + +#include "GpMain.h" +#include "GpAllocator_C.h" +#include "GpAudioDriverFactory.h" +#include "GpDisplayDriverFactory.h" +#include "GpGlobalConfig.h" +#include "GpFileSystem_Web.h" +#include "GpLogDriver_Web.h" +#include "GpFontHandlerFactory.h" +#include "GpInputDriverFactory.h" +#include "GpAppInterface.h" +#include "GpSystemServices_Web.h" +#include "GpVOSEvent.h" +#include "GpX.h" + +#include "IGpFileSystem.h" +#include "IGpThreadEvent.h" +#include "IGpVOSEventQueue.h" + +#include +#include + +GpXGlobals g_gpXGlobals; + +IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties); +IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties); +IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties); + +EM_JS(void, InitFileSystem, (), { Asyncify.handleSleep(wakeUp => { FS.mkdir('/aerofoil'); - //FS.mkdir('/aerofoil_memfs'); - FS.mount(IDBFS, {}, '/aerofoil'); - //FS.mount(MEMFS, {}, '/aerofoil_memfs'); - //FS.mkdir('/aerofoil_memfs/Export'); - FS.syncfs(true, function (err) { - assert(!err); - wakeUp(); - }); - }); -}); - -int main(int argc, char* argv[]) -{ - IGpAllocator *alloc = GpAllocator_C::GetInstance(); - - InitFileSystem(); - - GpLogDriver_Web::Init(); - IGpLogDriver *logger = GpLogDriver_Web::GetInstance(); - -#if GP_ASYNCIFY_PARANOID - SDL_SetHint(SDL_HINT_EMSCRIPTEN_ASYNCIFY, "0"); -#endif - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) - return -1; - - if (logger) - logger->Printf(IGpLogDriver::Category_Information, "Starting filesystem..."); - - GpFileSystem_Web::GetInstance()->Init(); - - GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection(); - - if (logger) - logger->Printf(IGpLogDriver::Category_Information, "Setting up drivers..."); - - drivers->SetDriver(GpFileSystem_Web::GetInstance()); - drivers->SetDriver(GpSystemServices_Web::GetInstance()); - drivers->SetDriver(GpLogDriver_Web::GetInstance()); - drivers->SetDriver(alloc); - - g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2; - - g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_SDL2; - - g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_None; - - EGpInputDriverType inputDrivers[] = - { - EGpInputDriverType_SDL2_Gamepad - }; - - g_gpGlobalConfig.m_inputDriverTypes = inputDrivers; - g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]); - - g_gpGlobalConfig.m_osGlobals = &g_gpXGlobals; - g_gpGlobalConfig.m_logger = logger; - g_gpGlobalConfig.m_systemServices = GpSystemServices_Web::GetInstance(); - g_gpGlobalConfig.m_allocator = alloc; - - GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2); - GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL); - GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_SDL2_Gamepad, GpDriver_CreateInputDriver_SDL2_Gamepad); - - if (logger) - logger->Printf(IGpLogDriver::Category_Information, "SDL environment configured, starting up"); - - int returnCode = GpMain::Run(); - - if (logger) - logger->Printf(IGpLogDriver::Category_Information, "SDL environment exited with code %i, cleaning up", returnCode); - - SDL_Quit(); - - return returnCode; -} + FS.mkdir('/aerofoil_memfs'); + FS.mount(IDBFS, {}, '/aerofoil'); + FS.mount(MEMFS, {}, '/aerofoil_memfs'); + FS.syncfs(true, function (err) { + assert(!err); + wakeUp(); + }); + }); +}); + +int main(int argc, char* argv[]) +{ + IGpAllocator *alloc = GpAllocator_C::GetInstance(); + + InitFileSystem(); + + GpLogDriver_Web::Init(); + IGpLogDriver *logger = GpLogDriver_Web::GetInstance(); + +#if GP_ASYNCIFY_PARANOID + SDL_SetHint(SDL_HINT_EMSCRIPTEN_ASYNCIFY, "0"); +#endif + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) + return -1; + + if (logger) + logger->Printf(IGpLogDriver::Category_Information, "Starting filesystem..."); + + GpFileSystem_Web::GetInstance()->Init(); + + GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection(); + + if (logger) + logger->Printf(IGpLogDriver::Category_Information, "Setting up drivers..."); + + drivers->SetDriver(GpFileSystem_Web::GetInstance()); + drivers->SetDriver(GpSystemServices_Web::GetInstance()); + drivers->SetDriver(GpLogDriver_Web::GetInstance()); + drivers->SetDriver(alloc); + + g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2; + + g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_SDL2; + + g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_None; + + EGpInputDriverType inputDrivers[] = + { + EGpInputDriverType_SDL2_Gamepad + }; + + g_gpGlobalConfig.m_inputDriverTypes = inputDrivers; + g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]); + + g_gpGlobalConfig.m_osGlobals = &g_gpXGlobals; + g_gpGlobalConfig.m_logger = logger; + g_gpGlobalConfig.m_systemServices = GpSystemServices_Web::GetInstance(); + g_gpGlobalConfig.m_allocator = alloc; + + GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2); + GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL); + GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_SDL2_Gamepad, GpDriver_CreateInputDriver_SDL2_Gamepad); + + if (logger) + logger->Printf(IGpLogDriver::Category_Information, "SDL environment configured, starting up"); + + int returnCode = GpMain::Run(); + + if (logger) + logger->Printf(IGpLogDriver::Category_Information, "SDL environment exited with code %i, cleaning up", returnCode); + + SDL_Quit(); + + return returnCode; +} diff --git a/AerofoilWeb/Link.bat b/AerofoilWeb/Link.bat index 39524b1..4309d8a 100644 --- a/AerofoilWeb/Link.bat +++ b/AerofoilWeb/Link.bat @@ -4,5 +4,7 @@ set OUTPUT_DIR=bin rem set DEBUG_LEVEL_FLAGS=-g4 -O0 set DEBUG_LEVEL_FLAGS=-O3 +copy /Y FileSaverDotJS\dist\FileSaver.js bin\FileSaver.js + set FLAGS=-flto %DEBUG_LEVEL_FLAGS% -s USE_SDL=2 -s USE_ZLIB=1 -s ASYNCIFY -s ASYNCIFY_IGNORE_INDIRECT -s INITIAL_MEMORY=33554432 -s ASYNCIFY_ADVISE -lidbfs.js -s ASYNCIFY_IMPORTS=['InitFileSystem','FlushFileSystem'] --shell-file shell_minimal.html emcc obj/AerofoilWeb_Combined.o obj/AerofoilWeb_Resources.o obj/GpShell_Combined.o obj/AerofoilSDL_Combined.o obj/AerofoilPortable_Combined.o obj/GpApp_Combined.o obj/PortabilityLayer_Combined.o obj/MacRomanConversion.o -o %OUTPUT_DIR%/aerofoil.html %FLAGS% diff --git a/AerofoilWeb/shell_minimal.html b/AerofoilWeb/shell_minimal.html index d7b8edb..0cf894d 100644 --- a/AerofoilWeb/shell_minimal.html +++ b/AerofoilWeb/shell_minimal.html @@ -3,7 +3,7 @@ - Aerofoil Web Pre-Release + Aerofoil