1

For some reason I just cant seem to get my head around the process of creating a C-Array instance variable for a class that can have elements added to it dynamically at runtime.

My goal is to create a class called AEMesh. All AEMesh objects will have a c-array storing the vertexdata for that specific AEMesh's 3D model for use with OpenGL ES (more specifically it's functionality for drawing a model by passing it a simple C-Array of vertexdata).

Initially I was using an NSMutableArray, on the assumption that I could simply pass this array to OpenGL ES, however that isnt the case as the framework requires a C-Array. I got around the issue by essentially creating a C-Array of all of the vertexdata for the current AEMesh when it came time to render that specific mesh, and passing that array to OpenGL ES. Obviously the issue here is performance as I am constantly allocating and deallocating enough memory to hold every 3D model's vertexdata in the app about a dozen times a second.

So, Im not one to want the answer spoon fed to me, but if anyone would be willing to explain to me the standard idiom for giving a class a mutable c-array (some articles Ive read mention using malloc?) I would greatly appreciate it. From the information Ive gathered, using malloc might work, but this isn't creating a standard c-array I can pass in to OpenGL ES, instead its more of a pseudo-c-array that works like a c-array?

Anyways, I will continue to experiment and search the internet but again, if anyone can offer a helping hand I would greatly appreciate it.

Thanks, - Adam Eisfeld

3 Answers 3

2

The idea would just be to add a pointer to an array of AEMesh structures to your class, and then maintain the array as necessary. Following is a little (untested) code that uses malloc() to create such an array and realloc() to resize it. I'm growing the array 10 meshes at a time:

@interface MyClass : NSObject
{
    int meshCount;
    AEMesh *meshes;
}
@end

@implementation MyClass

-(id)init {
    if ((self = [super init])) {
        meshCount = 0;
        meshes = malloc(sizeof(AEMesh)*10);
    }
    return self;
}

-(void)addMesh:(AEMesh)mesh {
    if (meshCount % 10 = 0) {
        meshCount = realloc(sizeof(AEMesh) * (meshCount + 10));
    }
    if (meshCount != nil) {
        meshes[meshCount] = mesh;
        meshCount++;
    }
}
@end

It might be worthwhile to factor the array management into it's own Objective-C class, much as Brian Coleman's answer uses std::vector to manage the meshes. That way, you could use it for C arrays of any type, not just AEMesh.

From the information Ive gathered, using malloc might work, but this isn't creating a standard c-array I can pass in to OpenGL ES, instead its more of a pseudo-c-array that works like a c-array?

A C array is nothing more than a series of objects ("objects" used here in the C sense of contiguous memory, not the OO sense) in memory. You can create one by declaring it on the stack:

int foo[10];  // array of 10 ints

or dynamically on the heap:

int foo[] = malloc(sizeof(int)*10); // array of 10 ints, not on the stack
int *bar = malloc(sizeof(int)*10); // another way to write the same thing

Don't forget to use free() to deallocate any blocks of memory you've created with malloc(), realloc(), calloc(), etc. when you're done with them.

Sign up to request clarification or add additional context in comments.

1 Comment

Is there much of a performance difference in using malloc / realloc to manually create and update the array instead of using Brian Coleman's answer regarding vectors? From what I can tell both of these methods are doing exactly the same thing, however the vectors are a little simpler to implement and according to Brian dont need any extra memory management. Im trying to write a 3D engine for the iPhone, so any performance gain I can get will help.
0

I know it doesn't directly answer your question, but an even easier approach would be to work with an NSMutableArray instance variable until the point where you need to pass it to the API, where you would use getObjects:range: in order to convert it to a C-Array. That way you won't have to deal with "mutable" C-Arrays and save yourself the trouble.

2 Comments

This is the method I was describing that I was doing previously. The issue is, this is for 3D rendering in a game loop. I need to iterate over every vertex of every 3D model in the video game up to 30 times a second to have a consistent enough framerate. Constantly converting NSMutableArrays to C-Arrays over and over every single game loop isnt exactly the fastest way to do things. Using the above posted method of vector arrays seems like it might be just what I was looking for.
if you reuse the array and its size doesn't change dramatically then it maybe isn't that bad after all.. but feel free to use C++ vectors ;)
0

If you're willing to use ObjectiveC++ and stray outside the bounds of C and ObjectiveC, then you can use a std::vector to amortise the cost of resizing the array of vertex data. Here's what things would look like:

include <vector>
include <gl.h>

@interface MyClass {
    std::vector<GLfloat> vertexData;
}

-(void) createMyVertexData;

-(void) useMyVertexData;

@end

@implementation

-(void) createMyVertexData {
    // Erase all current data from vertexData
    vertexData.erase(vertexData.begin(), 
                     std::remove(vertexData.begin(), 
                                 vertexData.end());
    // The number of vertices in a triangle
    std::size_t nVertices = 3;
    // The number of coordinates required to specify a vertex (x, y, z)
    std::size_t nDimensions = 3;
    // Reserve sufficient capacity to store the vertex data  
    vertexData.reserve(nVertices * nDimensions);
    // Add the vertex data to the vector
    // First vertex
    vertexData.push_back(0);
    vertexData.push_back(0);
    vertexData.push_back(0);
    // And so on
}

-(void) useMyVertexData {
    // Get a pointer to the first element in the vertex data array
    GLfloat* rawVertexData = &vertexData[0];
    // Get the size of the vertex data
    std::size_t sizeVertexData = vertexData.size();
    // Use the vertex data
}

@end

The neat bit is that vertexData is automatically destroyed along with the instance of MyClass. You don't have to add anything to the dealloc method in MyClass. Remember to define MyClass in a .mm file

10 Comments

Thanks, this seems interesting and going into the right direction.
Just a quick question, am I right in assuming that an std vector array is toll-fee bridged with c-arrays then? IE I would be able to simply pass vertexData to the glVertexPointer() function and OGLES will handle it exactly the same?
std::vector is designed so that it can be interchanged with a c array of the same type. This is a C++ feature rather than an Apple specific feature. The Apple specific feature used here is that the std::vector instance member is automatically destructed when the MyClass instance is deallocated by the Objective C runtime.
You would pass the GLfloat pointer (rawVertexData) to any OpenGL functions
Im getting an error after trying to implement your code Brian: "cannot convert '__gnu_cxx::__normal_iterator<float*, std::vector<float, std::allocator<float> > >' to 'const char*' for argument '1' to 'int remove(const char*)' " Any idea what this means? The compiler is flagging this error at the line calling vertexData.erase.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.