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
This commit is contained in:
parent
c322610fe4
commit
4ea8389306
10 changed files with 255 additions and 543 deletions
|
@ -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"], [
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Jonathan Schleifer <js@nil.im>
|
||||
*
|
||||
* 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 <ObjFW/ObjFW.h>
|
||||
|
||||
#import "O3DRenderer.h"
|
||||
|
||||
OF_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface O3DEngine: OFObject
|
||||
{
|
||||
id <O3DRenderer> _renderer;
|
||||
}
|
||||
|
||||
@property (readonly, nonatomic) id <O3DRenderer> renderer;
|
||||
|
||||
+ (OFArray OF_GENERIC(Class <O3DRenderer>) *)availableRenderers;
|
||||
|
||||
- (instancetype)initWithRenderer: (Class <O3DRenderer>)renderer
|
||||
options: (nullable OFDictionary
|
||||
OF_GENERIC(OFString *, id) *)options;
|
||||
@end
|
||||
|
||||
OF_ASSUME_NONNULL_END
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Jonathan Schleifer <js@nil.im>
|
||||
*
|
||||
* 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 <O3DRenderer>) *)availableRenderers
|
||||
{
|
||||
return [OFArray arrayWithObject: [O3DGlide3Renderer class]];
|
||||
}
|
||||
|
||||
- (instancetype)
|
||||
initWithRenderer: (Class <O3DRenderer>)renderer
|
||||
options: (OFDictionary OF_GENERIC(OFString *, id) *)options
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
@try {
|
||||
_renderer = [(id <O3DRenderer>)[(Class)renderer alloc]
|
||||
initWithOptions: options];
|
||||
} @catch (id e) {
|
||||
[self release];
|
||||
@throw e;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_renderer release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
|
@ -1,379 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Jonathan Schleifer <js@nil.im>
|
||||
*
|
||||
* 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 <assert.h>
|
||||
|
||||
#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
|
|
@ -21,13 +21,11 @@ OF_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class O3DWinAPIWindow;
|
||||
|
||||
@interface O3DGlide3Renderer: OFObject <O3DRenderer>
|
||||
@interface O3DGlideRenderer: OFObject <O3DRenderer>
|
||||
{
|
||||
GrResolution _resolution;
|
||||
#ifdef OF_WINDOWS
|
||||
O3DWinAPIWindow *_winAPIWindow;
|
||||
#endif
|
||||
GrContext_t _context;
|
||||
OFSize _clippingWindow;
|
||||
bool _syncsToVerticalBlank;
|
||||
}
|
228
src/O3DGlideRenderer.m
Normal file
228
src/O3DGlideRenderer.m
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Jonathan Schleifer <js@nil.im>
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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
|
|
@ -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 <OFObject>
|
||||
@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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#import <ObjFW/ObjFW.h>
|
||||
|
||||
#import "O3DEngine.h"
|
||||
#import "O3DGlideRenderer.h"
|
||||
|
||||
@interface TestsAppDelegate: OFObject <OFApplicationDelegate>
|
||||
@end
|
||||
|
@ -25,49 +25,31 @@ OF_APPLICATION_DELEGATE(TestsAppDelegate)
|
|||
@implementation TestsAppDelegate
|
||||
- (void)applicationDidFinishLaunching: (OFNotification *)notification
|
||||
{
|
||||
Class <O3DRenderer> 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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue