FossilOrigin-Name: 3632a7239a1926291c9162ba892d2315038a178a31652618df991c0ee549b5b5
233 lines
5.9 KiB
Objective-C
233 lines
5.9 KiB
Objective-C
/*
|
|
* 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;
|
|
#ifdef GR_RESOLUTION_1152x864
|
|
if (size.width == 1152 && size.height == 864)
|
|
return GR_RESOLUTION_1152x864;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_1280x960
|
|
if (size.width == 1280 && size.height == 960)
|
|
return GR_RESOLUTION_1280x960;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_1600x1024
|
|
if (size.width == 1600 && size.height == 1024)
|
|
return GR_RESOLUTION_1600x1024;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_1792x1344
|
|
if (size.width == 1792 && size.height == 1344)
|
|
return GR_RESOLUTION_1792x1344;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_1856x1392
|
|
if (size.width == 1856 && size.height == 1392)
|
|
return GR_RESOLUTION_1856x1392;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_1920x1440
|
|
if (size.width == 1920 && size.height == 1440)
|
|
return GR_RESOLUTION_1920x1440;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_2048x1536
|
|
if (size.width == 2048 && size.height == 1536)
|
|
return GR_RESOLUTION_2048x1536;
|
|
#endif
|
|
#ifdef GR_RESOLUTION_2048x2048
|
|
if (size.width == 2048 && size.height == 2048)
|
|
return GR_RESOLUTION_2048x2048;
|
|
#endif
|
|
|
|
@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)drawPolygonWithVertices: (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 = OFAllocZeroedMemory(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;
|
|
glideVertices[i].r = vertices[i].r * 255;
|
|
glideVertices[i].g = vertices[i].g * 255;
|
|
glideVertices[i].b = vertices[i].b * 255;
|
|
glideVertices[i].a = vertices[i].a * 255;
|
|
}
|
|
|
|
grDrawPolygonVertexList((int)count, glideVertices);
|
|
} @finally {
|
|
OFFreeMemory(glideVertices);
|
|
}
|
|
}
|
|
|
|
- (void)endFrame
|
|
{
|
|
grBufferSwap(_syncsToVerticalBlank ? 1 : 0);
|
|
}
|
|
@end
|