PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/HelloOpenGL/HelloOpenGL/CC3GLMatrix.m

https://gitlab.com/praveenvelanati/ios-demo
Objective C | 1045 lines | 749 code | 173 blank | 123 comment | 79 complexity | 976c863b4776d6fdfad2395617d9ffd8 MD5 | raw file
  1. /*
  2. * CC3GLMatrix.m
  3. *
  4. * $Version: cocos3d 0.5.4 (f5cd4df5048c) on 2011-04-14 $
  5. * Author: Bill Hollings
  6. * Copyright (c) 2010-2011 The Brenwill Workshop Ltd. All rights reserved.
  7. * http://www.brenwill.com
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. * http://en.wikipedia.org/wiki/MIT_License
  28. *
  29. * See header file CC3GLMatrix.h for full API documentation.
  30. */
  31. #import "CC3GLMatrix.h"
  32. #import "CC3Math.h"
  33. #import "CC3Kazmath.h"
  34. #pragma mark CC3Matrix private method declaration
  35. @interface CC3GLMatrix (Private)
  36. -(id) initParent;
  37. -(id) initWithFirstElement: (GLfloat) e00 remainingElements: (va_list) args;
  38. -(void) swap: (GLuint) idx1 with: (GLuint) idx2;
  39. +(void) swap: (GLuint) idx1 with: (GLuint) idx2 inMatrix: (GLfloat*) aGLMatrix;
  40. @end
  41. #pragma mark -
  42. #pragma mark CC3ArrayMatrix class cluster implementation class
  43. @interface CC3GLArrayMatrix : CC3GLMatrix {
  44. GLfloat glArray[16];
  45. }
  46. @end
  47. @implementation CC3GLArrayMatrix
  48. -(GLfloat*) glMatrix {
  49. return glArray;
  50. }
  51. @end
  52. #pragma mark -
  53. #pragma mark CC3GLPointerMatrix class cluster implementation class
  54. @interface CC3GLPointerMatrix : CC3GLMatrix {
  55. GLfloat* glMatrix;
  56. }
  57. @end
  58. @implementation CC3GLPointerMatrix
  59. -(GLfloat*) glMatrix {
  60. return glMatrix;
  61. }
  62. -(id) initOnGLMatrix: (GLfloat*) aGLMtx {
  63. if ( (self = [self initParent]) ) {
  64. glMatrix = aGLMtx;
  65. }
  66. return self;
  67. }
  68. @end
  69. #pragma mark -
  70. #pragma mark CC3Matrix implementation
  71. @implementation CC3GLMatrix
  72. @synthesize isIdentity;
  73. /**
  74. * Abstract class simply returns NULL.
  75. * Subclasses will provide concrete access to the appropriate structure.
  76. */
  77. -(GLfloat*) glMatrix {
  78. return NULL;
  79. }
  80. #pragma mark Allocation and initialization
  81. -(id) initParent {
  82. return [super init];
  83. }
  84. -(id) init {
  85. if ( [self isKindOfClass: [CC3GLArrayMatrix class]] ) {
  86. if( (self = [self initParent]) ) {
  87. [self populateZero];
  88. }
  89. return self;
  90. } else {
  91. [self release];
  92. return [[CC3GLArrayMatrix alloc] init];
  93. }
  94. }
  95. +(id) matrix {
  96. if ( [self isSubclassOfClass: [CC3GLArrayMatrix class]] ) {
  97. return [[[self alloc] init] autorelease];
  98. } else {
  99. return [CC3GLArrayMatrix matrix];
  100. }
  101. }
  102. -(id) initIdentity {
  103. if ( [self isKindOfClass: [CC3GLArrayMatrix class]] ) {
  104. if( (self = [self initParent]) ) {
  105. [self populateIdentity];
  106. }
  107. return self;
  108. } else {
  109. [self release];
  110. return [[CC3GLArrayMatrix alloc] initIdentity];
  111. }
  112. }
  113. +(id) identity {
  114. if ( [self isSubclassOfClass: [CC3GLArrayMatrix class]] ) {
  115. return [[[self alloc] initIdentity] autorelease];
  116. } else {
  117. return [CC3GLArrayMatrix identity];
  118. }
  119. }
  120. -(id) initFromGLMatrix: (GLfloat*) aGLMtx {
  121. if ( [self isKindOfClass: [CC3GLArrayMatrix class]] ) {
  122. if( (self = [self initParent]) ) {
  123. [self populateFromGLMatrix: aGLMtx];
  124. }
  125. return self;
  126. } else {
  127. [self release];
  128. return [[CC3GLArrayMatrix alloc] initFromGLMatrix: aGLMtx];
  129. }
  130. }
  131. +(id) matrixFromGLMatrix: (GLfloat*) aGLMtx {
  132. if ( [self isSubclassOfClass: [CC3GLArrayMatrix class]] ) {
  133. return [[[self alloc] initFromGLMatrix: aGLMtx] autorelease];
  134. } else {
  135. return [CC3GLArrayMatrix matrixFromGLMatrix: aGLMtx];
  136. }
  137. }
  138. -(id) initWithFirstElement: (GLfloat) e00 remainingElements: (va_list) args {
  139. if ( [self isKindOfClass: [CC3GLArrayMatrix class]] ) {
  140. if( (self = [self initParent]) ) {
  141. GLfloat* p = self.glMatrix;
  142. *p++ = e00;
  143. for (int i = 1; i < 16; i++) {
  144. *p++ = (GLfloat)va_arg(args, double);
  145. }
  146. }
  147. } else {
  148. [self release];
  149. self = [[CC3GLArrayMatrix alloc] initWithFirstElement: e00 remainingElements: args];
  150. }
  151. return self;
  152. }
  153. -(id) initWithElements: (GLfloat) e00, ... {
  154. va_list args;
  155. va_start(args, e00);
  156. self = [self initWithFirstElement: e00 remainingElements: args];
  157. va_end(args);
  158. return self;
  159. }
  160. +(id) matrixWithElements: (GLfloat) e00, ... {
  161. va_list args;
  162. va_start(args, e00);
  163. CC3GLMatrix* mtx = [[CC3GLArrayMatrix alloc] initWithFirstElement: e00 remainingElements: args];
  164. va_end(args);
  165. return [mtx autorelease];
  166. }
  167. -(id) initOnGLMatrix: (GLfloat*) aGLMtx {
  168. [self release];
  169. return [[CC3GLPointerMatrix alloc] initOnGLMatrix: aGLMtx];
  170. }
  171. +(id) matrixOnGLMatrix: (GLfloat*) aGLMtx {
  172. if ( [self isSubclassOfClass: [CC3GLPointerMatrix class]] ) {
  173. return [[[self alloc] initOnGLMatrix: aGLMtx] autorelease];
  174. } else {
  175. return [CC3GLPointerMatrix matrixOnGLMatrix: aGLMtx];
  176. }
  177. }
  178. - (id) copyWithZone: (NSZone*) zone {
  179. return [[CC3GLArrayMatrix matrixFromGLMatrix: self.glMatrix] retain];
  180. }
  181. -(NSString*) description {
  182. GLfloat* m = self.glMatrix;
  183. NSMutableString* desc = [NSMutableString stringWithCapacity: 200];
  184. [desc appendFormat: @"\n\t[%.3f, ", m[0]];
  185. [desc appendFormat: @"%.3f, ", m[4]];
  186. [desc appendFormat: @"%.3f, ", m[8]];
  187. [desc appendFormat: @"%.3f,\n\t ", m[12]];
  188. [desc appendFormat: @"%.3f, ", m[1]];
  189. [desc appendFormat: @"%.3f, ", m[5]];
  190. [desc appendFormat: @"%.3f, ", m[9]];
  191. [desc appendFormat: @"%.3f,\n\t ", m[13]];
  192. [desc appendFormat: @"%.3f, ", m[2]];
  193. [desc appendFormat: @"%.3f, ", m[6]];
  194. [desc appendFormat: @"%.3f, ", m[10]];
  195. [desc appendFormat: @"%.3f,\n\t ", m[14]];
  196. [desc appendFormat: @"%.3f, ", m[3]];
  197. [desc appendFormat: @"%.3f, ", m[7]];
  198. [desc appendFormat: @"%.3f, ", m[11]];
  199. [desc appendFormat: @"%.3f]", m[15]];
  200. return desc;
  201. }
  202. #pragma mark -
  203. #pragma mark Instance population
  204. static const GLfloat identityContents[] = { 1.0f, 0.0f, 0.0f, 0.0f,
  205. 0.0f, 1.0f, 0.0f, 0.0f,
  206. 0.0f, 0.0f, 1.0f, 0.0f,
  207. 0.0f, 0.0f, 0.0f, 1.0f };
  208. -(void) populateFrom: (CC3GLMatrix*) aMtx {
  209. if (aMtx.isIdentity) {
  210. [self populateIdentity];
  211. } else {
  212. [self populateFromGLMatrix: aMtx.glMatrix];
  213. }
  214. }
  215. -(void) populateFromGLMatrix: (GLfloat*) aGLMtx {
  216. [[self class] copyMatrix: aGLMtx into: self.glMatrix];
  217. isIdentity = NO;
  218. }
  219. -(void) populateZero {
  220. memset(self.glMatrix, 0, 16 * sizeof(GLfloat));
  221. isIdentity = NO;
  222. }
  223. -(void) populateIdentity {
  224. if (!isIdentity) {
  225. [[self class] copyMatrix: (GLfloat*)identityContents into: self.glMatrix];
  226. isIdentity = YES;
  227. }
  228. }
  229. -(void) populateFromTranslation: (CC3Vector) aVector {
  230. /*
  231. | 1 0 0 x |
  232. M = | 0 1 0 y |
  233. | 0 0 1 z |
  234. | 0 0 0 1 |
  235. */
  236. // Start with identity, then if the vector is not zero,
  237. // add the translation components, and mark not identity.
  238. [self populateIdentity];
  239. if (!CC3VectorsAreEqual(aVector, kCC3VectorZero)) {
  240. GLfloat* m = self.glMatrix;
  241. m[12] = aVector.x;
  242. m[13] = aVector.y;
  243. m[14] = aVector.z;
  244. isIdentity = NO;
  245. }
  246. }
  247. -(void) populateFromRotation: (CC3Vector) aVector {
  248. if (CC3VectorsAreEqual(aVector, kCC3VectorZero)) {
  249. [self populateIdentity];
  250. } else {
  251. CC3Vector rotRads = CC3VectorScaleUniform(aVector, DegreesToRadiansFactor);
  252. kmMat4RotationYXZ((kmMat4*)self.glMatrix, rotRads.x, rotRads.y, rotRads.z);
  253. isIdentity = NO;
  254. }
  255. }
  256. -(void) populateFromQuaternion: (CC3Vector4) aQuaternion {
  257. if (CC3Vector4sAreEqual(aQuaternion, kCC3Vector4QuaternionIdentity)) {
  258. [self populateIdentity];
  259. } else {
  260. kmMat4RotationQuaternion((kmMat4*)self.glMatrix, (kmQuaternion*)&aQuaternion);
  261. isIdentity = NO;
  262. }
  263. }
  264. -(void) populateFromScale: (CC3Vector) aVector {
  265. /*
  266. | x 0 0 0 |
  267. M = | 0 y 0 0 |
  268. | 0 0 z 0 |
  269. | 0 0 0 1 |
  270. */
  271. // Start with identity, then if the vector is not unity,
  272. // add the scale components, and mark not identity.
  273. [self populateIdentity];
  274. if (!CC3VectorsAreEqual(aVector, kCC3VectorUnitCube)) {
  275. GLfloat* m = self.glMatrix;
  276. m[0] = aVector.x;
  277. m[5] = aVector.y;
  278. m[10] = aVector.z;
  279. isIdentity = NO;
  280. }
  281. }
  282. -(void) populateToPointTowards: (CC3Vector) fwdDirection withUp: (CC3Vector) upDirection {
  283. [[self class] populate: self.glMatrix toPointTowards: fwdDirection withUp: upDirection];
  284. isIdentity = NO;
  285. }
  286. -(void) populateToLookAt: (CC3Vector) targetLocation
  287. withEyeAt: (CC3Vector) eyeLocation
  288. withUp: (CC3Vector) upDirection {
  289. [[self class] populate: self.glMatrix
  290. toLookAt: targetLocation
  291. withEyeAt: eyeLocation
  292. withUp: upDirection];
  293. isIdentity = NO;
  294. }
  295. -(void) populateFromFrustumLeft: (GLfloat) left
  296. andRight: (GLfloat) right
  297. andBottom: (GLfloat) bottom
  298. andTop: (GLfloat) top
  299. andNear: (GLfloat) near
  300. andFar: (GLfloat) far {
  301. [[self class] populate: self.glMatrix
  302. fromFrustumLeft: left andRight: right
  303. andBottom: bottom andTop: top
  304. andNear: near andFar: far];
  305. isIdentity = NO;
  306. }
  307. -(void) populateOrthoFromFrustumLeft: (GLfloat) left
  308. andRight: (GLfloat) right
  309. andBottom: (GLfloat) bottom
  310. andTop: (GLfloat) top
  311. andNear: (GLfloat) near
  312. andFar: (GLfloat) far {
  313. [[self class] populateOrtho: self.glMatrix
  314. fromFrustumLeft: left andRight: right
  315. andBottom: bottom andTop: top
  316. andNear: near andFar: far];
  317. isIdentity = NO;
  318. }
  319. #pragma mark Matrix population
  320. +(void) copyMatrix: (GLfloat*) srcGLMatrix into: (GLfloat*) destGLMatrix {
  321. memcpy(destGLMatrix, srcGLMatrix, 16 * sizeof(GLfloat));
  322. }
  323. +(void) populate: (GLfloat*) aGLMatrix toPointTowards: (CC3Vector) fwdDirection withUp: (CC3Vector) upDirection {
  324. /*
  325. | rx ux -fx 0 |
  326. M = | ry uy -fy 0 |
  327. | rz uz -fz 0 |
  328. | 0 0 0 1 |
  329. where f is the normalized Forward vector (the direction being pointed to)
  330. and u is the normalized Up vector in the rotated frame
  331. and r is the normalized Right vector in the rotated frame
  332. */
  333. CC3Vector f, u, r;
  334. f = CC3VectorNormalize(fwdDirection);
  335. r = CC3VectorNormalize(CC3VectorCross(f, upDirection));
  336. u = CC3VectorCross(r, f); // already normalized since f & r are orthonormal
  337. aGLMatrix[0] = r.x;
  338. aGLMatrix[1] = r.y;
  339. aGLMatrix[2] = r.z;
  340. aGLMatrix[3] = 0.0;
  341. aGLMatrix[4] = u.x;
  342. aGLMatrix[5] = u.y;
  343. aGLMatrix[6] = u.z;
  344. aGLMatrix[7] = 0.0;
  345. aGLMatrix[8] = -f.x;
  346. aGLMatrix[9] = -f.y;
  347. aGLMatrix[10] = -f.z;
  348. aGLMatrix[11] = 0.0;
  349. aGLMatrix[12] = 0.0;
  350. aGLMatrix[13] = 0.0;
  351. aGLMatrix[14] = 0.0;
  352. aGLMatrix[15] = 1.0;
  353. }
  354. +(void) populate: (GLfloat*) aGLMatrix
  355. toLookAt: (CC3Vector) targetLocation
  356. withEyeAt: (CC3Vector) eyeLocation
  357. withUp: (CC3Vector) upDirection {
  358. CC3Vector fwdDir = CC3VectorDifference(targetLocation, eyeLocation);
  359. [self populate: aGLMatrix toPointTowards: fwdDir withUp: upDirection];
  360. [self transpose: aGLMatrix];
  361. [self translate: aGLMatrix by: CC3VectorNegate(eyeLocation)];
  362. }
  363. +(void) populate: (GLfloat*) aGLMatrix
  364. fromFrustumLeft: (GLfloat) left
  365. andRight: (GLfloat) right
  366. andBottom: (GLfloat) bottom
  367. andTop: (GLfloat) top
  368. andNear: (GLfloat) near
  369. andFar: (GLfloat) far {
  370. aGLMatrix[0] = (2.0 * near) / (right - left);
  371. aGLMatrix[1] = 0.0;
  372. aGLMatrix[2] = 0.0;
  373. aGLMatrix[3] = 0.0;
  374. aGLMatrix[4] = 0.0;
  375. aGLMatrix[5] = (2.0 * near) / (top - bottom);
  376. aGLMatrix[6] = 0.0;
  377. aGLMatrix[7] = 0.0;
  378. aGLMatrix[8] = (right + left) / (right - left);
  379. aGLMatrix[9] = (top + bottom) / (top - bottom);
  380. aGLMatrix[10] = -(far + near) / (far - near);
  381. aGLMatrix[11] = -1.0;
  382. aGLMatrix[12] = 0.0;
  383. aGLMatrix[13] = 0.0;
  384. aGLMatrix[14] = -(2.0 * far * near) / (far - near);
  385. aGLMatrix[15] = 0.0;
  386. }
  387. +(void) populateOrtho: (GLfloat*) aGLMatrix
  388. fromFrustumLeft: (GLfloat) left
  389. andRight: (GLfloat) right
  390. andBottom: (GLfloat) bottom
  391. andTop: (GLfloat) top
  392. andNear: (GLfloat) near
  393. andFar: (GLfloat) far {
  394. aGLMatrix[0] = 2.0 / (right - left);
  395. aGLMatrix[1] = 0.0;
  396. aGLMatrix[2] = 0.0;
  397. aGLMatrix[3] = 0.0;
  398. aGLMatrix[4] = 0.0;
  399. aGLMatrix[5] = 2.0 / (top - bottom);
  400. aGLMatrix[6] = 0.0;
  401. aGLMatrix[7] = 0.0;
  402. aGLMatrix[8] = 0.0;
  403. aGLMatrix[9] = 0.0;
  404. aGLMatrix[10] = -2.0 / (far - near);
  405. aGLMatrix[11] = 0.0;
  406. aGLMatrix[12] = -(right + left) / (right - left);
  407. aGLMatrix[13] = -(top + bottom) / (top - bottom);
  408. aGLMatrix[14] = -(far + near) / (far - near);
  409. aGLMatrix[15] = 1.0;
  410. }
  411. #pragma mark -
  412. #pragma mark Instance accessing
  413. // CAUTION: This is a simple convenience utility. For speed, it does not honour
  414. // the isIdentity flag. It is the responsibility of the caller to deal with that flag.
  415. -(void) swap: (GLuint) idx1 with: (GLuint) idx2 {
  416. [[self class] swap: idx1 with: idx2 inMatrix: self.glMatrix];
  417. }
  418. -(CC3Vector) extractRotation {
  419. return [[self class] extractRotationYXZFromMatrix: self.glMatrix];
  420. }
  421. -(CC3Vector4) extractQuaternion {
  422. return [[self class] extractQuaternionFromMatrix: self.glMatrix];
  423. }
  424. -(CC3Vector) extractForwardDirection {
  425. return [[self class] extractForwardDirectionFrom: self.glMatrix];
  426. }
  427. -(CC3Vector) extractUpDirection {
  428. return [[self class] extractUpDirectionFrom: self.glMatrix];
  429. }
  430. -(CC3Vector) extractRightDirection {
  431. return [[self class] extractRightDirectionFrom: self.glMatrix];
  432. }
  433. #pragma mark Matrix accessing
  434. +(void) swap: (GLuint) idx1 with: (GLuint) idx2 inMatrix: (GLfloat*) aGLMatrix {
  435. GLfloat tmp = aGLMatrix[idx1];
  436. aGLMatrix[idx1] = aGLMatrix[idx2];
  437. aGLMatrix[idx2] = tmp;
  438. }
  439. // Assumes YXZ euler order, which is the OpenGL ES default
  440. +(CC3Vector) extractRotationYXZFromMatrix: (GLfloat*) aGLMatrix {
  441. /*
  442. | cycz + sxsysz czsxsy - cysz cxsy 0 |
  443. M = | cxsz cxcz -sx 0 |
  444. | cysxsz - czsy cyczsx + sysz cxcy 0 |
  445. | 0 0 0 1 |
  446. where cA = cos(A), sA = sin(A) for A = x,y,z
  447. */
  448. GLfloat radX, radY, radZ;
  449. GLfloat cxsz = aGLMatrix[1];
  450. GLfloat cxcz = aGLMatrix[5];
  451. GLfloat sx = -aGLMatrix[9];
  452. GLfloat cxsy = aGLMatrix[8];
  453. GLfloat cxcy = aGLMatrix[10];
  454. if (sx < +1.0) {
  455. if (sx > -1.0) {
  456. radX = asin(sx);
  457. radY = atan2(cxsy, cxcy);
  458. radZ = atan2(cxsz, cxcz);
  459. }
  460. else { // sx = -1. Not a unique solution: radZ + radY = atan2(-m01,m00).
  461. radX = -M_PI_2;
  462. radY = atan2(-aGLMatrix[4], aGLMatrix[0]);
  463. radZ = 0.0;
  464. }
  465. }
  466. else { // sx = +1. Not a unique solution: radZ - radY = atan2(-m01,m00).
  467. radX = +M_PI_2;
  468. radY = -atan2(-aGLMatrix[4], aGLMatrix[0]);
  469. radZ = 0.0;
  470. }
  471. return cc3v(RadiansToDegrees(radX), RadiansToDegrees(radY), RadiansToDegrees(radZ));
  472. }
  473. // Assumes ZYX euler order
  474. +(CC3Vector) extractRotationZYXFromMatrix: (GLfloat*) aGLMatrix {
  475. /*
  476. | cycz -cxsz + sxsycz sxsz + cxsycz 0 |
  477. M = | cysz cxcz + sxsysz -sxcz + cxsysz 0 |
  478. | -sy sxcy cxcy 0 |
  479. | 0 0 0 1 |
  480. where cA = cos(A), sA = sin(A) for A = x,y,z
  481. */
  482. GLfloat radX, radY, radZ;
  483. GLfloat cycz = aGLMatrix[0];
  484. GLfloat cysz = aGLMatrix[1];
  485. GLfloat sy = -aGLMatrix[2];
  486. GLfloat sxcy = aGLMatrix[6];
  487. GLfloat cxcy = aGLMatrix[10];
  488. if (sy < +1.0) {
  489. if (sy > -1.0) {
  490. radY = asin(sy);
  491. radZ = atan2(cysz, cycz);
  492. radX = atan2(sxcy, cxcy);
  493. }
  494. else { // sy = -1. Not a unique solution: radX + radZ = atan2(-m12,m11).
  495. radY = -M_PI_2;
  496. radZ = atan2(-aGLMatrix[9], aGLMatrix[5]);
  497. radX = 0.0;
  498. }
  499. }
  500. else { // sy = +1. Not a unique solution: radX - radZ = atan2(-m12,m11).
  501. radY = +M_PI_2;
  502. radZ = -atan2(-aGLMatrix[9], aGLMatrix[5]);
  503. radX = 0.0;
  504. }
  505. return cc3v(RadiansToDegrees(radX), RadiansToDegrees(radY), RadiansToDegrees(radZ));
  506. }
  507. +(CC3Vector4) extractQuaternionFromMatrix: (GLfloat*) aGLMatrix {
  508. CC3Vector4 quaternion;
  509. kmQuaternionRotationMatrix((kmQuaternion*)&quaternion, (kmMat4*)aGLMatrix);
  510. return quaternion;
  511. }
  512. +(CC3Vector) extractForwardDirectionFrom: (GLfloat*) aGLMatrix {
  513. return cc3v(-aGLMatrix[8], -aGLMatrix[9], -aGLMatrix[10]);
  514. }
  515. +(CC3Vector) extractUpDirectionFrom: (GLfloat*) aGLMatrix {
  516. return cc3v(aGLMatrix[4], aGLMatrix[5], aGLMatrix[6]);
  517. }
  518. +(CC3Vector) extractRightDirectionFrom: (GLfloat*) aGLMatrix {
  519. return cc3v(aGLMatrix[0], aGLMatrix[1], aGLMatrix[2]);
  520. }
  521. #pragma mark -
  522. #pragma mark Instance transformations
  523. -(void) translateBy: (CC3Vector) translationVector
  524. rotateBy: (CC3Vector) rotationVector
  525. scaleBy: (CC3Vector) scaleVector {
  526. // if not ALL identity transforms, transform this matrix
  527. if ( !(CC3VectorsAreEqual(translationVector, kCC3VectorZero) &&
  528. CC3VectorsAreEqual(rotationVector, kCC3VectorZero) &&
  529. CC3VectorsAreEqual(scaleVector, kCC3VectorUnitCube)) ) {
  530. [[self class] transform: self.glMatrix
  531. translateBy: translationVector
  532. rotateBy: rotationVector
  533. scaleBy: scaleVector];
  534. isIdentity = NO;
  535. }
  536. }
  537. -(void) translateBy: (CC3Vector) aVector {
  538. // Short-circuit an identity transform
  539. if ( !CC3VectorsAreEqual(aVector, kCC3VectorZero) ) {
  540. [[self class] translate: self.glMatrix by: aVector];
  541. isIdentity = NO;
  542. }
  543. }
  544. -(void) translateByX: (GLfloat) distance {
  545. // Short-circuit an identity transform
  546. if ( distance != 0.0f ) {
  547. [[self class] translate: self.glMatrix byX: distance];
  548. isIdentity = NO;
  549. }
  550. }
  551. -(void) translateByY: (GLfloat) distance {
  552. // Short-circuit an identity transform
  553. if ( distance != 0.0f ) {
  554. [[self class] translate: self.glMatrix byY: distance];
  555. isIdentity = NO;
  556. }
  557. }
  558. -(void) translateByZ: (GLfloat) distance {
  559. // Short-circuit an identity transform
  560. if ( distance != 0.0f ) {
  561. [[self class] translate: self.glMatrix byZ: distance];
  562. isIdentity = NO;
  563. }
  564. }
  565. -(void) rotateBy: (CC3Vector) aVector {
  566. // Short-circuit an identity transform
  567. if ( !CC3VectorsAreEqual(aVector, kCC3VectorZero) ) {
  568. [[self class] rotateYXZ: self.glMatrix by: aVector];
  569. isIdentity = NO;
  570. }
  571. }
  572. -(void) rotateByX: (GLfloat) degrees {
  573. // Short-circuit an identity transform
  574. if ( degrees != 0.0f ) {
  575. [[self class] rotate: self.glMatrix byX: degrees];
  576. isIdentity = NO;
  577. }
  578. }
  579. -(void) rotateByY: (GLfloat) degrees {
  580. // Short-circuit an identity transform
  581. if ( degrees != 0.0f ) {
  582. [[self class] rotate: self.glMatrix byY: degrees];
  583. isIdentity = NO;
  584. }
  585. }
  586. -(void) rotateByZ: (GLfloat) degrees {
  587. // Short-circuit an identity transform
  588. if ( degrees != 0.0f ) {
  589. [[self class] rotate: self.glMatrix byZ: degrees];
  590. isIdentity = NO;
  591. }
  592. }
  593. -(void) rotateByQuaternion: (CC3Vector4) aQuaternion {
  594. // Short-circuit an identity transform
  595. if ( !CC3Vector4sAreEqual(aQuaternion, kCC3Vector4QuaternionIdentity) ) {
  596. [[self class] rotate: self.glMatrix byQuaternion: aQuaternion];
  597. isIdentity = NO;
  598. }
  599. }
  600. -(void) scaleBy: (CC3Vector) aVector {
  601. // Short-circuit an identity transform
  602. if ( !CC3VectorsAreEqual(aVector, kCC3VectorUnitCube) ) {
  603. [[self class] scale: self.glMatrix by: aVector];
  604. isIdentity = NO;
  605. }
  606. }
  607. -(void) scaleByX: (GLfloat) scaleFactor {
  608. // Short-circuit an identity transform
  609. if ( scaleFactor != 1.0f ) {
  610. [[self class] scale: self.glMatrix byX: scaleFactor];
  611. isIdentity = NO;
  612. }
  613. }
  614. -(void) scaleByY: (GLfloat) scaleFactor {
  615. // Short-circuit an identity transform
  616. if ( scaleFactor != 1.0f ) {
  617. [[self class] scale: self.glMatrix byY: scaleFactor];
  618. isIdentity = NO;
  619. }
  620. }
  621. -(void) scaleByZ: (GLfloat) scaleFactor {
  622. // Short-circuit an identity transform
  623. if ( scaleFactor != 1.0f ) {
  624. [[self class] scale: self.glMatrix byZ: scaleFactor];
  625. isIdentity = NO;
  626. }
  627. }
  628. -(void) scaleUniformlyBy: (GLfloat) scaleFactor {
  629. // Short-circuit an identity transform
  630. if ( scaleFactor != 1.0f ) {
  631. [[self class] scale: self.glMatrix uniformlyBy: scaleFactor];
  632. isIdentity = NO;
  633. }
  634. }
  635. #pragma mark Matrix transformations
  636. +(void) transform: (GLfloat*) aGLMatrix
  637. translateBy: (CC3Vector) translationVector
  638. rotateBy: (CC3Vector) rotationVector
  639. scaleBy: (CC3Vector) scaleVector {
  640. kmVec3 kmTranslation = kmVec3Make(translationVector.x, translationVector.y, translationVector.z);
  641. kmVec3 kmRotation = kmVec3Make(DegreesToRadians(rotationVector.x),
  642. DegreesToRadians(rotationVector.y),
  643. DegreesToRadians(rotationVector.z));
  644. kmVec3 kmScale = kmVec3Make(scaleVector.x, scaleVector.y, scaleVector.z);
  645. kmMat4 mXfm;
  646. kmMat4Transformation(&mXfm, kmTranslation, kmRotation, kmScale);
  647. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mXfm];
  648. }
  649. +(void) rotateYXZ: (GLfloat*) aGLMatrix by: (CC3Vector) aVector {
  650. kmMat4 mRot;
  651. CC3Vector rotRads = CC3VectorScaleUniform(aVector, DegreesToRadiansFactor);
  652. kmMat4RotationYXZ(&mRot, rotRads.x, rotRads.y, rotRads.z);
  653. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mRot];
  654. }
  655. +(void) rotateZYX: (GLfloat*) aGLMatrix by: (CC3Vector) aVector {
  656. kmMat4 mRot;
  657. CC3Vector rotRads = CC3VectorScaleUniform(aVector, DegreesToRadiansFactor);
  658. kmMat4RotationZYX(&mRot, rotRads.x, rotRads.y, rotRads.z);
  659. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mRot];
  660. }
  661. +(void) rotate: (GLfloat*) aGLMatrix byX: (GLfloat) degrees {
  662. kmMat4 mRot;
  663. kmMat4RotationX(&mRot, DegreesToRadians(degrees));
  664. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mRot];
  665. }
  666. +(void) rotate: (GLfloat*) aGLMatrix byY: (GLfloat) degrees {
  667. kmMat4 mRot;
  668. kmMat4RotationY(&mRot, DegreesToRadians(degrees));
  669. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mRot];
  670. }
  671. +(void) rotate: (GLfloat*) aGLMatrix byZ: (GLfloat) degrees {
  672. kmMat4 mRot;
  673. kmMat4RotationZ(&mRot, DegreesToRadians(degrees));
  674. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mRot];
  675. }
  676. +(void) rotate: (GLfloat*) aGLMatrix byQuaternion: (CC3Vector4) aQuaternion {
  677. kmMat4 mRot;
  678. kmMat4RotationQuaternion(&mRot, (kmQuaternion*)&aQuaternion);
  679. [self multiply: aGLMatrix byMatrix: (GLfloat*)&mRot];
  680. }
  681. +(void) translate: (GLfloat*) aGLMatrix by: (CC3Vector) aVector {
  682. GLfloat* m = aGLMatrix; // Make a simple alias
  683. m[12] = aVector.x * m[0] + aVector.y * m[4] + aVector.z * m[8] + m[12];
  684. m[13] = aVector.x * m[1] + aVector.y * m[5] + aVector.z * m[9] + m[13];
  685. m[14] = aVector.x * m[2] + aVector.y * m[6] + aVector.z * m[10] + m[14];
  686. m[15] = aVector.x * m[3] + aVector.y * m[7] + aVector.z * m[11] + m[15];
  687. }
  688. +(void) translate: (GLfloat*) aGLMatrix byX: (GLfloat) distance {
  689. [self translate: aGLMatrix by: cc3v(distance, 0.0, 0.0)];
  690. }
  691. +(void) translate: (GLfloat*) aGLMatrix byY: (GLfloat) distance {
  692. [self translate: aGLMatrix by: cc3v(0.0, distance, 0.0)];
  693. }
  694. +(void) translate: (GLfloat*) aGLMatrix byZ: (GLfloat) distance {
  695. [self translate: aGLMatrix by: cc3v(0.0, 0.0, distance)];
  696. }
  697. +(void) scale: (GLfloat*) aGLMatrix by: (CC3Vector) aVector {
  698. GLfloat* m = aGLMatrix; // Make a simple alias
  699. m[0] *= aVector.x;
  700. m[1] *= aVector.x;
  701. m[2] *= aVector.x;
  702. m[3] *= aVector.x;
  703. m[4] *= aVector.y;
  704. m[5] *= aVector.y;
  705. m[6] *= aVector.y;
  706. m[7] *= aVector.y;
  707. m[8] *= aVector.z;
  708. m[9] *= aVector.z;
  709. m[10] *= aVector.z;
  710. m[11] *= aVector.z;
  711. }
  712. +(void) scale: (GLfloat*) aGLMatrix byX: (GLfloat) scaleFactor {
  713. [self scale: aGLMatrix by: cc3v(scaleFactor, 1.0, 1.0)];
  714. }
  715. +(void) scale: (GLfloat*) aGLMatrix byY: (GLfloat) scaleFactor {
  716. [self scale: aGLMatrix by: cc3v(1.0, scaleFactor, 1.0)];
  717. }
  718. +(void) scale: (GLfloat*) aGLMatrix byZ: (GLfloat) scaleFactor {
  719. [self scale: aGLMatrix by: cc3v(1.0, 1.0, scaleFactor)];
  720. }
  721. +(void) scale: (GLfloat*) aGLMatrix uniformlyBy: (GLfloat) scaleFactor {
  722. [self scale: aGLMatrix by: cc3v(scaleFactor, scaleFactor, scaleFactor)];
  723. }
  724. #pragma mark -
  725. #pragma mark Instance math operations
  726. // Includes short-circuits when one of the matrix is an identity matrix
  727. -(void) multiplyByMatrix: (CC3GLMatrix*) aGLMatrix {
  728. // If other matrix is identity, this matrix doesn't change, so leave
  729. if (aGLMatrix.isIdentity) {
  730. return;
  731. }
  732. // If this matrix is identity, it just becomes the other matrix
  733. if (self.isIdentity) {
  734. [self populateFrom: aGLMatrix];
  735. return;
  736. }
  737. // Otherwise, go through with the multiplication
  738. [[self class] multiply: self.glMatrix byMatrix: aGLMatrix.glMatrix];
  739. isIdentity = NO;
  740. }
  741. -(CC3Vector) transformLocation: (CC3Vector) aLocation {
  742. // Short-circuit if this is an identity matrix
  743. if (isIdentity) {
  744. return aLocation;
  745. } else {
  746. return [[self class] transformLocation: aLocation withMatrix: self.glMatrix];
  747. }
  748. }
  749. -(CC3Vector) transformDirection: (CC3Vector) aDirection {
  750. // Short-circuit if this is an identity matrix
  751. if (isIdentity) {
  752. return aDirection;
  753. } else {
  754. return [[self class] transformDirection: aDirection withMatrix: self.glMatrix];
  755. }
  756. }
  757. -(CC3Vector4) transformHomogeneousVector: (CC3Vector4) aVector {
  758. // Short-circuit if this is an identity matrix
  759. if (isIdentity) {
  760. return aVector;
  761. } else {
  762. return [[self class] transformHomogeneousVector: aVector withMatrix: self.glMatrix];
  763. }
  764. }
  765. -(void) transpose {
  766. // Short-circuit if this is an identity matrix
  767. if (!isIdentity) {
  768. [[self class] transpose: self.glMatrix];
  769. }
  770. }
  771. -(BOOL) invert {
  772. // Short-circuit if this is an identity matrix
  773. if (isIdentity) {
  774. return YES;
  775. } else {
  776. return [[self class] invert: self.glMatrix];
  777. }
  778. }
  779. -(BOOL) invertAffine {
  780. // Short-circuit if this is an identity matrix
  781. if (isIdentity) {
  782. return YES;
  783. } else {
  784. return [[self class] invertAffine: self.glMatrix];
  785. }
  786. }
  787. -(void) invertRigid {
  788. // Short-circuit if this is an identity matrix
  789. if (!isIdentity) {
  790. [[self class] invertRigid: self.glMatrix];
  791. }
  792. }
  793. #pragma mark Matrix math operations
  794. +(void) multiply: (GLfloat*) aGLMatrix byMatrix: (GLfloat*) anotherGLMatrix {
  795. kmMat4 mOut;
  796. kmMat4Multiply(&mOut, (kmMat4*)aGLMatrix, (kmMat4*)anotherGLMatrix);
  797. [self copyMatrix: (GLfloat*)&mOut into: aGLMatrix];
  798. }
  799. +(CC3Vector) transformLocation: (CC3Vector) aLocation withMatrix: (GLfloat*) aGLMatrix {
  800. return CC3VectorFromCC3Vector4([self transformHomogeneousVector: CC3Vector4FromCC3Vector(aLocation, 1.0)
  801. withMatrix: aGLMatrix]);
  802. }
  803. +(CC3Vector) transformDirection: (CC3Vector) aDirection withMatrix: (GLfloat*) aGLMatrix {
  804. return CC3VectorFromCC3Vector4([self transformHomogeneousVector: CC3Vector4FromCC3Vector(aDirection, 0.0)
  805. withMatrix: aGLMatrix]);
  806. }
  807. +(CC3Vector4) transformHomogeneousVector: (CC3Vector4) aVector withMatrix: (GLfloat*) aGLMatrix {
  808. CC3Vector4 vOut;
  809. GLfloat* m = aGLMatrix; // Make a simple alias
  810. vOut.x = aVector.x * m[0] + aVector.y * m[4] + aVector.z * m[8] + aVector.w * m[12];
  811. vOut.y = aVector.x * m[1] + aVector.y * m[5] + aVector.z * m[9] + aVector.w * m[13];
  812. vOut.z = aVector.x * m[2] + aVector.y * m[6] + aVector.z * m[10] + aVector.w * m[14];
  813. vOut.w = aVector.x * m[3] + aVector.y * m[7] + aVector.z * m[11] + aVector.w * m[15];
  814. return vOut;
  815. }
  816. +(void) transpose: (GLfloat*) aGLMatrix {
  817. [self swap: 1 with: 4 inMatrix: aGLMatrix];
  818. [self swap: 2 with: 8 inMatrix: aGLMatrix];
  819. [self swap: 3 with: 12 inMatrix: aGLMatrix];
  820. [self swap: 6 with: 9 inMatrix: aGLMatrix];
  821. [self swap: 7 with: 13 inMatrix: aGLMatrix];
  822. [self swap: 11 with: 14 inMatrix: aGLMatrix];
  823. }
  824. +(BOOL) invert: (GLfloat*) aGLMatrix {
  825. kmMat4 inv;
  826. [[self class] copyMatrix: aGLMatrix into: (GLfloat*)&inv];
  827. kmMat4 tmp;
  828. [[self class] copyMatrix: (GLfloat*)identityContents into: (GLfloat*)&tmp];
  829. BOOL wasInverted = kmGaussJordan(&inv, &tmp);
  830. if (wasInverted) {
  831. [[self class] copyMatrix: (GLfloat*)&inv into: aGLMatrix];
  832. }
  833. return wasInverted;
  834. }
  835. +(BOOL) invertAffine: (GLfloat*) aGLMatrix {
  836. /*
  837. M = | L t |
  838. | 0 1 |
  839. where L is a 3x3 linear tranformation matrix, t is a translation vector, and 0 is a row of 3 zeros
  840. */
  841. GLfloat* m = aGLMatrix; // Make a simple alias
  842. BOOL wasInverted = [self invert: m]; // Invert the matrix
  843. m[3] = m[7] = m[11] = 0.0f; // Ensure bottom row are exactly {0, 0, 0, 1}
  844. m[15] = 1.0f;
  845. return wasInverted;
  846. }
  847. +(void) invertRigid: (GLfloat*) aGLMatrix {
  848. /*
  849. M = | RT -RT(t) |
  850. | 0 1 |
  851. where RT is the transposed 3x3 rotation matrix extracted from the 4x4 matrix
  852. and t is a translation vector extracted from the 4x4 matrix
  853. */
  854. GLfloat* m = aGLMatrix; // Make a simple alias
  855. // Extract translation component of matrix and remove it to leave a rotation-only matrix
  856. CC3Vector t = cc3v(m[12], m[13], m[14]);
  857. m[12] = m[13] = m[14] = 0.0f;
  858. // Transpose (invert) rotation matrix
  859. [self transpose: m];
  860. // Transform negated translation with transposed rotation matrix
  861. // and reinsert into transposed matrix
  862. t = [self transformDirection: CC3VectorNegate(t) withMatrix: m];
  863. m[12] = t.x;
  864. m[13] = t.y;
  865. m[14] = t.z;
  866. }
  867. @end