Merge pull request #1208 from ClassiCube/MacClassic

Optimise performance for Mac OS classic a bit
This commit is contained in:
UnknownShadow200 2024-06-04 17:46:27 +10:00 committed by GitHub
commit 7af729335e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 261 additions and 117 deletions

View File

@ -1,5 +1,12 @@
name: Build latest (macOS 64 bit) 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: concurrency:
group: ${{ github.ref }}-mac64 group: ${{ github.ref }}-mac64
@ -7,7 +14,6 @@ concurrency:
jobs: jobs:
build: build:
if: github.ref_name == github.event.repository.default_branch
runs-on: macOS-latest runs-on: macOS-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -51,4 +57,4 @@ jobs:
if: ${{ always() && steps.compile.outcome == 'success' }} if: ${{ always() && steps.compile.outcome == 'success' }}
with: with:
SOURCE_FILE: 'src/cc-mac-arm64' SOURCE_FILE: 'src/cc-mac-arm64'
DEST_NAME: 'ClassiCube-mac-ARM64' DEST_NAME: 'ClassiCube-mac-ARM64'

View File

@ -1,5 +1,11 @@
name: Build latest (PS1) 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: concurrency:
group: ${{ github.ref }}-ps1 group: ${{ github.ref }}-ps1
@ -7,7 +13,6 @@ concurrency:
jobs: jobs:
build-PS1: build-PS1:
if: github.ref_name == github.event.repository.default_branch
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/classicube/minimal-psn00b:latest image: ghcr.io/classicube/minimal-psn00b:latest
@ -54,10 +59,3 @@ jobs:
with: with:
SOURCE_FILE: 'misc/ps1/build/template.cue' SOURCE_FILE: 'misc/ps1/build/template.cue'
DEST_NAME: 'ClassiCube-PS1.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'

View File

@ -18,6 +18,6 @@ resource 'SIZE' (-1) {
reserved, reserved,
reserved, reserved,
reserved, reserved,
8192 * 1024, 3072 * 1024,
8192 * 1024 8192 * 1024
}; };

View File

@ -4,6 +4,8 @@ RETRO68=../Retro68-build/toolchain
PREFIX=$(RETRO68)/m68k-apple-macos PREFIX=$(RETRO68)/m68k-apple-macos
CC=$(RETRO68)/bin/m68k-apple-macos-gcc CC=$(RETRO68)/bin/m68k-apple-macos-gcc
CXX=$(RETRO68)/bin/m68k-apple-macos-g++ CXX=$(RETRO68)/bin/m68k-apple-macos-g++
CFLAGS=-O1 -fno-math-errno
REZ=$(RETRO68)/bin/Rez REZ=$(RETRO68)/bin/Rez
LDFLAGS=-lRetroConsole LDFLAGS=-lRetroConsole

View File

@ -4,6 +4,8 @@ RETRO68=../Retro68-build/toolchain
PREFIX=$(RETRO68)/powerpc-apple-macos PREFIX=$(RETRO68)/powerpc-apple-macos
CC=$(RETRO68)/bin/powerpc-apple-macos-gcc CC=$(RETRO68)/bin/powerpc-apple-macos-gcc
CXX=$(RETRO68)/bin/powerpc-apple-macos-g++ CXX=$(RETRO68)/bin/powerpc-apple-macos-g++
CFLAGS=-O1 -fno-math-errno
REZ=$(RETRO68)/bin/Rez REZ=$(RETRO68)/bin/Rez
MakePEF=$(RETRO68)/bin/MakePEF MakePEF=$(RETRO68)/bin/MakePEF

View File

@ -27,6 +27,6 @@ resource 'SIZE' (-1) {
reserved, reserved,
reserved, reserved,
reserved, reserved,
8192 * 1024, 3072 * 1024,
8192 * 1024 8192 * 1024
}; };

View File

