diff --git a/src/O3DGlide3Renderer.h b/src/O3DGlide3Renderer.h index e0cbe90..e3e3849 100644 --- a/src/O3DGlide3Renderer.h +++ b/src/O3DGlide3Renderer.h @@ -28,6 +28,8 @@ OF_ASSUME_NONNULL_BEGIN O3DWinAPIWindow *_winAPIWindow; #endif GrContext_t _context; + OFSize _clippingWindow; + bool _syncsToVerticalBlank; } @end diff --git a/src/O3DGlide3Renderer.m b/src/O3DGlide3Renderer.m index c6a20ca..511ec5a 100644 --- a/src/O3DGlide3Renderer.m +++ b/src/O3DGlide3Renderer.m @@ -13,9 +13,15 @@ * this file. */ +#include + #import "O3DGlide3Renderer.h" #import "O3DWinAPIWindow.h" +@interface O3DGlide3Renderer () +- (void)setState; +@end + static OFSize screenResolutionToSize(GrScreenResolution_t resolution) { @@ -180,7 +186,27 @@ floatToScreenRefresh(float refresh) 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 { @@ -297,5 +323,57 @@ floatToScreenRefresh(float refresh) 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/O3DRenderer.h b/src/O3DRenderer.h index 5de2758..1142e53 100644 --- a/src/O3DRenderer.h +++ b/src/O3DRenderer.h @@ -19,13 +19,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; +- (void)beginFrame; +- (void)setColor: (OFColor *)color; +- (void)drawVertices: (OFData *)vertices; +- (void)endFrame; @end #ifdef __cplusplus diff --git a/tests/TestsAppDelegate.m b/tests/TestsAppDelegate.m index 87fe929..ac970a8 100644 --- a/tests/TestsAppDelegate.m +++ b/tests/TestsAppDelegate.m @@ -39,7 +39,36 @@ OF_APPLICATION_DELEGATE(TestsAppDelegate) secondObject: [OFNumber numberWithFloat: 60]]; [engine.renderer createWithResolution: resolution]; - [OFThread sleepForTimeInterval: 5]; + O3DVertex values1[] = { + { -1, -1 }, + { 0, 1 }, + { 1, -1 } + }; + O3DVertex values2[] = { + { -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]; + } [OFApplication terminate]; }