开发者

Xcode / iOS: Simple example of a mutable C-Array as a class instance variable?

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 wou开发者_如何学JAVAld 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


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.


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.


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