diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml index 7d3006b2c..4b7c73203 100644 --- a/.github/workflows/build_mac.yml +++ b/.github/workflows/build_mac.yml @@ -1,5 +1,12 @@ name: Build latest (macOS 64 bit) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - main + - master + workflow_dispatch: + concurrency: group: ${{ github.ref }}-mac64 @@ -7,7 +14,6 @@ concurrency: jobs: build: - if: github.ref_name == github.event.repository.default_branch runs-on: macOS-latest steps: - uses: actions/checkout@v4 @@ -51,4 +57,4 @@ jobs: if: ${{ always() && steps.compile.outcome == 'success' }} with: SOURCE_FILE: 'src/cc-mac-arm64' - DEST_NAME: 'ClassiCube-mac-ARM64' \ No newline at end of file + DEST_NAME: 'ClassiCube-mac-ARM64' diff --git a/.github/workflows/build_ps1.yml b/.github/workflows/build_ps1.yml index 2ab3f1b4e..674f43eac 100644 --- a/.github/workflows/build_ps1.yml +++ b/.github/workflows/build_ps1.yml @@ -1,5 +1,11 @@ name: Build latest (PS1) -on: [push] +# trigger via either push to selected branches or on manual run +on: + push: + branches: + - main + - master + workflow_dispatch: concurrency: group: ${{ github.ref }}-ps1 @@ -7,7 +13,6 @@ concurrency: jobs: build-PS1: - if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: ghcr.io/classicube/minimal-psn00b:latest @@ -54,10 +59,3 @@ jobs: with: SOURCE_FILE: 'misc/ps1/build/template.cue' DEST_NAME: 'ClassiCube-PS1.cue' - - - - uses: ./.github/actions/notify_success - if: ${{ always() && steps.compile.outcome == 'success' }} - with: - DESTINATION_URL: '${{ secrets.NOTIFY_URL }}' - WORKFLOW_NAME: 'ps1' diff --git a/misc/macclassic/68APPL.r b/misc/macclassic/68APPL.r index de74bd0b0..2a78e8d48 100644 --- a/misc/macclassic/68APPL.r +++ b/misc/macclassic/68APPL.r @@ -18,6 +18,6 @@ resource 'SIZE' (-1) { reserved, reserved, reserved, - 8192 * 1024, + 3072 * 1024, 8192 * 1024 }; diff --git a/misc/macclassic/Makefile_68k b/misc/macclassic/Makefile_68k index 56b774f0c..a960a2f54 100644 --- a/misc/macclassic/Makefile_68k +++ b/misc/macclassic/Makefile_68k @@ -4,6 +4,8 @@ RETRO68=../Retro68-build/toolchain PREFIX=$(RETRO68)/m68k-apple-macos CC=$(RETRO68)/bin/m68k-apple-macos-gcc CXX=$(RETRO68)/bin/m68k-apple-macos-g++ +CFLAGS=-O1 -fno-math-errno + REZ=$(RETRO68)/bin/Rez LDFLAGS=-lRetroConsole diff --git a/misc/macclassic/Makefile_ppc b/misc/macclassic/Makefile_ppc index 4eee32cf8..bfc3f5d47 100644 --- a/misc/macclassic/Makefile_ppc +++ b/misc/macclassic/Makefile_ppc @@ -4,6 +4,8 @@ RETRO68=../Retro68-build/toolchain PREFIX=$(RETRO68)/powerpc-apple-macos CC=$(RETRO68)/bin/powerpc-apple-macos-gcc CXX=$(RETRO68)/bin/powerpc-apple-macos-g++ +CFLAGS=-O1 -fno-math-errno + REZ=$(RETRO68)/bin/Rez MakePEF=$(RETRO68)/bin/MakePEF diff --git a/misc/macclassic/ppcAPPL.r b/misc/macclassic/ppcAPPL.r index 5d0c59166..232824164 100644 --- a/misc/macclassic/ppcAPPL.r +++ b/misc/macclassic/ppcAPPL.r @@ -27,6 +27,6 @@ resource 'SIZE' (-1) { reserved, reserved, reserved, - 8192 * 1024, + 3072 * 1024, 8192 * 1024 }; diff --git a/src/Core.h b/src/Core.h index 6c3b79455..dfa79461a 100644 --- a/src/Core.h +++ b/src/Core.h @@ -220,7 +220,9 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_MACCLASSIC #define CC_BUILD_HTTPCLIENT #define CC_BUILD_OPENAL + #define CC_BUILD_LOWMEM #define CC_BUILD_COOPTHREADED + #undef CC_BUILD_FREETYPE #elif defined __sun__ #define CC_BUILD_SOLARIS #define CC_BUILD_POSIX diff --git a/src/Graphics_SoftGPU.c b/src/Graphics_SoftGPU.c index 8226a4007..58ed6e31b 100644 --- a/src/Graphics_SoftGPU.c +++ b/src/Graphics_SoftGPU.c @@ -5,10 +5,10 @@ #include "Window.h" static cc_bool faceCulling; -static int width, height; +static int fb_width, fb_height; static struct Bitmap fb_bmp; static float vp_hwidth, vp_hheight; -static int sc_maxX, sc_maxY; +static int fb_maxX, fb_maxY; static PackedCol* colorBuffer; static PackedCol clearColor; @@ -63,6 +63,7 @@ typedef struct CCTexture { static CCTexture* curTexture; static BitmapCol* curTexPixels; static int curTexWidth, curTexHeight; +static int texWidthMask, texHeightMask; void Gfx_BindTexture(GfxResourceID texId) { if (!texId) texId = white_square; @@ -72,6 +73,9 @@ void Gfx_BindTexture(GfxResourceID texId) { curTexPixels = tex->pixels; curTexWidth = tex->width; curTexHeight = tex->height; + + texWidthMask = (1 << Math_ilog2(tex->width)) - 1; + texHeightMask = (1 << Math_ilog2(tex->height)) - 1; } void Gfx_DeleteTexture(GfxResourceID* texId) { @@ -123,7 +127,7 @@ static void SetAlphaBlend(cc_bool enabled) { void Gfx_SetAlphaArgBlend(cc_bool enabled) { } void Gfx_ClearBuffers(GfxBuffers buffers) { - int i, size = width * height; + int i, size = fb_width * fb_height; if (buffers & GFX_BUFFER_COLOR) { for (i = 0; i < size; i++) colorBuffer[i] = clearColor; @@ -275,35 +279,39 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f /*########################################################################################################################* *---------------------------------------------------------Rendering-------------------------------------------------------* *#########################################################################################################################*/ -typedef struct Vector4 { float x, y, z, w; } Vector4; typedef struct Vector3 { float x, y, z; } Vector3; typedef struct Vector2 { float x, y; } Vector2; +typedef struct Vertex_ { + float x, y, z, w; + float u, v; + PackedCol c; +} Vertex; -static void TransformVertex(int index, Vector4* frag, Vector2* uv, PackedCol* color) { +static void TransformVertex(int index, Vertex* vertex) { // TODO: avoid the multiply, just add down in DrawTriangles char* ptr = (char*)gfx_vertices + index * gfx_stride; Vector3* pos = (Vector3*)ptr; - Vector4 coord; + struct Vec4 coord; coord.x = pos->x * mvp.row1.x + pos->y * mvp.row2.x + pos->z * mvp.row3.x + mvp.row4.x; coord.y = pos->x * mvp.row1.y + pos->y * mvp.row2.y + pos->z * mvp.row3.y + mvp.row4.y; coord.z = pos->x * mvp.row1.z + pos->y * mvp.row2.z + pos->z * mvp.row3.z + mvp.row4.z; coord.w = pos->x * mvp.row1.w + pos->y * mvp.row2.w + pos->z * mvp.row3.w + mvp.row4.w; float invW = 1.0f / coord.w; - frag->x = vp_hwidth * (1 + coord.x * invW); - frag->y = vp_hheight * (1 - coord.y * invW); - frag->z = coord.z * invW; - frag->w = invW; + vertex->x = vp_hwidth * (1 + coord.x * invW); + vertex->y = vp_hheight * (1 - coord.y * invW); + vertex->z = coord.z * invW; + vertex->w = invW; if (gfx_format != VERTEX_FORMAT_TEXTURED) { struct VertexColoured* v = (struct VertexColoured*)ptr; - *color = v->Col; + vertex->c = v->Col; } else { struct VertexTextured* v = (struct VertexTextured*)ptr; - *color = v->Col; - uv->x = (v->U + texOffsetX) * invW; - uv->y = (v->V + texOffsetY) * invW; + vertex->u = (v->U + texOffsetX) * invW; + vertex->v = (v->V + texOffsetY) * invW; + vertex->c = v->Col; } } @@ -319,11 +327,10 @@ static int MultiplyColours(PackedCol vColor, BitmapCol tColor) { return PackedCol_Make(r, g, b, a); } -static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, - Vector2 uv1, Vector2 uv2, Vector2 uv3, PackedCol color) { - int x1 = (int)frag1.x, y1 = (int)frag1.y; - int x2 = (int)frag2.x, y2 = (int)frag2.y; - int x3 = (int)frag3.x, y3 = (int)frag3.y; +static void DrawTriangle(Vertex* frag1, Vertex* frag2, Vertex* frag3) { + int x1 = (int)frag1->x, y1 = (int)frag1->y; + int x2 = (int)frag2->x, y2 = (int)frag2->y; + int x3 = (int)frag3->x, y3 = (int)frag3->y; int minX = min(x1, min(x2, x3)); int minY = min(y1, min(y2, y3)); int maxX = max(x1, max(x2, x3)); @@ -337,18 +344,24 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, } // Reject triangles completely outside - if (minX < 0 && maxX < 0 || minX >= width && maxX >= width ) return; - if (minY < 0 && maxY < 0 || minY >= height && maxY >= height) return; + if ((minX < 0 && maxX < 0) || (minX > fb_maxX && maxX > fb_maxX)) return; + if ((minY < 0 && maxY < 0) || (minY > fb_maxY && maxY > fb_maxY)) return; // Perform scissoring - minX = max(minX, 0); maxX = min(maxX, sc_maxX); - minY = max(minY, 0); maxY = min(maxY, sc_maxY); + minX = max(minX, 0); maxX = min(maxX, fb_maxX); + minY = max(minY, 0); maxY = min(maxY, fb_maxY); // NOTE: W in frag variables below is actually 1/W float factor = 1.0f / ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3)); + float w1 = frag1->w, w2 = frag2->w, w3 = frag3->w; // TODO proper clipping - if (frag1.w <= 0 || frag2.w <= 0 || frag3.w <= 0) return; + if (w1 <= 0 || w2 <= 0 || w3 <= 0) return; + + float z1 = frag1->z, z2 = frag2->z, z3 = frag3->z; + float u1 = frag1->u, u2 = frag2->u, u3 = frag3->u; + float v1 = frag1->v, v2 = frag2->v, v3 = frag3->v; + PackedCol color = frag1->c; for (int y = minY; y <= maxY; y++) { float yy = y + 0.5f; @@ -362,9 +375,9 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, float ic2 = 1.0f - ic0 - ic1; if (ic2 < 0 || ic2 > 1) continue; - int index = y * width + x; - float w = 1 / (ic0 * frag1.w + ic1 * frag2.w + ic2 * frag3.w); - float z = (ic0 * frag1.z + ic1 * frag2.z + ic2 * frag3.z) * w; + int index = y * fb_width + x; + float w = 1 / (ic0 * w1 + ic1 * w2 + ic2 * w3); + float z = (ic0 * z1 + ic1 * z2 + ic2 * z3) * w; if (depthTest && (z < 0 || z > depthBuffer[index])) continue; if (!colWrite) { @@ -374,10 +387,10 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, PackedCol fragColor = color; if (gfx_format == VERTEX_FORMAT_TEXTURED) { - float u = (ic0 * uv1.x + ic1 * uv2.x + ic2 * uv3.x) * w; - float v = (ic0 * uv1.y + ic1 * uv2.y + ic2 * uv3.y) * w; - int texX = ((int)(Math_AbsF(u - Math_Floor(u)) * curTexWidth )) % curTexWidth; // TODO avoid slow % - int texY = ((int)(Math_AbsF(v - Math_Floor(v)) * curTexHeight)) % curTexHeight; + float u = (ic0 * u1 + ic1 * u2 + ic2 * u3) * w; + float v = (ic0 * v1 + ic1 * v2 + ic2 * v3) * w; + int texX = ((int)(Math_AbsF(u - Math_Floor(u)) * curTexWidth )) & texWidthMask; + int texY = ((int)(Math_AbsF(v - Math_Floor(v)) * curTexHeight)) & texHeightMask; int texIndex = texY * curTexWidth + texX; fragColor = MultiplyColours(fragColor, curTexPixels[texIndex]); @@ -407,24 +420,19 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, } void DrawQuads(int startVertex, int verticesCount) { - Vector4 frag[4]; - Vector2 uv[4]; - PackedCol color[4]; + Vertex vertices[4]; int j = startVertex; // 4 vertices = 1 quad = 2 triangles for (int i = 0; i < verticesCount / 4; i++, j += 4) { - TransformVertex(j + 0, &frag[0], &uv[0], &color[0]); - TransformVertex(j + 1, &frag[1], &uv[1], &color[1]); - TransformVertex(j + 2, &frag[2], &uv[2], &color[2]); - TransformVertex(j + 3, &frag[3], &uv[3], &color[3]); + TransformVertex(j + 0, &vertices[0]); + TransformVertex(j + 1, &vertices[1]); + TransformVertex(j + 2, &vertices[2]); + TransformVertex(j + 3, &vertices[3]); - DrawTriangle(frag[0], frag[1], frag[2], - uv[0], uv[1], uv[2], color[0]); - - DrawTriangle(frag[2], frag[3], frag[0], - uv[2], uv[3], uv[0], color[2]); + DrawTriangle(&vertices[0], &vertices[1], &vertices[2]); + DrawTriangle(&vertices[2], &vertices[3], &vertices[0]); } } @@ -453,7 +461,7 @@ void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { *#########################################################################################################################*/ cc_result Gfx_TakeScreenshot(struct Stream* output) { struct Bitmap bmp; - Bitmap_Init(bmp, width, height, colorBuffer); + Bitmap_Init(bmp, fb_width, fb_height, colorBuffer); return Png_Encode(&bmp, output, NULL, false, NULL); } @@ -464,7 +472,7 @@ cc_bool Gfx_WarnIfNecessary(void) { void Gfx_BeginFrame(void) { } void Gfx_EndFrame(void) { - Rect2D r = { 0, 0, width, height }; + Rect2D r = { 0, 0, fb_width, fb_height }; Window_DrawFramebuffer(r, &fb_bmp); } @@ -476,17 +484,17 @@ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { void Gfx_OnWindowResize(void) { if (depthBuffer) DestroyBuffers(); - fb_bmp.width = width = Game.Width; - fb_bmp.height = height = Game.Height; + fb_bmp.width = fb_width = Game.Width; + fb_bmp.height = fb_height = Game.Height; - vp_hwidth = width / 2.0f; - vp_hheight = height / 2.0f; + vp_hwidth = fb_width / 2.0f; + vp_hheight = fb_height / 2.0f; - sc_maxX = width - 1; - sc_maxY = height - 1; + fb_maxX = fb_width - 1; + fb_maxY = fb_height - 1; Window_AllocFramebuffer(&fb_bmp); - depthBuffer = Mem_Alloc(width * height, 4, "depth buffer"); + depthBuffer = Mem_Alloc(fb_width * fb_height, 4, "depth buffer"); colorBuffer = fb_bmp.scan0; } diff --git a/src/Platform_MacClassic.c b/src/Platform_MacClassic.c index 9f50212a4..91f6b33a9 100644 --- a/src/Platform_MacClassic.c +++ b/src/Platform_MacClassic.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include const cc_result ReturnCode_FileShareViolation = 1000000000; /* TODO: not used apparently */ const cc_result ReturnCode_FileNotFound = ENOENT; @@ -26,15 +28,38 @@ const cc_result ReturnCode_SocketInProgess = EINPROGRESS; const cc_result ReturnCode_SocketWouldBlock = EWOULDBLOCK; const cc_result ReturnCode_DirectoryExists = EEXIST; -const char* Platform_AppNameSuffix = " MAC68k"; +#if TARGET_CPU_68K +const char* Platform_AppNameSuffix = " MAC 68k"; +#else +const char* Platform_AppNameSuffix = " MAC PPC"; +#endif cc_bool Platform_SingleProcess = true; +static long sysVersion; /*########################################################################################################################* *---------------------------------------------------Imported headers------------------------------------------------------* *#########################################################################################################################*/ +// On 68k these are implemented using direct 68k opcodes +// On PPC these are implemented using function calls +#if TARGET_CPU_68K + #define MAC_SYSAPI(_type) static _type + #define MAC_ONEWORDINLINE(w1) = w1 + #define MAC_TWOWORDINLINE(w1,w2) = {w1, w2} + #define MAC_THREEWORDINLINE(w1,w2,w3) = {w1, w2, w3} + #define MAC_FOURWORDINLINE(w1,w2,w3,w4) = {w1, w2, w3, w4} +#else + #define MAC_SYSAPI(_type) extern pascal _type + #define MAC_ONEWORDINLINE(w1) + #define MAC_TWOWORDINLINE(w1,w2) + #define MAC_THREEWORDINLINE(w1,w2,w3) + #define MAC_FOURWORDINLINE(w1,w2,w3,w4) +#endif +typedef unsigned long MAC_FourCharCode; + +// ==================================== IMPORTS FROM TIMER.H ==================================== // Availability: in InterfaceLib 7.1 and later -static void Microseconds(UnsignedWide* microTickCount) FOURWORDINLINE(0xA193, 0x225F, 0x22C8, 0x2280); +MAC_SYSAPI(void) Microseconds(UnsignedWide* microTickCount) MAC_FOURWORDINLINE(0xA193, 0x225F, 0x22C8, 0x2280); /*########################################################################################################################* *---------------------------------------------------------Memory----------------------------------------------------------* @@ -88,25 +113,21 @@ void Platform_Log(const char* msg, int len) { // classic macOS uses an epoch of 1904 #define EPOCH_ADJUSTMENT 2082866400UL -static void gettod(struct timeval *tp) { +static time_t gettod(void) { unsigned long secs; GetDateTime(&secs); - - tp->tv_sec = secs - EPOCH_ADJUSTMENT; - tp->tv_usec = 0; + return secs - EPOCH_ADJUSTMENT; } TimeMS DateTime_CurrentUTC(void) { - struct timeval cur; - gettod(&cur); - return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS; + time_t secs = gettod(); + return (cc_uint64)secs + UNIX_EPOCH_SECONDS; } void DateTime_CurrentLocal(struct DateTime* t) { - struct timeval cur; struct tm loc_time; - gettod(&cur); - localtime_r(&cur.tv_sec, &loc_time); + time_t secs = gettod(); + localtime_r(&secs, &loc_time); t->year = loc_time.tm_year + 1900; t->month = loc_time.tm_mon + 1; @@ -120,13 +141,19 @@ void DateTime_CurrentLocal(struct DateTime* t) { /*########################################################################################################################* *--------------------------------------------------------Stopwatch--------------------------------------------------------* *#########################################################################################################################*/ -#define NS_PER_SEC 1000000000ULL +#define MS_PER_SEC 1000000ULL cc_uint64 Stopwatch_Measure(void) { - //return TickCount(); + if (sysVersion < 0x7000) { + // 60 ticks a second + cc_uint64 count = TickCount(); + return count * MS_PER_SEC / 60; + } + UnsignedWide count; Microseconds(&count); return (cc_uint64)count.lo | ((cc_uint64)count.hi << 32); + //return UnsignedWideToUInt64(count); } cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) { @@ -141,7 +168,7 @@ cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) { void Directory_GetCachePath(cc_string* path) { } cc_result Directory_Create(const cc_string* path) { - return ERR_NOT_SUPPORTED; + return 0; // TODO } int File_Exists(const cc_string* path) { @@ -153,7 +180,7 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall } cc_result File_Open(cc_file* file, const cc_string* path) { - return ERR_NOT_SUPPORTED; + return ReturnCode_FileNotFound; } cc_result File_Create(cc_file* file, const cc_string* path) { @@ -204,6 +231,9 @@ cc_result File_Length(cc_file file, cc_uint32* len) { *#########################################################################################################################*/ void Thread_Sleep(cc_uint32 milliseconds) { // TODO Delay API + long delay = milliseconds * 100; // TODO wrong + long final; + Delay(delay, &final); } void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char* name) { @@ -407,6 +437,8 @@ cc_bool Platform_DescribeError(cc_result res, cc_string* dst) { } void Platform_Init(void) { + Gestalt(gestaltSystemVersion, &sysVersion); + Platform_Log1("Running on Mac OS %h", &sysVersion); Platform_LoadSysFonts(); } diff --git a/src/Window_MacClassic.c b/src/Window_MacClassic.c index 01a4e208c..bb77fdf2a 100644 --- a/src/Window_MacClassic.c +++ b/src/Window_MacClassic.c @@ -15,24 +15,57 @@ #include #include #include +#include +#include static WindowPtr win; +static cc_bool hasColorQD; /*########################################################################################################################* *---------------------------------------------------Imported headers------------------------------------------------------* *#########################################################################################################################*/ - -// Availability: in InterfaceLib 7.1 and later -static long GetScrap(Handle dst, FourCharCode type, SInt32* offset) ONEWORDINLINE(0xA9FD); -// Availability: in InterfaceLib 7.1 and later -static OSStatus PutScrap(SInt32 srcLen, FourCharCode type, const void* src) ONEWORDINLINE(0xA9FE); +// On 68k these are implemented using direct 68k opcodes +// On PPC these are implemented using function calls +#if TARGET_CPU_68K + #define MAC_SYSAPI(_type) static _type + #define MAC_ONEWORDINLINE(w1) = w1 + #define MAC_TWOWORDINLINE(w1,w2) = {w1, w2} + #define MAC_THREEWORDINLINE(w1,w2,w3) = {w1, w2, w3} + #define MAC_FOURWORDINLINE(w1,w2,w3,w4) = {w1, w2, w3, w4} +#else + #define MAC_SYSAPI(_type) extern pascal _type + #define MAC_ONEWORDINLINE(w1) + #define MAC_TWOWORDINLINE(w1,w2) + #define MAC_THREEWORDINLINE(w1,w2,w3) + #define MAC_FOURWORDINLINE(w1,w2,w3,w4) +#endif +typedef unsigned long MAC_FourCharCode; /*########################################################################################################################* *--------------------------------------------------Public implementation--------------------------------------------------* *#########################################################################################################################*/ -void Window_PreInit(void) { } -void Window_Init(void) { +static const cc_uint8 key_map[8 * 16] = { +/* 0x00 */ 'A', 'S', 'D', 'F', 'H', 'G', 'Z', 'X', +/* 0x08 */ 'C', 'V', 0, 'B', 'Q', 'W', 'E', 'R', +/* 0x10 */ 'Y', 'T', '1', '2', '3', '4', '6', '5', +/* 0x18 */ CCKEY_EQUALS, '9', '7', CCKEY_MINUS, '8', '0', CCKEY_RBRACKET, 'O', +/* 0x20 */ 'U', CCKEY_LBRACKET, 'I', 'P', CCKEY_ENTER, 'L', 'J', CCKEY_QUOTE, +/* 0x28 */ 'K', CCKEY_SEMICOLON, CCKEY_BACKSLASH, CCKEY_COMMA, CCKEY_SLASH, 'N', 'M', CCKEY_PERIOD, +/* 0x30 */ CCKEY_TAB, CCKEY_SPACE, CCKEY_TILDE, CCKEY_BACKSPACE, 0, CCKEY_ESCAPE, 0, CCKEY_LWIN, +/* 0x38 */ CCKEY_LSHIFT, CCKEY_CAPSLOCK, CCKEY_LALT, CCKEY_LCTRL, 0, 0, 0, 0, +/* 0x40 */ 0, CCKEY_KP_DECIMAL, 0, CCKEY_KP_MULTIPLY, 0, CCKEY_KP_PLUS, 0, CCKEY_NUMLOCK, +/* 0x48 */ CCKEY_VOLUME_UP, CCKEY_VOLUME_DOWN, CCKEY_VOLUME_MUTE, CCKEY_KP_DIVIDE, CCKEY_KP_ENTER, 0, CCKEY_KP_MINUS, 0, +/* 0x50 */ 0, CCKEY_KP_ENTER, CCKEY_KP0, CCKEY_KP1, CCKEY_KP2, CCKEY_KP3, CCKEY_KP4, CCKEY_KP5, +/* 0x58 */ CCKEY_KP6, CCKEY_KP7, 0, CCKEY_KP8, CCKEY_KP9, 'N', 'M', CCKEY_PERIOD, +/* 0x60 */ CCKEY_F5, CCKEY_F6, CCKEY_F7, CCKEY_F3, CCKEY_F8, CCKEY_F9, 0, CCKEY_F11, +/* 0x68 */ 0, CCKEY_F13, 0, CCKEY_F14, 0, CCKEY_F10, 0, CCKEY_F12, +/* 0x70 */ 'U', CCKEY_F15, CCKEY_INSERT, CCKEY_HOME, CCKEY_PAGEUP, CCKEY_DELETE, CCKEY_F4, CCKEY_END, +/* 0x78 */ CCKEY_F2, CCKEY_PAGEDOWN, CCKEY_F1, CCKEY_LEFT, CCKEY_RIGHT, CCKEY_DOWN, CCKEY_UP, 0, +}; +static int MapNativeKey(UInt32 key) { return key < Array_Elems(key_map) ? key_map[key] : 0; } + +void Window_PreInit(void) { InitGraf(&qd.thePort); InitFonts(); InitWindows(); @@ -45,6 +78,13 @@ void Window_Init(void) { EventAvail(everyEvent, &event); FlushEvents(everyEvent, 0); + long tmpLong = 0; + Gestalt(gestaltQuickdrawVersion, &tmpLong); + hasColorQD = tmpLong >= gestalt32BitQD; + if (!hasColorQD) Platform_LogConst("RUNNING IN SLOW MODE"); +} + +void Window_Init(void) { Rect r = qd.screenBits.bounds; DisplayInfo.x = r.left; DisplayInfo.y = r.top; @@ -64,7 +104,11 @@ static void DoCreateWindow(int width, int height) { r.top += 40; InsetRect(&r, 100, 100); - win = NewWindow(NULL, &r, "\pClassiCube", true, 0, (WindowPtr)-1, false, 0); + if (hasColorQD) { + win = NewCWindow(NULL, &r, "\pClassiCube", true, 0, (WindowPtr)-1, false, 0); + } else { + win = NewWindow( NULL, &r, "\pClassiCube", true, 0, (WindowPtr)-1, false, 0); + } SetPort(win); r = win->portRect; @@ -212,17 +256,7 @@ void Window_ProcessEvents(float delta) { } } -short isPressed(unsigned short k) { - unsigned char km[16]; - - GetKeys((long *)km); - return ((km[k>>3] >> (k&7) ) &1); -} - void Window_ProcessGamepads(float delta) { - Gamepad_SetButton(0, CCPAD_UP, isPressed(0x0D)); - Gamepad_SetButton(0, CCPAD_DOWN, isPressed(0x01)); - Gamepad_SetButton(0, CCPAD_START, isPressed(0x24)); } static void Cursor_GetRawPos(int* x, int* y) { @@ -233,6 +267,7 @@ static void Cursor_GetRawPos(int* x, int* y) { void Cursor_SetPosition(int x, int y) { // TODO } + static void Cursor_DoSetVisible(cc_bool visible) { if (visible) { ShowCursor(); @@ -243,54 +278,113 @@ static void Cursor_DoSetVisible(cc_bool visible) { static void ShowDialogCore(const char* title, const char* msg) { // TODO + for (int i = 0; i < 20; i++) + { + Platform_LogConst(title); + Platform_LogConst(msg); + } } cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { // TODO - return 1; + return ERR_NOT_SUPPORTED; } cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { // TODO - return 1; + return ERR_NOT_SUPPORTED; } +static GWorldPtr fb_world; +static PixMapHandle fb_pixmap; +static int fb_stride; +static char* fb_bits; + void Window_AllocFramebuffer(struct Bitmap* bmp) { bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); + if (!hasColorQD) return; + + // TODO bmp->scan0 should be the fb_world + QDErr err = NewGWorld(&fb_world, 32, &win->portRect, 0, 0, 0); + if (err != noErr) Logger_Abort2(err, "Failed to allocate GWorld"); + + fb_pixmap = GetGWorldPixMap(fb_world); + if (!fb_pixmap) Logger_Abort("Failed to allocate pixmap"); + + LockPixels(fb_pixmap); + fb_stride = (*fb_pixmap)->rowBytes & 0x3FFF; + fb_bits = (char*)GetPixBaseAddr(fb_pixmap); } -void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { - GrafPtr thePort = (CGrafPtr)win; - SetPort(win); - int ww = bmp->width; - int hh = bmp->height; +static void DrawFramebufferFast(Rect2D r, struct Bitmap* bmp) { + GrafPtr thePort = (GrafPtr)win; + const BitMap* memBits; + const BitMap* winBits; - // Iterate through each pixel - for (int y = r.y; y < r.y + r.height; ++y) { + for (int y = r.y; y < r.y + r.height; y++) + { + BitmapCol* src = Bitmap_GetRow(bmp, y); + uint32_t* dst = (uint32_t*)(fb_bits + fb_stride * y); + + for (int x = r.x; x < r.x + r.width; x++) + { + dst[x] = src[x]; + } + } + + memBits = &((GrafPtr)fb_world)->portBits; + winBits = &thePort->portBits; + + Rect update; + update.left = r.x; + update.right = r.x + r.width; + update.top = r.y; + update.bottom = r.y + r.height; + + CopyBits(memBits, winBits, &update, &update, srcCopy, nil); +} + +static void DrawFramebufferSlow(Rect2D r, struct Bitmap* bmp) { + for (int y = r.y; y < r.y + r.height; ++y) + { BitmapCol* row = Bitmap_GetRow(bmp, y); - for (int x = r.x; x < r.x + r.width; ++x) { - + for (int x = r.x; x < r.x + r.width; ++x) + { // TODO optimise BitmapCol col = row[x]; cc_uint8 R = BitmapCol_R(col); cc_uint8 G = BitmapCol_G(col); cc_uint8 B = BitmapCol_B(col); - // Set the pixel color in the window - RGBColor pixelColor; - pixelColor.red = R * 256; - pixelColor.green = G * 256; - pixelColor.blue = B * 256; + RGBColor pixelColor; + pixelColor.red = R << 8; + pixelColor.green = G << 8; + pixelColor.blue = B << 8; + RGBForeColor(&pixelColor); MoveTo(x, y); Line(0, 0); -//SetCPixel(x, y, &pixelColor); + //SetCPixel(x, y, &pixelColor); } } } +void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { + SetPort(win); + + if (hasColorQD) { + DrawFramebufferFast(r, bmp); + } else { + DrawFramebufferSlow(r, bmp); + } +} + void Window_FreeFramebuffer(struct Bitmap* bmp) { Mem_Free(bmp->scan0); + if (!hasColorQD) return; + + UnlockPixels(fb_pixmap); + DisposeGWorld(fb_world); } void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { }