Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -8,11 +8,12 @@ STATIC_LIB = ${OBJFW_STATIC_LIB} FRAMEWORK = ${OBJFW_FRAMEWORK} LIB_MAJOR = ${OBJFW_LIB_MAJOR} LIB_MINOR = ${OBJFW_LIB_MINOR} -SRCS = OFASPrintF.m \ +SRCS = OF4x4Matrix.m \ + OFASPrintF.m \ OFApplication.m \ OFArray.m \ OFBase64.m \ OFBlock.m \ OFCRC16.m \ ADDED src/OF4x4Matrix.h Index: src/OF4x4Matrix.h ================================================================== --- src/OF4x4Matrix.h +++ src/OF4x4Matrix.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2021 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. 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 "OFObject.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @brief A 4x4 matrix of floats. + */ +OF_SUBCLASSING_RESTRICTED +@interface OF4x4Matrix: OFObject +{ + float _values[16]; +} + +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (readonly, class) OF4x4Matrix *identity; +#endif + +/** + * @brief An array of the 16 floats of the 4x4 matrix in column-major format. + * + * These may be modified directly. + */ +@property (readonly, nonatomic) float *values; + +/** + * @brief Returns the 4x4 identity matrix. + */ ++ (OF4x4Matrix *)identity; + +/** + * @brief Creates a new 4x4 matrix with the specified values. + * + * @param values An array of 16 floats in column-major format + * @return A new, autoreleased OF4x4Matrix + */ ++ (instancetype)matrixWithValues: (const float [_Nonnull 16])values; + +/** + * @brief Initializes an already allocated 4x4 matrix with the specified values. + * + * @param values An array of 16 floats in column-major format + * @return An initialized OF4x4Matrix + */ +- (instancetype)initWithValues: (const float [_Nonnull 16])values; + +/** + * @brief Transposes the matrix. + */ +- (void)transpose; +@end + +OF_ASSUME_NONNULL_END ADDED src/OF4x4Matrix.m Index: src/OF4x4Matrix.m ================================================================== --- src/OF4x4Matrix.m +++ src/OF4x4Matrix.m @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2008-2021 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. 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 "config.h" + +#import "OF4x4Matrix.h" +#import "OFString.h" + +static const float identityValues[16] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 +}; +static OF4x4Matrix *identity; + +@implementation OF4x4Matrix ++ (void)initialize +{ + if (self != [OF4x4Matrix class]) + return; + + identity = [[OF4x4Matrix alloc] initWithValues: identityValues]; +} + ++ (OF4x4Matrix *)identity +{ + return identity; +} + ++ (instancetype)matrixWithValues: (const float [16])values +{ + return [[[self alloc] initWithValues: values] autorelease]; +} + +- (instancetype)initWithValues: (const float [16])values +{ + self = [super init]; + + memcpy(_values, values, 16 * sizeof(float)); + + return self; +} + +- (float *)values +{ + return _values; +} + +- (bool)isEqual: (OF4x4Matrix *)matrix +{ + if (![matrix isKindOfClass: [OF4x4Matrix class]]) + return false; + + return (memcmp(_values, matrix->_values, 16 * sizeof(float)) == 0); +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + for (size_t i = 0; i < 16; i++) + OFHashAddHash(&hash, OFFloatToRawUInt32(_values[i])); + + OFHashFinalize(&hash); + + return hash; +} + +- (void)transpose +{ + float copy[16]; + memcpy(copy, _values, 16 * sizeof(float)); + + _values[1] = copy[4]; + _values[2] = copy[8]; + _values[3] = copy[12]; + _values[4] = copy[1]; + _values[6] = copy[9]; + _values[7] = copy[13]; + _values[8] = copy[2]; + _values[9] = copy[6]; + _values[11] = copy[14]; + _values[12] = copy[3]; + _values[13] = copy[7]; + _values[14] = copy[11]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"", + _values[0], _values[4], _values[8], _values[12], + _values[1], _values[5], _values[9], _values[13], + _values[2], _values[6], _values[10], _values[14], + _values[3], _values[7], _values[11], _values[15]]; +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -126,10 +126,12 @@ #import "OFSystemInfo.h" #import "OFLocale.h" #import "OFOptionsParser.h" #import "OFTimer.h" #import "OFRunLoop.h" + +#import "OF4x4Matrix.h" #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -11,10 +11,11 @@ DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ + OF4x4MatrixTests.m \ OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ OFCharacterSetTests.m \ OFDataTests.m \ OFDateTests.m \ ADDED tests/OF4x4MatrixTests.m Index: tests/OF4x4MatrixTests.m ================================================================== --- tests/OF4x4MatrixTests.m +++ tests/OF4x4MatrixTests.m @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2021 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. 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 "config.h" + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OF4x4MatrixTests"; + +@implementation TestsAppDelegate (OF4x4MatrixTests) +- (void)_4x4MatrixTests +{ + void *pool = objc_autoreleasePoolPush(); + OF4x4Matrix *matrix; + + TEST(@"+[identity]", + memcmp([[OF4x4Matrix identity] values], (float [16]){ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + }, 16 * sizeof(float)) == 0) + + TEST(@"+[matrixWithValues:]", + (matrix = [OF4x4Matrix matrixWithValues: (float [16]){ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16 + }])) + + TEST(@"-[description]", + [matrix.description isEqual: @""]) + + TEST(@"-[transpose]", + R([matrix transpose]) && memcmp(matrix.values, (float [16]){ + 1, 5, 9, 13, + 2, 6, 10, 14, + 3, 7, 11, 15, + 4, 8, 12, 16 + }, 16 * sizeof(float)) == 0) + + TEST(@"-[isEqual:]", [[OF4x4Matrix identity] isEqual: + [OF4x4Matrix matrixWithValues: (float [16]){ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + }]]) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -56,10 +56,14 @@ - (void)outputTesting: (OFString *)test inModule: (OFString *)module; - (void)outputSuccess: (OFString *)test inModule: (OFString *)module; - (void)outputFailure: (OFString *)test inModule: (OFString *)module; @end + +@interface TestsAppDelegate (OF4x4MatrixTests) +- (void)_4x4MatrixTests; +@end @interface TestsAppDelegate (OFArrayTests) - (void)arrayTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -374,10 +374,12 @@ #ifdef OF_HAVE_FILES [self serializationTests]; #endif [self JSONTests]; [self propertyListTests]; + [self _4x4MatrixTests]; + #if defined(OF_HAVE_PLUGINS) [self pluginTests]; #endif #ifdef OF_WINDOWS [self windowsRegistryKeyTests];