From 4ea838930601c0c7b8426a437b3d2392fb0640d9 Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Tue, 10 Jan 2023 01:12:33 +0000 Subject: [PATCH] Backport to Glide 2 Most games were using Glide 2, meaning there is more wrappers for Glide 2 available than for Glide 3. In particular, it seems there is no open source Glide 3 wrapper. FossilOrigin-Name: 16bb6bc399e5b4db4f5117199f6b534231c42072555575b70f40795651805648 --- configure.ac | 8 +- src/Makefile | 3 +- src/O3DEngine.h | 36 -- src/O3DEngine.m | 50 --- src/O3DGlide3Renderer.m | 379 ------------------ ...O3DGlide3Renderer.h => O3DGlideRenderer.h} | 4 +- src/O3DGlideRenderer.m | 228 +++++++++++ src/O3DRenderer.h | 17 +- src/O3DRenderer.m | 27 -- tests/TestsAppDelegate.m | 46 +-- 10 files changed, 255 insertions(+), 543 deletions(-) delete mode 100644 src/O3DEngine.h delete mode 100644 src/O3DEngine.m delete mode 100644 src/O3DGlide3Renderer.m rename src/{O3DGlide3Renderer.h => O3DGlideRenderer.h} (88%) create mode 100644 src/O3DGlideRenderer.m diff --git a/configure.ac b/configure.ac index 2568da1..dd79595 100644 --- a/configure.ac +++ b/configure.ac @@ -69,14 +69,14 @@ AS_IF([test x"$enable_static" = x"yes" -o x"$enable_shared" = x"no"], [ AC_SUBST(LIBOBJ3DENGINE_DEP, "../src/libobj3dengine.a") ]) -AC_CHECK_LIB(glide3x, main, [ - LIBS="-lglide3x $LIBS" +AC_CHECK_LIB(glide2x, main, [ + LIBS="-lglide2x $LIBS" AC_CHECK_HEADER(glide.h, [], [ - AC_MSG_ERROR([glide.h not found. Please install Glide 3 SDK!]) + AC_MSG_ERROR([glide.h not found. Please install Glide 2 SDK!]) ]) ], [ - AC_MSG_ERROR([glide3x not found. Please install Glide 3 SDK!]) + AC_MSG_ERROR([glide2x not found. Please install Glide 2 SDK!]) ]) AS_IF([test x"$GOBJC" = x"yes"], [ diff --git a/src/Makefile b/src/Makefile index 62b9f96..dfdcce0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,8 +8,7 @@ FRAMEWORK = ${OBJ3DENGINE_FRAMEWORK} LIB_MAJOR = ${OBJ3DENGINE_LIB_MAJOR} LIB_MINOR = ${OBJ3DENGINE_LIB_MINOR} -SRCS = O3DEngine.m \ - O3DGlide3Renderer.m \ +SRCS = O3DGlideRenderer.m \ O3DRenderer.m \ O3DWinAPIWindow.m INCLUDES := ${SRCS:.m=.h} diff --git a/src/O3DEngine.h b/src/O3DEngine.h deleted file mode 100644 index cf0947d..0000000 --- a/src/O3DEngine.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of Obj3DEngine. It may be distributed under the terms of - * the Q Public License 1.0, which can be found in the file LICENSE.QPL - * included in the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of - * this file. - */ - -#import - -#import "O3DRenderer.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface O3DEngine: OFObject -{ - id _renderer; -} - -@property (readonly, nonatomic) id renderer; - -+ (OFArray OF_GENERIC(Class ) *)availableRenderers; - -- (instancetype)initWithRenderer: (Class )renderer - options: (nullable OFDictionary - OF_GENERIC(OFString *, id) *)options; -@end - -OF_ASSUME_NONNULL_END diff --git a/src/O3DEngine.m b/src/O3DEngine.m deleted file mode 100644 index 0197772..0000000 --- a/src/O3DEngine.m +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of Obj3DEngine. It may be distributed under the terms of - * the Q Public License 1.0, which can be found in the file LICENSE.QPL - * included in the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of - * this file. - */ - -#import "O3DEngine.h" -#import "O3DGlide3Renderer.h" - -@implementation O3DEngine -@synthesize renderer = _renderer; - -+ (OFArray OF_GENERIC(Class ) *)availableRenderers -{ - return [OFArray arrayWithObject: [O3DGlide3Renderer class]]; -} - -- (instancetype) - initWithRenderer: (Class )renderer - options: (OFDictionary OF_GENERIC(OFString *, id) *)options -{ - self = [super init]; - - @try { - _renderer = [(id )[(Class)renderer alloc] - initWithOptions: options]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_renderer release]; - - [super dealloc]; -} -@end diff --git a/src/O3DGlide3Renderer.m b/src/O3DGlide3Renderer.m deleted file mode 100644 index 511ec5a..0000000 --- a/src/O3DGlide3Renderer.m +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (c) 2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of Obj3DEngine. It may be distributed under the terms of - * the Q Public License 1.0, which can be found in the file LICENSE.QPL - * included in the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of - * this file. - */ - -#include - -#import "O3DGlide3Renderer.h" -#import "O3DWinAPIWindow.h" - -@interface O3DGlide3Renderer () -- (void)setState; -@end - -static OFSize -screenResolutionToSize(GrScreenResolution_t resolution) -{ - switch (resolution) { - case GR_RESOLUTION_320x200: - return OFMakeSize(320, 200); - case GR_RESOLUTION_320x240: - return OFMakeSize(320, 240); - case GR_RESOLUTION_400x256: - return OFMakeSize(400, 256); - case GR_RESOLUTION_512x384: - return OFMakeSize(512, 384); - case GR_RESOLUTION_640x200: - return OFMakeSize(640, 200); - case GR_RESOLUTION_640x350: - return OFMakeSize(640, 350); - case GR_RESOLUTION_640x400: - return OFMakeSize(640, 400); - case GR_RESOLUTION_640x480: - return OFMakeSize(640, 480); - case GR_RESOLUTION_800x600: - return OFMakeSize(800, 600); - case GR_RESOLUTION_960x720: - return OFMakeSize(960, 720); - case GR_RESOLUTION_856x480: - return OFMakeSize(856, 480); - case GR_RESOLUTION_512x256: - return OFMakeSize(512, 256); - case GR_RESOLUTION_1024x768: - return OFMakeSize(1024, 768); - case GR_RESOLUTION_1280x1024: - return OFMakeSize(1280, 1024); - case GR_RESOLUTION_1600x1200: - return OFMakeSize(1600, 1200); - case GR_RESOLUTION_400x300: - return OFMakeSize(400, 300); - case GR_RESOLUTION_1152x864: - return OFMakeSize(1152, 864); - case GR_RESOLUTION_1280x960: - return OFMakeSize(1280, 960); - case GR_RESOLUTION_1600x1024: - return OFMakeSize(1600, 1024); - case GR_RESOLUTION_1792x1344: - return OFMakeSize(1792, 1344); - case GR_RESOLUTION_1856x1392: - return OFMakeSize(1856, 1392); - case GR_RESOLUTION_1920x1440: - return OFMakeSize(1920, 1440); - case GR_RESOLUTION_2048x1536: - return OFMakeSize(2048, 1536); - case GR_RESOLUTION_2048x2048: - return OFMakeSize(2048, 2048); - default: - return OFMakeSize(0, 0); - } -} - -static GrScreenResolution_t -sizeToScreenResolution(OFSize size) -{ - if (size.width == 320 && size.height == 200) - return GR_RESOLUTION_320x200; - if (size.width == 320 && size.height == 240) - return GR_RESOLUTION_320x240; - if (size.width == 400 && size.height == 256) - return GR_RESOLUTION_400x256; - if (size.width == 512 && size.height == 384) - return GR_RESOLUTION_512x384; - if (size.width == 640 && size.height == 200) - return GR_RESOLUTION_640x200; - if (size.width == 640 && size.height == 350) - return GR_RESOLUTION_640x350; - if (size.width == 640 && size.height == 400) - return GR_RESOLUTION_640x400; - if (size.width == 640 && size.height == 480) - return GR_RESOLUTION_640x480; - if (size.width == 800 && size.height == 600) - return GR_RESOLUTION_800x600; - if (size.width == 960 && size.height == 720) - return GR_RESOLUTION_960x720; - if (size.width == 856 && size.height == 480) - return GR_RESOLUTION_856x480; - if (size.width == 512 && size.height == 256) - return GR_RESOLUTION_512x256; - if (size.width == 1024 && size.height == 768) - return GR_RESOLUTION_1024x768; - if (size.width == 1280 && size.height == 1024) - return GR_RESOLUTION_1280x1024; - if (size.width == 1600 && size.height == 1200) - return GR_RESOLUTION_1600x1200; - if (size.width == 400 && size.height == 300) - return GR_RESOLUTION_400x300; - if (size.width == 1152 && size.height == 864) - return GR_RESOLUTION_1152x864; - if (size.width == 1280 && size.height == 960) - return GR_RESOLUTION_1280x960; - if (size.width == 1600 && size.height == 1024) - return GR_RESOLUTION_1600x1024; - if (size.width == 1792 && size.height == 1344) - return GR_RESOLUTION_1792x1344; - if (size.width == 1856 && size.height == 1392) - return GR_RESOLUTION_1856x1392; - if (size.width == 1920 && size.height == 1440) - return GR_RESOLUTION_1920x1440; - if (size.width == 2048 && size.height == 1536) - return GR_RESOLUTION_2048x1536; - if (size.width == 2048 && size.height == 2048) - return GR_RESOLUTION_2048x2048; - - return GR_RESOLUTION_NONE; -} - -static float -screenRefreshToFloat(GrScreenRefresh_t refresh) -{ - switch (refresh) { - case GR_REFRESH_60Hz: - return 60; - case GR_REFRESH_70Hz: - return 70; - case GR_REFRESH_72Hz: - return 72; - case GR_REFRESH_75Hz: - return 75; - case GR_REFRESH_80Hz: - return 80; - case GR_REFRESH_90Hz: - return 90; - case GR_REFRESH_100Hz: - return 100; - case GR_REFRESH_85Hz: - return 85; - case GR_REFRESH_120Hz: - return 120; - default: - return 0; - } -} - -static GrScreenRefresh_t -floatToScreenRefresh(float refresh) -{ - if (refresh == 60) - return GR_REFRESH_60Hz; - if (refresh == 70) - return GR_REFRESH_70Hz; - if (refresh == 72) - return GR_REFRESH_72Hz; - if (refresh == 75) - return GR_REFRESH_75Hz; - if (refresh == 80) - return GR_REFRESH_80Hz; - if (refresh == 90) - return GR_REFRESH_90Hz; - if (refresh == 100) - return GR_REFRESH_100Hz; - if (refresh == 85) - return GR_REFRESH_85Hz; - if (refresh == 120) - return GR_REFRESH_120Hz; - - return GR_REFRESH_NONE; -} - -static OF_INLINE void -translateVertices(O3DVertex *vertices, size_t count, OFSize size) -{ - /* - * Range is -1 to 1, we add 1, so we get 0 to 2 - so we need to - * multiply with half the width / height. - */ - size.width /= 2; - size.height /= 2; - - for (size_t i = 0; i < count; i++) { - vertices[i].x += 1; - vertices[i].y += 1; - vertices[i].x *= size.width; - vertices[i].y *= size.height; - } -} - -@implementation O3DGlide3Renderer -@synthesize syncsToVerticalBlank = _syncsToVerticalBlank; - -- (instancetype)initWithOptions: - (OFDictionary OF_GENERIC(OFString *, id) *)options -{ - self = [super init]; - - @try { - grGlideInit(); - - FxI32 numDevices; - if (grGet(GR_NUM_BOARDS, sizeof(numDevices), &numDevices) == 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - long long deviceIndex = [[options objectForKey: - O3DRendererDeviceIndex] longLongValue]; - if (deviceIndex > numDevices) - @throw [OFInvalidArgumentException exception]; - - grSstSelect((int)deviceIndex); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - if (_context != 0) - grSstWinClose(_context); - - grGlideShutdown(); - -#ifdef OF_WINDOWS - [_winAPIWindow release]; -#endif - - [super dealloc]; -} - -- (OFArray OF_GENERIC(OFPair OF_GENERIC(OFValue *, OFNumber *) *) *) - availableResolutions -{ - OFMutableArray *ret = [OFMutableArray array]; - GrResolution query = { - .resolution = GR_QUERY_ANY, - .refresh = GR_QUERY_ANY, - .numColorBuffers = 2, - .numAuxBuffers = 1 - }; - size_t size = grQueryResolutions(&query, NULL); - - GrResolution *resolutions = OFAllocMemory(1, size); - @try { - size = grQueryResolutions(&query, resolutions); - - void *pool = objc_autoreleasePoolPush(); - for (size_t i = 0; i < size / sizeof(*resolutions); i++) { - OFSize resolutionSize = - screenResolutionToSize(resolutions[i].resolution); - float refreshFloat = - screenRefreshToFloat(resolutions[i].refresh); - - if (resolutionSize.width == 0 || - resolutionSize.height == 0) - continue; - if (refreshFloat == 0) - continue; - - OFValue *resolution = - [OFValue valueWithSize: resolutionSize]; - OFNumber *refresh = - [OFNumber numberWithFloat: refreshFloat]; - [ret addObject: [OFPair pairWithFirstObject: resolution - secondObject: refresh]]; - } - objc_autoreleasePoolPop(pool); - } @finally { - OFFreeMemory(resolutions); - } - - [ret sortUsingFunction: O3DCompareResolution - context: NULL - options: OFArraySortDescending]; - - [ret makeImmutable]; - - return ret; -} - -- (void)createWithResolution: (O3DResolution)resolution -{ - if (_context != 0) - @throw [OFAlreadyOpenException exceptionWithObject: self]; - - GrScreenResolution_t screenResolution = - sizeToScreenResolution([resolution.firstObject sizeValue]); - GrScreenRefresh_t screenRefresh = - floatToScreenRefresh([resolution.secondObject floatValue]); - - if (screenResolution == GR_RESOLUTION_NONE || - screenRefresh == GR_REFRESH_NONE) - @throw [OFInvalidArgumentException exception]; - - FxU32 hWnd = 0; -#ifdef OF_WINDOWS - _winAPIWindow = [[O3DWinAPIWindow alloc] - initWithSize: [resolution.firstObject sizeValue]]; - hWnd = (FxU32)_winAPIWindow.hWnd; -#endif - - if ((_context = grSstWinOpen(hWnd, screenResolution, screenRefresh, - GR_COLORFORMAT_RGBA, GR_ORIGIN_LOWER_LEFT, 2, 1)) == 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - _clippingWindow = [resolution.firstObject sizeValue]; - - [self setState]; -} - -- (void)setState -{ - grVertexLayout(GR_PARAM_XY, offsetof(O3DVertex, x), GR_PARAM_ENABLE); - grSstOrigin(GR_ORIGIN_LOWER_LEFT); -} - -- (void)beginFrame -{ - assert(_context != 0); - - if (!grSelectContext(_context)) - [self setState]; - - grBufferClear(0, 0, 0); -} - -- (void)setColor: (OFColor *)color -{ - float values[4]; - [color getRed: &values[0] - green: &values[1] - blue: &values[2] - alpha: &values[3]]; - for (uint_fast8_t i = 0; i < 4; i++) - values[i] *= 255; - grColorCombine(GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, - GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE, FXFALSE); - grConstantColorValue((((GrColor_t)values[0]) << 24) | - (((GrColor_t)values[1]) << 16) | (((GrColor_t)values[2]) << 8) | - (GrColor_t)values[2]); -} - -- (void)drawVertices: (OFData *)vertices_ -{ - assert(vertices_.itemSize == sizeof(O3DVertex)); - - OFMutableData *vertices = [[vertices_ mutableCopy] autorelease]; - translateVertices(vertices.mutableItems, vertices.count, - _clippingWindow); - grDrawVertexArrayContiguous(GR_TRIANGLE_STRIP, - vertices.count, vertices.mutableItems, sizeof(O3DVertex)); -} - -- (void)endFrame -{ - grBufferSwap(_syncsToVerticalBlank ? 1 : 0); -} -@end diff --git a/src/O3DGlide3Renderer.h b/src/O3DGlideRenderer.h similarity index 88% rename from src/O3DGlide3Renderer.h rename to src/O3DGlideRenderer.h index e3e3849..b4cca56 100644 --- a/src/O3DGlide3Renderer.h +++ b/src/O3DGlideRenderer.h @@ -21,13 +21,11 @@ OF_ASSUME_NONNULL_BEGIN @class O3DWinAPIWindow; -@interface O3DGlide3Renderer: OFObject +@interface O3DGlideRenderer: OFObject { - GrResolution _resolution; #ifdef OF_WINDOWS O3DWinAPIWindow *_winAPIWindow; #endif - GrContext_t _context; OFSize _clippingWindow; bool _syncsToVerticalBlank; } diff --git a/src/O3DGlideRenderer.m b/src/O3DGlideRenderer.m new file mode 100644 index 0000000..23a2eb1 --- /dev/null +++ b/src/O3DGlideRenderer.m @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2022 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of Obj3DEngine. It may be distributed under the terms of + * the Q Public License 1.0, which can be found in the file LICENSE.QPL + * included in the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of + * this file. + */ + +#include +#include + +#import "O3DGlideRenderer.h" +#import "O3DWinAPIWindow.h" + +static GrScreenResolution_t +sizeToScreenResolution(OFSize size) +{ + if (size.width == 320 && size.height == 200) + return GR_RESOLUTION_320x200; + if (size.width == 320 && size.height == 240) + return GR_RESOLUTION_320x240; + if (size.width == 400 && size.height == 256) + return GR_RESOLUTION_400x256; + if (size.width == 512 && size.height == 384) + return GR_RESOLUTION_512x384; + if (size.width == 640 && size.height == 200) + return GR_RESOLUTION_640x200; + if (size.width == 640 && size.height == 350) + return GR_RESOLUTION_640x350; + if (size.width == 640 && size.height == 400) + return GR_RESOLUTION_640x400; + if (size.width == 640 && size.height == 480) + return GR_RESOLUTION_640x480; + if (size.width == 800 && size.height == 600) + return GR_RESOLUTION_800x600; + if (size.width == 960 && size.height == 720) + return GR_RESOLUTION_960x720; + if (size.width == 856 && size.height == 480) + return GR_RESOLUTION_856x480; + if (size.width == 512 && size.height == 256) + return GR_RESOLUTION_512x256; + if (size.width == 1024 && size.height == 768) + return GR_RESOLUTION_1024x768; + if (size.width == 1280 && size.height == 1024) + return GR_RESOLUTION_1280x1024; + if (size.width == 1600 && size.height == 1200) + return GR_RESOLUTION_1600x1200; + if (size.width == 400 && size.height == 300) + return GR_RESOLUTION_400x300; + if (size.width == 1152 && size.height == 864) + return GR_RESOLUTION_1152x864; + if (size.width == 1280 && size.height == 960) + return GR_RESOLUTION_1280x960; + if (size.width == 1600 && size.height == 1024) + return GR_RESOLUTION_1600x1024; + if (size.width == 1792 && size.height == 1344) + return GR_RESOLUTION_1792x1344; + if (size.width == 1856 && size.height == 1392) + return GR_RESOLUTION_1856x1392; + if (size.width == 1920 && size.height == 1440) + return GR_RESOLUTION_1920x1440; + if (size.width == 2048 && size.height == 1536) + return GR_RESOLUTION_2048x1536; + if (size.width == 2048 && size.height == 2048) + return GR_RESOLUTION_2048x2048; + + @throw [OFInvalidArgumentException exception]; +} + +static GrScreenRefresh_t +floatToScreenRefresh(float refresh) +{ + if (refresh == 60) + return GR_REFRESH_60Hz; + if (refresh == 70) + return GR_REFRESH_70Hz; + if (refresh == 72) + return GR_REFRESH_72Hz; + if (refresh == 75) + return GR_REFRESH_75Hz; + if (refresh == 80) + return GR_REFRESH_80Hz; + if (refresh == 90) + return GR_REFRESH_90Hz; + if (refresh == 100) + return GR_REFRESH_100Hz; + if (refresh == 85) + return GR_REFRESH_85Hz; + if (refresh == 120) + return GR_REFRESH_120Hz; + + @throw [OFInvalidArgumentException exception]; +} + +@implementation O3DGlideRenderer +@synthesize syncsToVerticalBlank = _syncsToVerticalBlank; + +static void +grGlideShutdownCdecl(void) +{ + grGlideShutdown(); +} + ++ (void)initialize +{ + if (self != [O3DGlideRenderer class]) + return; + + grGlideInit(); + atexit(grGlideShutdownCdecl); +} + ++ (unsigned int)numAvailableDevices +{ + GrHwConfiguration config; + if (!grSstQueryHardware(&config)) + return 0; + + if (config.num_sst < 0) + return 0; + + return (unsigned int)config.num_sst; +} + +- (instancetype)initWithResolution: (OFSize)resolution + bitsPerPixel: (uint8_t)bitsPerPixel + refreshRate: (float)refreshRate + options: (nullable OFDictionary *)options +{ + self = [super init]; + + @try { + if (bitsPerPixel != 16) + @throw [OFInvalidArgumentException exception]; + + long long deviceIndex = [[options objectForKey: + O3DRendererDeviceIndex] longLongValue]; + if (deviceIndex > [self.class numAvailableDevices]) + @throw [OFInvalidArgumentException exception]; + + grSstSelect((int)deviceIndex); + + FxU32 hWnd = 0; +#ifdef OF_WINDOWS + _winAPIWindow = [[O3DWinAPIWindow alloc] + initWithSize: resolution]; + hWnd = (FxU32)_winAPIWindow.hWnd; +#endif + + if (!grSstWinOpen(hWnd, sizeToScreenResolution(resolution), + floatToScreenRefresh(refreshRate), GR_COLORFORMAT_RGBA, + GR_ORIGIN_LOWER_LEFT, 2, 1)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + grSstWinClose(); + +#ifdef OF_WINDOWS + [_winAPIWindow release]; +#endif + + [super dealloc]; +} + +- (void)beginFrame +{ + grBufferClear(0, 0, 0); +} + +- (void)setColor: (OFColor *)color +{ + float values[4]; + [color getRed: &values[0] + green: &values[1] + blue: &values[2] + alpha: &values[3]]; + for (uint_fast8_t i = 0; i < 4; i++) + values[i] *= 255; + grColorCombine(GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE, FXFALSE); + grConstantColorValue((((GrColor_t)values[0]) << 24) | + (((GrColor_t)values[1]) << 16) | (((GrColor_t)values[2]) << 8) | + (GrColor_t)values[2]); +} + +- (void)drawPolygonVertices: (const O3DVertex *)vertices count: (size_t)count +{ + /* + * Range is -1 to 1, we add 1, so we get 0 to 2 - so we need to + * multiply with half the width / height. + */ + float halfWidth = grSstScreenWidth() / 2; + float halfHeight = grSstScreenHeight() / 2; + + GrVertex *glideVertices = OFAllocMemory(count, sizeof(GrVertex)); + @try { + for (size_t i = 0; i < count; i++) { + glideVertices[i].x = (vertices[i].x + 1) * halfWidth; + glideVertices[i].y = (vertices[i].y + 1) * halfHeight; + } + + grDrawPolygonVertexList((int)count, glideVertices); + } @finally { + OFFreeMemory(glideVertices); + } +} + +- (void)endFrame +{ + grBufferSwap(_syncsToVerticalBlank ? 1 : 0); +} +@end diff --git a/src/O3DRenderer.h b/src/O3DRenderer.h index 1142e53..9758cc8 100644 --- a/src/O3DRenderer.h +++ b/src/O3DRenderer.h @@ -17,23 +17,22 @@ OF_ASSUME_NONNULL_BEGIN -typedef OFPair OF_GENERIC(OFValue *, OFNumber *) *O3DResolution; - typedef struct OF_BOXABLE { float x, y; } O3DVertex; @protocol O3DRenderer -@property (readonly, nonatomic) OFArray OF_GENERIC(OFPair OF_GENERIC(OFValue *, - OFNumber *) *) *availableResolutions; @property (nonatomic) bool syncsToVerticalBlank; -- (instancetype)initWithOptions: - (nullable OFDictionary OF_GENERIC(OFString *, id) *)options; -- (void)createWithResolution: (O3DResolution)resolution; ++ (unsigned int)numAvailableDevices; + +- (instancetype)initWithResolution: (OFSize)resolution + bitsPerPixel: (uint8_t)bitsPerPixel + refreshRate: (float)refreshRate + options: (nullable OFDictionary *)options; - (void)beginFrame; - (void)setColor: (OFColor *)color; -- (void)drawVertices: (OFData *)vertices; +- (void)drawPolygonVertices: (const O3DVertex *)vertices count: (size_t)count; - (void)endFrame; @end @@ -41,8 +40,6 @@ typedef struct OF_BOXABLE { extern "C" { #endif extern OFString *const O3DRendererDeviceIndex; -extern OFComparisonResult O3DCompareResolution(id _Nullable left, - id _Nullable right, void *_Nullable context); #ifdef __cplusplus } #endif diff --git a/src/O3DRenderer.m b/src/O3DRenderer.m index 7159638..af3c071 100644 --- a/src/O3DRenderer.m +++ b/src/O3DRenderer.m @@ -16,30 +16,3 @@ #import "O3DRenderer.h" OFString *const O3DRendererDeviceIndex = @"O3DRendererDeviceIndex"; - -OFComparisonResult -O3DCompareResolution(id left, id right, void *context) -{ - OFSize leftResolution = [[left firstObject] sizeValue]; - OFSize rightResolution = [[right firstObject] sizeValue]; - - if (leftResolution.width > rightResolution.width) - return OFOrderedDescending; - if (leftResolution.width < rightResolution.width) - return OFOrderedAscending; - - if (leftResolution.height > rightResolution.height) - return OFOrderedDescending; - if (leftResolution.height < rightResolution.height) - return OFOrderedAscending; - - float leftRefresh = [[left secondObject] floatValue]; - float rightRefresh = [[right secondObject] floatValue]; - - if (leftRefresh > rightRefresh) - return OFOrderedDescending; - if (leftRefresh < rightRefresh) - return OFOrderedAscending; - - return OFOrderedSame; -} diff --git a/tests/TestsAppDelegate.m b/tests/TestsAppDelegate.m index ac970a8..a866cc2 100644 --- a/tests/TestsAppDelegate.m +++ b/tests/TestsAppDelegate.m @@ -15,7 +15,7 @@ #import -#import "O3DEngine.h" +#import "O3DGlideRenderer.h" @interface TestsAppDelegate: OFObject @end @@ -25,49 +25,31 @@ OF_APPLICATION_DELEGATE(TestsAppDelegate) @implementation TestsAppDelegate - (void)applicationDidFinishLaunching: (OFNotification *)notification { - Class renderer = - [O3DEngine availableRenderers].firstObject; - O3DEngine *engine = - [[[O3DEngine alloc] initWithRenderer: renderer - options: nil] autorelease]; + O3DGlideRenderer *renderer = [[[O3DGlideRenderer alloc] + initWithResolution: OFMakeSize(640, 480) + bitsPerPixel: 16 + refreshRate: 60 + options: nil] autorelease]; - [OFStdOut writeFormat: @"Available resolutions: %@\n", - engine.renderer.availableResolutions]; - - O3DResolution resolution = [OFPair - pairWithFirstObject: [OFValue valueWithSize: OFMakeSize(800, 600)] - secondObject: [OFNumber numberWithFloat: 60]]; - [engine.renderer createWithResolution: resolution]; - - O3DVertex values1[] = { + const O3DVertex outerTriangle[] = { { -1, -1 }, { 0, 1 }, { 1, -1 } }; - O3DVertex values2[] = { + const O3DVertex innerTriangle[] = { { -0.5, 0.5 }, { 0, -0.5 }, { 0.5, 0.5 } }; - OFData *vertices1 = [OFData - dataWithItemsNoCopy: values1 - count: sizeof(values1) / sizeof(*values2) - itemSize: sizeof(O3DVertex) - freeWhenDone: false]; - OFData *vertices2 = [OFData - dataWithItemsNoCopy: values2 - count: sizeof(values2) / sizeof(*values2) - itemSize: sizeof(O3DVertex) - freeWhenDone: false]; OFDate *startDate = [OFDate date]; while (-startDate.timeIntervalSinceNow < 5) { - [engine.renderer beginFrame]; - [engine.renderer setColor: [OFColor yellow]]; - [engine.renderer drawVertices: vertices1]; - [engine.renderer setColor: [OFColor red]]; - [engine.renderer drawVertices: vertices2]; - [engine.renderer endFrame]; + [renderer beginFrame]; + [renderer setColor: [OFColor yellow]]; + [renderer drawPolygonVertices: outerTriangle count: 3]; + [renderer setColor: [OFColor red]]; + [renderer drawPolygonVertices: innerTriangle count: 3]; + [renderer endFrame]; } [OFApplication terminate];