Re: OpenGL Nurbs Surface/Dynamic Multi-Dimensional C Arrays Questions
Re: OpenGL Nurbs Surface/Dynamic Multi-Dimensional C Arrays Questions
- Subject: Re: OpenGL Nurbs Surface/Dynamic Multi-Dimensional C Arrays Questions
- From: mathew <email@hidden>
- Date: Tue, 21 Oct 2003 21:44:46 -0400
On Friday, Oct 17, 2003, at 18:37 US/Eastern, Clinton Parsons wrote:
The problem comes from needing the flexibility of the objective-c
format, and not being able to properly declare/allocate (malloc I
assume) a dynamic multi-dimensional C array to be sent as the 'control
points array' argument in the OpenGL command gluNurbsSurface().
I don't know where you got the idea that you can't allocate C arrays in
the normal way. There's nothing stopping you from allocating a control
points array, copying in the values from your Cocoa NSMutableArray
objects, and then passing the result to OpenGL.
A better approach, however, might be to use C arrays for the actual
storage, and wrap them in an Objective-C class which implements the
essential parts of the NSMutableArray interface. If you know roughly
how big your arrays are going to be, you can pre-allocate that size for
performance gains. If you expect to do a lot of "append 1 element to
array", do block allocation--rather than resizing the memory every
time, instead never add less than X cells to the array, and separately
track how many cells are actually used.
e.g. if I were writing code like that to handle e-mail messages as
arrays of lines of characters, I might allocate in blocks of 80
characters, and pre-allocate 2K at the start. Even if the code was
called in the pathological case of reading a 100K e-mail and writing it
to the dynamic array one character at a time, internal overheads from
memory reallocation would probably be swamped by function call
overheads.
From the point of view of the code that uses the NSMutableNURBSArray,
it's just like an NSMutableArray, except you can call [foo cArray] to
get the address of the internal C array to pass to the OpenGL calls. Or
alternatively, have the NSMutableNURBSArray handle all the OpenGL calls
as well.
That's what I did with the Red Pill screen saver--there's an
Objective-C class MatrixStrip which hides all the C allocation and
deallocation for its internal data storage, and you send it a draw
message to get it to issue all the OpenGL calls to draw itself as a
vertex array. The caller just says init a MatrixStrip at this location
in 3D space, this big, animating with these parameters. It doesn't have
to know about malloc() or free() or making sure allocated C memory
arrays are large enough, because the MatrixStrip class handles all that.
Of course the float values of the NSNumbers would be transfered into
the allocated C array before it was sent as an argument. The
multi-dimensional C array would need to have the option of varying in
the size of each dimension multiple times during execution. However,
the size of the variations is unknown at compile time.
That's why we have realloc (3). :-)
As a side note, if I understand it correctly, It is unefficient to use
a bezier surface because, once displayed, the surface, in this
example, only needs to add a row on one end, and drop a row on the
other, maintaining the same size once displayed. The user needs to be
able to update the size of any dimension during execution.
Assume you have a 2-dimensional array of cells, where each cell
contains the control point data for one polygon of the surface. Suppose
in C you choose to store cell N at (X(N) + RowSize * Y(N)) *
sizeof(cell).
Increasing or decreasing the Y size is easy, right?
Surprisingly, increasing the X size is also easy to do in an optimized
fashion if you're careful. e.g. going from 3x3 to 4x3, you realloc your
9 cells to be 12 cells. In memory:
123
456
789
becomes
1234
5678
9***
Now, OS X memmove is defined in the man page to always be
non-destructive if the areas of memory overlap. So you can calculate
the start address of each row if the array were still 3x3, and memmove
to the appropriate start address now that the array is 4x3. So after
the first move you have
1234
56**
789*
Then after the second move
123*
456*
789*
So in the worst case you only need one memmove call per row and a
single realloc, and you never need to have two copies of the array
sitting around in memory.
Decreasing the X size is just the reverse process--you do all the
memmoves first to pack the data into a smaller space, then realloc. (Or
don't bother, if you think you might need to make the array bigger
again later.)
mathew
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.