/* * Copyright (c) 2008-2023 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 "OFMatrix4x4.h" #import "OFOnce.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 OFMatrix4x4 *identityMatrix; static void initIdentityMatrix(void) { identityMatrix = [[OFMatrix4x4 alloc] initWithValues: identityValues]; } @implementation OFMatrix4x4 + (void)initialize { if (self != [OFMatrix4x4 class]) return; } + (OFMatrix4x4 *)identityMatrix { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, initIdentityMatrix); return identityMatrix; } + (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; } - (instancetype)copy { return [[OFMatrix4x4 alloc] initWithValues: _values]; } - (bool)isEqual: (OFMatrix4x4 *)matrix { if (![matrix isKindOfClass: [OFMatrix4x4 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)multiplyWithMatrix: (OFMatrix4x4 *)matrix { float r[16], *m = _values, *l = matrix->_values; memcpy(r, m, sizeof(r)); m[ 0] = l[0] * r[ 0] + l[4] * r[ 1] + l[ 8] * r[ 2] + l[12] * r[ 3]; m[ 1] = l[1] * r[ 0] + l[5] * r[ 1] + l[ 9] * r[ 2] + l[13] * r[ 3]; m[ 2] = l[2] * r[ 0] + l[6] * r[ 1] + l[10] * r[ 2] + l[14] * r[ 3]; m[ 3] = l[3] * r[ 0] + l[7] * r[ 1] + l[11] * r[ 2] + l[15] * r[ 3]; m[ 4] = l[0] * r[ 4] + l[4] * r[ 5] + l[ 8] * r[ 6] + l[12] * r[ 7]; m[ 5] = l[1] * r[ 4] + l[5] * r[ 5] + l[ 9] * r[ 6] + l[13] * r[ 7]; m[ 6] = l[2] * r[ 4] + l[6] * r[ 5] + l[10] * r[ 6] + l[14] * r[ 7]; m[ 7] = l[3] * r[ 4] + l[7] * r[ 5] + l[11] * r[ 6] + l[15] * r[ 7]; m[ 8] = l[0] * r[ 8] + l[4] * r[ 9] + l[ 8] * r[10] + l[12] * r[11]; m[ 9] = l[1] * r[ 8] + l[5] * r[ 9] + l[ 9] * r[10] + l[13] * r[11]; m[10] = l[2] * r[ 8] + l[6] * r[ 9] + l[10] * r[10] + l[14] * r[11]; m[11] = l[3] * r[ 8] + l[7] * r[ 9] + l[11] * r[10] + l[15] * r[11]; m[12] = l[0] * r[12] + l[4] * r[13] + l[ 8] * r[14] + l[12] * r[15]; m[13] = l[1] * r[12] + l[5] * r[13] + l[ 9] * r[14] + l[13] * r[15]; m[14] = l[2] * r[12] + l[6] * r[13] + l[10] * r[14] + l[14] * r[15]; m[15] = l[3] * r[12] + l[7] * r[13] + l[11] * r[14] + l[15] * r[15]; } - (void)translateWithVector: (OFVector3D)vector { OFMatrix4x4 *translation = [[OFMatrix4x4 alloc] initWithValues: (float [16]){ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vector.x, vector.y, vector.z, 1 }]; [self multiplyWithMatrix: translation]; [translation release]; } - (void)scaleWithVector: (OFVector3D)vector { OFMatrix4x4 *scale = [[OFMatrix4x4 alloc] initWithValues: (float [16]){ vector.x, 0, 0, 0, 0, vector.y, 0, 0, 0, 0, vector.z, 0, 0, 0, 0, 1 }]; [self multiplyWithMatrix: scale]; [scale release]; } - (OFVector4D)transformedVector: (OFVector4D)vec { float *m = _values; return OFMakeVector4D( m[0] * vec.x + m[4] * vec.y + m[ 8] * vec.z + m[12] * vec.w, m[1] * vec.x + m[5] * vec.y + m[ 9] * vec.z + m[13] * vec.w, m[2] * vec.x + m[6] * vec.y + m[10] * vec.z + m[14] * vec.w, m[3] * vec.x + m[7] * vec.y + m[11] * vec.z + m[15] * vec.w); } - (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