@ -220,7 +220,9 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_MACCLASSIC #define CC_BUILD_MACCLASSIC
#define CC_BUILD_HTTPCLIENT #define CC_BUILD_HTTPCLIENT
#define CC_BUILD_OPENAL #define CC_BUILD_OPENAL
#define CC_BUILD_LOWMEM
#define CC_BUILD_COOPTHREADED #define CC_BUILD_COOPTHREADED
#undef CC_BUILD_FREETYPE
#elif defined __sun__ #elif defined __sun__
#define CC_BUILD_SOLARIS #define CC_BUILD_SOLARIS
#define CC_BUILD_POSIX #define CC_BUILD_POSIX

View File

@ -5,10 +5,10 @@
#include "Window.h" #include "Window.h"
static cc_bool faceCulling; static cc_bool faceCulling;
static int width, height; static int fb_width, fb_height;
static struct Bitmap fb_bmp; static struct Bitmap fb_bmp;
static float vp_hwidth, vp_hheight; static float vp_hwidth, vp_hheight;
static int sc_maxX, sc_maxY; static int fb_maxX, fb_maxY;
static PackedCol* colorBuffer; static PackedCol* colorBuffer;
static PackedCol clearColor; static PackedCol clearColor;
@ -63,6 +63,7 @@ typedef struct CCTexture {
static CCTexture* curTexture; static CCTexture* curTexture;
static BitmapCol* curTexPixels; static BitmapCol* curTexPixels;
static int curTexWidth, curTexHeight; static int curTexWidth, curTexHeight;
static int texWidthMask, texHeightMask;
void Gfx_BindTexture(GfxResourceID texId) { void Gfx_BindTexture(GfxResourceID texId) {
if (!texId) texId = white_square; if (!texId) texId = white_square;
@ -72,6 +73,9 @@ void Gfx_BindTexture(GfxResourceID texId) {
curTexPixels = tex->pixels; curTexPixels = tex->pixels;
curTexWidth = tex->width; curTexWidth = tex->width;
curTexHeight = tex->height; curTexHeight = tex->height;
texWidthMask = (1 << Math_ilog2(tex->width)) - 1;
texHeightMask = (1 << Math_ilog2(tex->height)) - 1;
} }
void Gfx_DeleteTexture(GfxResourceID* texId) { void Gfx_DeleteTexture(GfxResourceID* texId) {
@ -123,7 +127,7 @@ static void SetAlphaBlend(cc_bool enabled) {
void Gfx_SetAlphaArgBlend(cc_bool enabled) { } void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
void Gfx_ClearBuffers(GfxBuffers buffers) { void Gfx_ClearBuffers(GfxBuffers buffers) {
int i, size = width * height; int i, size = fb_width * fb_height;
if (buffers & GFX_BUFFER_COLOR) { if (buffers & GFX_BUFFER_COLOR) {
for (i = 0; i < size; i++) colorBuffer[i] = clearColor; 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-------------------------------------------------------* *---------------------------------------------------------Rendering-------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
typedef struct Vector4 { float x, y, z, w; } Vector4;
typedef struct Vector3 { float x, y, z; } Vector3; typedef struct Vector3 { float x, y, z; } Vector3;
typedef struct Vector2 { float x, y; } Vector2; 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 // TODO: avoid the multiply, just add down in DrawTriangles
char* ptr = (char*)gfx_vertices + index * gfx_stride; char* ptr = (char*)gfx_vertices + index * gfx_stride;
Vector3* pos = (Vector3*)ptr; 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.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.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.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; 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; float invW = 1.0f / coord.w;
frag->x = vp_hwidth * (1 + coord.x * invW); vertex->x = vp_hwidth * (1 + coord.x * invW);
frag->y = vp_hheight * (1 - coord.y * invW); vertex->y = vp_hheight * (1 - coord.y * invW);
frag->z = coord.z * invW; vertex->z = coord.z * invW;
frag->w = invW; vertex->w = invW;
if (gfx_format != VERTEX_FORMAT_TEXTURED) { if (gfx_format != VERTEX_FORMAT_TEXTURED) {
struct VertexColoured* v = (struct VertexColoured*)ptr; struct VertexColoured* v = (struct VertexColoured*)ptr;
*color = v->Col; vertex->c = v->Col;
} else { } else {
struct VertexTextured* v = (struct VertexTextured*)ptr; struct VertexTextured* v = (struct VertexTextured*)ptr;
*color = v->Col; vertex->u = (v->U + texOffsetX) * invW;
uv->x = (v->U + texOffsetX) * invW; vertex->v = (v->V + texOffsetY) * invW;
uv->y = (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); return PackedCol_Make(r, g, b, a);
} }
static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3, static void DrawTriangle(Vertex* frag1, Vertex* frag2, Vertex* frag3) {
Vector2 uv1, Vector2 uv2, Vector2 uv3, PackedCol color) { int x1 = (int)frag1->x, y1 = (int)frag1->y;
int x1 = (int)frag1.x, y1 = (int)frag1.y; int x2 = (int)frag2->x, y2 = (int)frag2->y;
int x2 = (int)frag2.x, y2 = (int)frag2.y; int x3 = (int)frag3->x, y3 = (int)frag3->y;
int x3 = (int)frag3.x, y3 = (int)frag3.y;
int minX = min(x1, min(x2, x3)); int minX = min(x1, min(x2, x3));
int minY = min(y1, min(y2, y3)); int minY = min(y1, min(y2, y3));
int maxX = max(x1, max(x2, x3)); int maxX = max(x1, max(x2, x3));
@ -337,18 +344,24 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3,
} }
// Reject triangles completely outside // Reject triangles completely outside
if (minX < 0 && maxX < 0 || minX >= width && maxX >= width ) return; if ((minX < 0 && maxX < 0) || (minX > fb_maxX && maxX > fb_maxX)) return;
if (minY < 0 && maxY < 0 || minY >= height && maxY >= height) return; if ((minY < 0 && maxY < 0) || (minY > fb_maxY && maxY > fb_maxY)) return;
// Perform scissoring // Perform scissoring
minX = max(minX, 0); maxX = min(maxX, sc_maxX); minX = max(minX, 0); maxX = min(maxX, fb_maxX);
minY = max(minY, 0); maxY = min(maxY, sc_maxY); minY = max(minY, 0); maxY = min(maxY, fb_maxY);
// NOTE: W in frag variables below is actually 1/W // NOTE: W in frag variables below is actually 1/W
float factor = 1.0f / ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3)); 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 // 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++) { for (int y = minY; y <= maxY; y++) {
float yy = y + 0.5f; float yy = y + 0.5f;
@ -362,9 +375,9 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3,
float ic2 = 1.0f - ic0 - ic1; float ic2 = 1.0f - ic0 - ic1;
if (ic2 < 0 || ic2 > 1) continue; if (ic2 < 0 || ic2 > 1) continue;
int index = y * width + x; int index = y * fb_width + x;
float w = 1 / (ic0 * frag1.w + ic1 * frag2.w + ic2 * frag3.w); float w = 1 / (ic0 * w1 + ic1 * w2 + ic2 * w3);
float z = (ic0 * frag1.z + ic1 * frag2.z + ic2 * frag3.z) * w; float z = (ic0 * z1 + ic1 * z2 + ic2 * z3) * w;
if (depthTest && (z < 0 || z > depthBuffer[index])) continue; if (depthTest && (z < 0 || z > depthBuffer[index])) continue;
if (!colWrite) { if (!colWrite) {
@ -374,10 +387,10 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3,
PackedCol fragColor = color; PackedCol fragColor = color;
if (gfx_format == VERTEX_FORMAT_TEXTURED) { if (gfx_format == VERTEX_FORMAT_TEXTURED) {
float u = (ic0 * uv1.x + ic1 * uv2.x + ic2 * uv3.x) * w; float u = (ic0 * u1 + ic1 * u2 + ic2 * u3) * w;
float v = (ic0 * uv1.y + ic1 * uv2.y + ic2 * uv3.y) * w; float v = (ic0 * v1 + ic1 * v2 + ic2 * v3) * w;
int texX = ((int)(Math_AbsF(u - Math_Floor(u)) * curTexWidth )) % curTexWidth; // TODO avoid slow % int texX = ((int)(Math_AbsF(u - Math_Floor(u)) * curTexWidth )) & texWidthMask;
int texY = ((int)(Math_AbsF(v - Math_Floor(v)) * curTexHeight)) % curTexHeight; int texY = ((int)(Math_AbsF(v - Math_Floor(v)) * curTexHeight)) & texHeightMask;
int texIndex = texY * curTexWidth + texX; int texIndex = texY * curTexWidth + texX;
fragColor = MultiplyColours(fragColor, curTexPixels[texIndex]); fragColor = MultiplyColours(fragColor, curTexPixels[texIndex]);
@ -407,24 +420,19 @@ static void DrawTriangle(Vector4 frag1, Vector4 frag2, Vector4 frag3,
} }
void DrawQuads(int startVertex, int verticesCount) { void DrawQuads(int startVertex, int verticesCount) {
Vector4 frag[4]; Vertex vertices[4];
Vector2 uv[4];
PackedCol color[4];
int j = startVertex; int j = startVertex;
// 4 vertices = 1 quad = 2 triangles // 4 vertices = 1 quad = 2 triangles
for (int i = 0; i < verticesCount / 4; i++, j += 4) for (int i = 0; i < verticesCount / 4; i++, j += 4)
{ {
TransformVertex(j + 0, &frag[0], &uv[0], &color[0]); TransformVertex(j + 0, &vertices[0]);
TransformVertex(j + 1, &frag[1], &uv[1], &color[1]); TransformVertex(j + 1, &vertices[1]);
TransformVertex(j + 2, &frag[2], &uv[2], &color[2]); TransformVertex(j + 2, &vertices[2]);
TransformVertex(j + 3, &frag[3], &uv[3], &color[3]); TransformVertex(j + 3, &vertices[3]);
DrawTriangle(frag[0], frag[1], frag[2], DrawTriangle(&vertices[0], &vertices[1], &vertices[2]);
uv[0], uv[1], uv[2], color[0]); DrawTriangle(&vertices[2], &vertices[3], &vertices[0]);
DrawTriangle(frag[2], frag[3], frag[0],
uv[2], uv[3], uv[0], color[2]);
} }
} }
@ -453,7 +461,7 @@ void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {
*#########################################################################################################################*/ *#########################################################################################################################*/
cc_result Gfx_TakeScreenshot(struct Stream* output) { cc_result Gfx_TakeScreenshot(struct Stream* output) {
struct Bitmap bmp; 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); return Png_Encode(&bmp, output, NULL, false, NULL);
} }
@ -464,7 +472,7 @@ cc_bool Gfx_WarnIfNecessary(void) {
void Gfx_BeginFrame(void) { } void Gfx_BeginFrame(void) { }
void Gfx_EndFrame(void) { void Gfx_EndFrame(void) {
Rect2D r = { 0, 0, width, height }; Rect2D r = { 0, 0, fb_width, fb_height };
Window_DrawFramebuffer(r, &fb_bmp); Window_DrawFramebuffer(r, &fb_bmp);
} }
@ -476,17 +484,17 @@ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) {
void Gfx_OnWindowResize(void) { void Gfx_OnWindowResize(void) {
if (depthBuffer) DestroyBuffers(); if (depthBuffer) DestroyBuffers();
fb_bmp.width = width = Game.Width; fb_bmp.width = fb_width = Game.Width;
fb_bmp.height = height = Game.Height; fb_bmp.height = fb_height = Game.Height;
vp_hwidth = width / 2.0f; vp_hwidth = fb_width / 2.0f;
vp_hheight = height / 2.0f; vp_hheight = fb_height / 2.0f;
sc_maxX = width - 1; fb_maxX = fb_width - 1;
sc_maxY = height - 1; fb_maxY = fb_height - 1;
Window_AllocFramebuffer(&fb_bmp); 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; colorBuffer = fb_bmp.scan0;
} }

View File

@ -19,6 +19,8 @@
#include <MacMemory.h> #include <MacMemory.h>
#include <Processes.h> #include <Processes.h>
#include <Files.h> #include <Files.h>
#include <Gestalt.h>
#include <Math64.h>
const cc_result ReturnCode_FileShareViolation = 1000000000; /* TODO: not used apparently */ const cc_result ReturnCode_FileShareViolation = 1000000000; /* TODO: not used apparently */
const cc_result ReturnCode_FileNotFound = ENOENT; 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_SocketWouldBlock = EWOULDBLOCK;
const cc_result ReturnCode_DirectoryExists = EEXIST; 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; cc_bool Platform_SingleProcess = true;
static long sysVersion;
/*########################################################################################################################* /*########################################################################################################################*
*---------------------------------------------------Imported headers------------------------------------------------------* *---------------------------------------------------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 // 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----------------------------------------------------------* *---------------------------------------------------------Memory----------------------------------------------------------*
@ -88,25 +113,21 @@ void Platform_Log(const char* msg, int len) {
// classic macOS uses an epoch of 1904 // classic macOS uses an epoch of 1904
#define EPOCH_ADJUSTMENT 2082866400UL #define EPOCH_ADJUSTMENT 2082866400UL
static void gettod(struct timeval *tp) { static time_t gettod(void) {
unsigned long secs; unsigned long secs;
GetDateTime(&secs); GetDateTime(&secs);
return secs - EPOCH_ADJUSTMENT;
tp->tv_sec = secs - EPOCH_ADJUSTMENT;
tp->tv_usec = 0;
} }
TimeMS DateTime_CurrentUTC(void) { TimeMS DateTime_CurrentUTC(void) {
struct timeval cur; time_t secs = gettod();
gettod(&cur); return (cc_uint64)secs + UNIX_EPOCH_SECONDS;
return (cc_uint64)cur.tv_sec + UNIX_EPOCH_SECONDS;
} }
void DateTime_CurrentLocal(struct DateTime* t) { void DateTime_CurrentLocal(struct DateTime* t) {
struct timeval cur;
struct tm loc_time; struct tm loc_time;
gettod(&cur); time_t secs = gettod();
localtime_r(&cur.tv_sec, &loc_time); localtime_r(&secs, &loc_time);
t->year = loc_time.tm_year + 1900; t->year = loc_time.tm_year + 1900;
t->month = loc_time.tm_mon + 1; t->month = loc_time.tm_mon + 1;
@ -120,13 +141,19 @@ void DateTime_CurrentLocal(struct DateTime* t) {
/*########################################################################################################################* /*########################################################################################################################*
*--------------------------------------------------------Stopwatch--------------------------------------------------------* *--------------------------------------------------------Stopwatch--------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
#define NS_PER_SEC 1000000000ULL #define MS_PER_SEC 1000000ULL
cc_uint64 Stopwatch_Measure(void) { 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; UnsignedWide count;
Microseconds(&count); Microseconds(&count);
return (cc_uint64)count.lo | ((cc_uint64)count.hi << 32); return (cc_uint64)count.lo | ((cc_uint64)count.hi << 32);
//return UnsignedWideToUInt64(count);
} }
cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) { 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) { } void Directory_GetCachePath(cc_string* path) { }
cc_result Directory_Create(const 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) { 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) { 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) { 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) { void Thread_Sleep(cc_uint32 milliseconds) {
// TODO Delay API // 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) { 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) { void Platform_Init(void) {
Gestalt(gestaltSystemVersion, &sysVersion);
Platform_Log1("Running on Mac OS %h", &sysVersion);
Platform_LoadSysFonts(); Platform_LoadSysFonts();
} }

View File

@ -15,24 +15,57 @@
#include <Fonts.h> #include <Fonts.h>
#include <Events.h> #include <Events.h>
#include <DiskInit.h> #include <DiskInit.h>
#include <Scrap.h>
#include <Gestalt.h>
static WindowPtr win; static WindowPtr win;
static cc_bool hasColorQD;
/*########################################################################################################################* /*########################################################################################################################*
*---------------------------------------------------Imported headers------------------------------------------------------* *---------------------------------------------------Imported headers------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
// On 68k these are implemented using direct 68k opcodes
// Availability: in InterfaceLib 7.1 and later // On PPC these are implemented using function calls
static long GetScrap(Handle dst, FourCharCode type, SInt32* offset) ONEWORDINLINE(0xA9FD); #if TARGET_CPU_68K
// Availability: in InterfaceLib 7.1 and later #define MAC_SYSAPI(_type) static _type
static OSStatus PutScrap(SInt32 srcLen, FourCharCode type, const void* src) ONEWORDINLINE(0xA9FE); #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--------------------------------------------------* *--------------------------------------------------Public implementation--------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
void Window_PreInit(void) { } static const cc_uint8 key_map[8 * 16] = {
void Window_Init(void) { /* 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); InitGraf(&qd.thePort);
InitFonts(); InitFonts();
InitWindows(); InitWindows();
@ -45,6 +78,13 @@ void Window_Init(void) {
EventAvail(everyEvent, &event); EventAvail(everyEvent, &event);
FlushEvents(everyEvent, 0); 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; Rect r = qd.screenBits.bounds;
DisplayInfo.x = r.left; DisplayInfo.x = r.left;
DisplayInfo.y = r.top; DisplayInfo.y = r.top;
@ -64,7 +104,11 @@ static void DoCreateWindow(int width, int height) {
r.top += 40; r.top += 40;
InsetRect(&r, 100, 100); 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); SetPort(win);
r = win->portRect; 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) { 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) { 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) { void Cursor_SetPosition(int x, int y) {
// TODO // TODO
} }
static void Cursor_DoSetVisible(cc_bool visible) { static void Cursor_DoSetVisible(cc_bool visible) {
if (visible) { if (visible) {
ShowCursor(); ShowCursor();
@ -243,54 +278,113 @@ static void Cursor_DoSetVisible(cc_bool visible) {
static void ShowDialogCore(const char* title, const char* msg) { static void ShowDialogCore(const char* title, const char* msg) {
// TODO // TODO
for (int i = 0; i < 20; i++)
{
Platform_LogConst(title);
Platform_LogConst(msg);
}
} }
cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
// TODO // TODO
return 1; return ERR_NOT_SUPPORTED;
} }
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
// TODO // 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) { void Window_AllocFramebuffer(struct Bitmap* bmp) {
bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); 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) { static void DrawFramebufferFast(Rect2D r, struct Bitmap* bmp) {
GrafPtr thePort = (CGrafPtr)win; GrafPtr thePort = (GrafPtr)win;
SetPort(win); const BitMap* memBits;
int ww = bmp->width; const BitMap* winBits;
int hh = bmp->height;
// 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); 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 // TODO optimise
BitmapCol col = row[x]; BitmapCol col = row[x];
cc_uint8 R = BitmapCol_R(col); cc_uint8 R = BitmapCol_R(col);
cc_uint8 G = BitmapCol_G(col); cc_uint8 G = BitmapCol_G(col);
cc_uint8 B = BitmapCol_B(col); cc_uint8 B = BitmapCol_B(col);
// Set the pixel color in the window RGBColor pixelColor;
RGBColor pixelColor; pixelColor.red = R << 8;
pixelColor.red = R * 256; pixelColor.green = G << 8;
pixelColor.green = G * 256; pixelColor.blue = B << 8;
pixelColor.blue = B * 256;
RGBForeColor(&pixelColor); RGBForeColor(&pixelColor);
MoveTo(x, y); MoveTo(x, y);
Line(0, 0); 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) { void Window_FreeFramebuffer(struct Bitmap* bmp) {
Mem_Free(bmp->scan0); Mem_Free(bmp->scan0);
if (!hasColorQD) return;
UnlockPixels(fb_pixmap);
DisposeGWorld(fb_world);
} }
void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { } void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { }