Reputation: 120
I normally pass functions that have arrays in C since Objective-C is a superset of C which makes it easy to change between the two. I wanted to write a specific function in Objective-C though which would pass an array of GLfloats (Yes, I'm using OpenGL) to the function for doing matrix calculations. I tried doing this:
- (void)setIdentity:(GLfloat *)target
{
target[0] = 1;
target[1] = 0;
target[2] = 0;
target[3] = 0;
target[4] = 0;
target[5] = 1;
target[6] = 0;
target[7] = 0;
target[8] = 0;
target[9] = 0;
target[10] = 1;
target[11] = 0;
target[12] = 0;
target[13] = 0;
target[14] = 0;
target[15] = 1;
}
And then tried to pass the Matrix to the function as a 16 entry long GLfloat array using this:
[matrix setIdentity:ModelMat];
//Log the result
NSLog(@"ModelMat:\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f",
ModelMat[0], ModelMat[1], ModelMat[2], ModelMat[3], ModelMat[4], ModelMat[5],
ModelMat[6], ModelMat[7], ModelMat[8], ModelMat[9], ModelMat[10], ModelMat[11],
ModelMat[12], ModelMat[13], ModelMat[14], ModelMat[15]);
Just to make sure that it was returning the proper values but the output was simply a matrix of 0's. What am I doing wrong here?
To better help others understand my problem I am adding the source code for the Scene class that I am trying to set the identity in and the Matrix class where I have the identity, as well as many more matrix related items in it.
Matrix.h
@interface Matrix : NSObject
- (void)copyMatrix:(GLfloat *)from to:(GLfloat *)to;
- (void)setIdentity:(GLfloat *)target;
- (void)multiplyMatrix:(GLfloat *)second by:(GLfloat *)first giving:(GLfloat *)newMatrix;
- (void)applyTranslation:(GLfloat *)source x:(GLfloat)x y:(GLfloat)y z:(GLfloat)z;
- (void)applyScale:(GLfloat *)source x:(GLfloat)x y:(GLfloat)y z:(GLfloat)z;
- (void)applyRotation:(GLfloat *)source pitch:(GLfloat)pitch yaw:(GLfloat)yaw roll:(GLfloat)roll;
- (void)applyRotationWithMag:(GLfloat *)source angle:(GLfloat)angle magX:(GLfloat)magX magY:(GLfloat)magY magZ:(GLfloat)magZ
- (void)setProjection:(GLfloat *)source fov:(GLfloat)fov aspect:(GLfloat)aspect near:(GLfloat)near far:(GLfloat)far;
@end
Matrix.m
#import "Matrix.h"
#define PI 3.1415926535897932384626433832795f
@implementation Matrix
- (void)copyMatrix:(GLfloat *)from to:(GLfloat *)to
{
for(int i = 0; i < 16; i++)
from[i] = to[i];
}
- (void)setIdentity:(GLfloat *)target
{
target[0] = 1;
target[1] = 0;
target[2] = 0;
target[3] = 0;
target[4] = 0;
target[5] = 1;
target[6] = 0;
target[7] = 0;
target[8] = 0;
target[9] = 0;
target[10] = 1;
target[11] = 0;
target[12] = 0;
target[13] = 0;
target[14] = 0;
target[15] = 1;
}
- (void)multiplyMatrix:(GLfloat *)second by:(GLfloat *)first giving:(GLfloat *)newMatrix
{
GLfloat tempMatrix[16];
//Column 1
tempMatrix[0] = (second[0] * first[0]) +
(second[4] * first[1]) +
(second[8] * first[2]) +
(second[12] * first[3]);
tempMatrix[1] = (second[1] * first[0]) +
(second[5] * first[1]) +
(second[9] * first[2]) +
(second[13] * first[3]);
tempMatrix[2] = (second[2] * first[0]) +
(second[6] * first[1]) +
(second[10] * first[2]) +
(second[14] * first[3]);
tempMatrix[3] = (second[3] * first[0]) +
(second[7] * first[1]) +
(second[11] * first[2]) +
(second[15] * first[3]);
//Column 2
tempMatrix[4] = (second[0] * first[4]) +
(second[4] * first[5]) +
(second[8] * first[6]) +
(second[12] * first[7]);
tempMatrix[5] = (second[1] * first[4]) +
(second[5] * first[5]) +
(second[9] * first[6]) +
(second[13] * first[7]);
tempMatrix[6] = (second[2] * first[4]) +
(second[6] * first[5]) +
(second[10] * first[6]) +
(second[14] * first[7]);
tempMatrix[7] = (second[3] * first[4]) +
(second[7] * first[5]) +
(second[11] * first[6]) +
(second[15] * first[7]);
//Column 3
tempMatrix[8] = (second[0] * first[8]) +
(second[4] * first[9]) +
(second[8] * first[10]) +
(second[12] * first[11]);
tempMatrix[9] = (second[1] * first[8]) +
(second[5] * first[9]) +
(second[9] * first[10]) +
(second[13] * first[11]);
tempMatrix[10] = (second[2] * first[8]) +
(second[6] * first[9]) +
(second[10] * first[10]) +
(second[14] * first[11]);
tempMatrix[11] = (second[3] * first[8]) +
(second[7] * first[9]) +
(second[11] * first[10]) +
(second[15] * first[11]);
//Column 4
tempMatrix[12] = (second[0] * first[12]) +
(second[4] * first[13]) +
(second[8] * first[14]) +
(second[12] * first[15]);
tempMatrix[13] = (second[1] * first[12]) +
(second[5] * first[13]) +
(second[9] * first[14]) +
(second[13] * first[15]);
tempMatrix[14] = (second[2] * first[12]) +
(second[6] * first[13]) +
(second[10] * first[14]) +
(second[14] * first[15]);
tempMatrix[15] = (second[3] * first[12]) +
(second[7] * first[13]) +
(second[11] * first[14]) +
(second[15] * first[15]);
[self copyMatrix:tempMatrix to:newMatrix];
}
- (void)applyTranslation:(GLfloat *)source x:(GLfloat)x y:(GLfloat)y z:(GLfloat)z
{
GLfloat tempMatrix[16];
[self setIdentity:tempMatrix];
tempMatrix[12] = x;
tempMatrix[13] = y;
tempMatrix[14] = z;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
- (void)applyScale:(GLfloat *)source x:(GLfloat)x y:(GLfloat)y z:(GLfloat)z
{
GLfloat tempMatrix[16];
[self setIdentity:tempMatrix];
tempMatrix[0] = x;
tempMatrix[5] = y;
tempMatrix[10] = z;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
- (void)applyRotation:(GLfloat *)source pitch:(GLfloat)pitch yaw:(GLfloat)yaw roll:(GLfloat)roll
{
GLfloat tempMatrix[16];
if (pitch != 0) {
GLfloat c = cosf(pitch);
GLfloat s = sinf(pitch);
[self setIdentity:tempMatrix];
tempMatrix[5] = c;
tempMatrix[6] = -s;
tempMatrix[9] = s;
tempMatrix[10] = c;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
if (yaw != 0) {
GLfloat c = cosf(yaw);
GLfloat s = sinf(yaw);
[self setIdentity:tempMatrix];
tempMatrix[0] = c;
tempMatrix[2] = s;
tempMatrix[8] = -s;
tempMatrix[10] = c;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
if (roll != 0) {
GLfloat c = cosf(roll);
GLfloat s = sinf(roll);
[self setIdentity:tempMatrix];
tempMatrix[0] = c;
tempMatrix[1] = -s;
tempMatrix[4] = s;
tempMatrix[5] = c;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
}
- (void)applyRotationWithMag:(GLfloat *)source angle:(GLfloat)angle magX:(GLfloat)magX magY:(GLfloat)magY magZ:(GLfloat)magZ
{
GLfloat tempMatrix[16];
GLfloat sinAngle, cosAngle;
GLfloat magnitude;
magnitude = sqrtf((magX * magX) + (magY * magY) + (magZ * magZ));
sinAngle = sinf(angle * PI / 180.0f);
cosAngle = cosf(angle * PI / 180.0f);
if (magnitude > 0) {
GLfloat xx, yy, zz, xy, xz, yz, xs, ys, zs;
GLfloat oneMinusCos;
magX /= magnitude;
magY /= magnitude;
magZ /= magnitude;
xx = magX * magX;
yy = magY * magY;
zz = magZ * magZ;
xy = magX * magY;
xz = magX * magZ;
yz = magY * magZ;
xs = magX * sinAngle;
ys = magY * sinAngle;
zs = magZ * sinAngle;
oneMinusCos = 1 - cosAngle;
tempMatrix[0] = (oneMinusCos * xx) + cosAngle;
tempMatrix[1] = (oneMinusCos * xy) - zs;
tempMatrix[2] = (oneMinusCos * xz) + ys;
tempMatrix[3] = 0;
tempMatrix[4] = (oneMinusCos * xy) + zs;
tempMatrix[5] = (oneMinusCos * yy) + cosAngle;
tempMatrix[6] = (oneMinusCos * yz) - xs;
tempMatrix[7] = 0;
tempMatrix[8] = (oneMinusCos * xz) - ys;
tempMatrix[9] = (oneMinusCos * yz) + xs;
tempMatrix[10] = (oneMinusCos * zz) + cosAngle;
tempMatrix[11] = 0;
tempMatrix[12] = 0;
tempMatrix[13] = 0;
tempMatrix[14] = 0;
tempMatrix[15] = 1;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
}
- (void)setProjection:(GLfloat *)source fov:(GLfloat)fov aspect:(GLfloat)aspect near:(GLfloat)near far:(GLfloat)far
{
GLfloat tempMatrix[16];
[self setIdentity:tempMatrix];
GLfloat r = fov * M_PI / 180.0f;
GLfloat f = 1.0f / tanf(r / 2.0f);
tempMatrix[0] = f;
tempMatrix[5] = f / aspect;
tempMatrix[10] = -(far + near) / (far - near);
tempMatrix[11] = -1;
tempMatrix[14] = -(2 * far * near) / (far - near);
tempMatrix[15] = 0;
[self multiplyMatrix:tempMatrix by:source giving:source];
}
@end
Scene.h
#import "Shader.h"
#import "Matrix.h"
@class Texture;
@interface Scene : NSObject {
Texture *texture;
GLuint textureName;
float animationPhase;
BOOL didShowInfo;
BOOL wireframe;
GLuint vaoID[1];
GLuint vboID[2];
GLuint programHandle;
GLuint shaderHandle[2];
GLuint ProjectionMatrixHandle, ViewMatrixHandle, ModelMatrixHandle;
GLfloat PerspectiveMat[16], ViewMat[16], ModelMat[16];
GLfloat updateValue;
Matrix *matrix;
Shader *shader;
}
- (id)init;
- (void)setViewportRect:(NSRect)bounds;
- (void)render;
- (void)advanceTimeBy:(float)seconds;
- (void)setAnimationPhase:(float)newAnimationPhase;
- (void)toggleWireframe;
@end
Scene.m (Using some code from the Apple fullscreen demo)
#import "Scene.h"
static double dtor( double degrees )
{
return degrees * M_PI / 180.0;
}
@implementation Scene
- (id) init
{
self = [super init];
if (self) {
wireframe = NO;
didShowInfo = NO;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_CULL_FACE);
glFrontFace(GL_CW);
GLfloat verts[32] =
{
-0.5, -0.5, -1.0, 1.0, 1.0f, 1.0f, 1.0f, 1.0f,
-0.5, 0.5, -1.0, 1.0, 1.0f, 1.0f, 1.0f, 1.0f,
0.5, 0.5, -1.0, 1.0, 1.0f, 1.0f, 1.0f, 1.0f,
0.5, -0.5, -1.0, 1.0, 1.0f, 1.0f, 1.0f, 1.0f
};
GLfloat indices[6] =
{
0, 1, 2,
0, 2, 3
};
[matrix setIdentity:ModelMat];
[matrix setIdentity:ViewMat];
NSLog(@"ModelMat:\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f", ModelMat[0], ModelMat[1], ModelMat[2], ModelMat[3], ModelMat[4], ModelMat[5], ModelMat[6], ModelMat[7], ModelMat[8], ModelMat[9], ModelMat[10], ModelMat[11], ModelMat[12], ModelMat[13], ModelMat[14], ModelMat[15]);
[matrix applyTranslation:ViewMat x:0 y:0 z:-2];
NSLog(@"ViewMat:\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f", ViewMat[0], ViewMat[1], ViewMat[2], ViewMat[3], ViewMat[4], ViewMat[5], ViewMat[6], ViewMat[7], ViewMat[8], ViewMat[9], ViewMat[10], ViewMat[11], ViewMat[12], ViewMat[13], ViewMat[14], ViewMat[15]);
programHandle = glCreateProgram();
shaderHandle[0] = [shader compileShader:@"shader.vert" ofType:GL_VERTEX_SHADER];
shaderHandle[1] = [shader compileShader:@"shader.frag" ofType:GL_FRAGMENT_SHADER];
glAttachShader(programHandle, shaderHandle[0]);
glAttachShader(programHandle, shaderHandle[1]);
glLinkProgram(programHandle);
ModelMatrixHandle = glGetUniformLocation(programHandle, "ModelMatrix");
ViewMatrixHandle = glGetUniformLocation(programHandle, "ViewMatrix");
ProjectionMatrixHandle = glGetUniformLocation(programHandle, "ProjectionMatrix");
glGenVertexArrays(1, &vaoID[0]);
glBindVertexArray(vaoID[0]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glGenBuffers(2, &vboID[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 4, GL_FLOAT, GL_FALSE, sizeof(verts[0]), 0);
glVertexAttribPointer((GLuint)1, 4, GL_FLOAT, GL_FALSE, sizeof(verts[0]), (GLvoid*)4);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0);
}
return self;
}
- (void)dealloc
{
[texture release];
[super dealloc];
}
- (void)advanceTimeBy:(float)seconds
{
float phaseDelta = seconds - floor(seconds);
float newAnimationPhase = animationPhase + 0.015625 * phaseDelta;
newAnimationPhase = newAnimationPhase - floor(newAnimationPhase);
[self setAnimationPhase:newAnimationPhase];
}
- (void)setAnimationPhase:(float)newAnimationPhase
{
animationPhase = newAnimationPhase;
}
- (void)toggleWireframe
{
wireframe = !wireframe;
}
- (void)setViewportRect:(NSRect)bounds
{
[matrix setIdentity:PerspectiveMat];
glViewport(0, 0, bounds.size.width, bounds.size.height);
[matrix setProjection:PerspectiveMat fov:60
aspect:(GLfloat)bounds.size.width / (GLfloat)bounds.size.height
near:1.0f far:100.0f];
}
- (void)render
{
updateValue += 0.015;
if (updateValue > 1)
updateValue = 0;
glClearColor(updateValue, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programHandle);
glUniformMatrix4fv(ModelMatrixHandle, 1, GL_FALSE, ModelMat);
glUniformMatrix4fv(ViewMatrixHandle, 1, GL_FALSE, ViewMat);
glUniformMatrix4fv(ProjectionMatrixHandle, 1, GL_FALSE, PerspectiveMat);
glBindVertexArray(vaoID[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (GLvoid*)0);
glBindVertexArray(0);
glUseProgram(0);
}
@end
Upvotes: 0
Views: 427
Reputation: 53010
In the comments you write:
Let me clarify. ModelMat is created in the header of the file it is called. It is simply created as such: GLfloat ModelMat[16];
That does create an array ModelMat
and as GLFloat
is a value type it can be used directly. However you continue:
The matrix part is simply a pointer to my Matrix class which holds the identity function. I create it in the header as well. Matrix *matrix; They are both created in the header interface
While this creates the variable matrix
, similar to above, it's type Matrix *
is a reference type. Creating a variable of reference type does not also create an object and store the reference to that object in the variable. Before using matrix
you must create an object, using a statement like:
matrix = [Matrix new];
As to passing arrays, you can do that exactly as in C - remembering that they are passed by reference to functions/methods. HTH.
Upvotes: 0
Reputation: 6580
You are not creating an instance of Matrix
anywhere. In -[Scene init]
, you need to add a line to create an instance of Matrix
, like so:
...
GLfloat indices[6] =
{
0, 1, 2,
0, 2, 3
};
// Add the following line
matrix = [[Matrix alloc] init];
[matrix setIdentity:ModelMat];
[matrix setIdentity:ViewMat];
...
That will fix it, although frankly your Matrix
instance methods could all be turned into class methods. Your Matrix
class doesn't have any instance variables, and the methods are more like standalone functions. Then you wouldn't have to track Matrix
objects at all.
Upvotes: 1