I'm creating a particle system renderer, the problem is that all my particle positions are encapsulated into classes that integrate them over time and do some other stuff. Instead of copying the values into a separate array to render each frame, I created a point struct like this that I can use to point to all the values once:
typedef struct
{
float *x, *y, *z;
} point;
I then malloc an array of these the same size as my array of particles.
Declaration at the top:
point *points;
Malloc:
points = malloc(sizeof(point) * [particles count]);
I then loop through all the particles and copy the addresses of each position to the corresponding pointer so:
for (int i = 0; i < [particles count]; ++i)
{
points[i].x = &[[particles objectAtIndex:i] getPosition].x;
points[i].y = &[[particles objectAtIndex:i] getPosition].y;
points[i].z = &[[particles objectAtIndex:i] getPosition].z;
}
My get position function just returns a vector struct (float x, y, z).
The first problem I encountered with this is that when I display the values like so:
NSLog(#"%f", *points[0].x);
Instead of reading of the value (say: 0.5), it displays it rounded and negated (so: -1.0).
I then get the data into my VBO like this:
glBufferData(GL_ARRAY_BUFFER, sizeof(point) * [particles count], &points[0], GL_DYNAMIC_DRAW);
I think this is also wrong but can't find any information on how to pass pointers into VBOs.
What you're doing is wrong because in C everything is passed by value, so when you dereference the .x member of the returned struct, you're doing it on a copy of the position struct, which will be popped from the stack if not assigned to any value.
You're design is wrong, you don't need a struct like this one:
typedef struct
{
float *x, *y, *z;
} point;
Rather one like this:
typedef struct
{
float x,y,z;
}
If you still want to assign it to it's original value, in a way that if the original struct's values change, also this struct is changed, then you need a getter who will return a pointer to the struct, and hold a pointer to it:
points[i] = [[particles objectAtIndex:i] getPositionPointer];
This way you're sure that your struct contains the same values of the original struct, but you're violating encapsulation. Which makes me think that maybe you don't really need to hold a pointer to original struct, but if there's a reason to do then I've shown you the way.
Related
How to return a C-style array of integers from an Objective-C method? This is what my code looks like so far:
Function call:
maze = [amaze getMaze];
Function:
-(int*) getMaze{
return maze;
}
I just started writing in Objective-C today so this is all new to me.
In C if you need to return an array from a function, you need to allocate memory for it using malloc and then return the pointer pointing to the newly allocated memory.
Once you're done working with this memory you need to free it.
Something like:
#include <stdlib.h> /* need this include at top for malloc and free */
int* foo(int size)
{
int* out = malloc(sizeof(int) * size); /* need to get the size of the int type and multiply it
* by the number of integers we would like to return */
return out; /* returning pointer to the function calling foo().
* Don't forget to free the memory allocated with malloc */
}
int main()
{
... /* some code here */
int* int_ptr = foo(25); /* int_ptr now points to the memory allocated in foo */
... /* some more code */
free(int_ptr); /* we're done with this, let's free it */
...
return 0;
}
This is as C style as it gets :) There are probably other (arguably more suitable) ways to do this in Objective C. However, as Objective C is considered a strict superset of C, this would also work.
If I may further expand on the need to do this by pointers. C-style arrays allocated in a function are considered local, once the function is out of scope they are automatically cleaned up.
As pointed out by another poster, returning a standard array (e.g. int arr[10];) from a function is a bad idea as by the time the array is returned it no longer exists.
In C we get around this problem by allocating memory dynamically using malloc and having a pointer that points to that memory returned.
However unless you free this memory adequately, you may introduce a memory leak or some other nasty behavior (e.g. free-ing a malloc-ed pointer twice will produce unwanted results).
Given you explicitly ask about C-style arrays no suggestions here that you should use NSArray etc.
You cannot return a C-style array directly (see below) as a value in Objective-C (or C or C++), you can return a reference to such an array.
Types such as int, double and struct x can all be passed by value - that is the actual bits representing the value are passed around. Other things; such as C-style arrays, dynamically allocated memory, Objective-C style objects, etc.; are all passed by reference - that is a reference to a location in memory that contains the actual bits the represent the value is passed around.
So to return a C-style array from a function/method you can:
Dynamically (malloc et al) an array and return the reference to the allocated memory;
Pass in a reference to an already existing array and have the function fill it up; or
Wrap the array up as a struct...
The normal choices are (1) or (2) - note you cannot return a reference to a stack allocated array, as in:
int *thisIsInvalid()
{
int myValues[5];
...
return myValues; // will not work, the type is correct but once function
// returns myValues no longer exists.
}
If you really want to return a (small) array by value you can actually do it using (3). Remember that struct values are passed by value. So the following will work:
typedef struct
{
int array[5];
} fiveInts;
fiveInts thisIsValid()
{
fiveInts myValues;
...
myValues.array[3] = ...; // etc.
...
return myValues;
}
(Note that there is no overhead from wrapping the array inside a struct when it comes to reading/writing the array - the cost in the above is copying all the values back - hence only advised for small arrays!)
HTH
- (NSArray *)toArray:(int *)maze {
NSMutableArray *retVal = [[NSMutableArray alloc] init];
for (int c = 0; maze[c] != NULL; c++) {
[retVal addObject:[NSNumber numberWithInt:maze[c]]];
}
return [retVal array];
}
I've never been comfortable passing mutable data in and out of methods and not sure why. If you need to change the values later, send the array a mutableCopy message.
you can do it in this way
- (void)getArray:(int *)array withLength:(NSUInteger)length{
for (int i = 0; i < length; i++)
array[i] = i;
}
int array[3];
[object getArray:array withLength:3];
NSLog(#"%d %d %d", array[0], array[1], array[2]); // 1 2 3
I am trying to do a very simple thing but I can't figure out how;
NSInteger * a=10;
a=a-1;
NSlog(#"a=%d",a);
For some reason it's showing a=6.
How can it be?
Your problem is that you've declared the variable a as a pointer.
Most Objective-C variables are pointers, but NSInteger is an exception, because it's just typedef'd to int or long.
Your code should look like this:
NSInteger a=10;
a=a-1;
NSlog(#"a=%d",a);
When you do math on a pointer, you are actually moving the location in memory it points to. For example if the size of an NSInteger is 4 (sizeof(NSInteger) == 4), moving it -1, or in other words, a one structure size back, the pointer gets decreased by 4.
This mechanique is heavily used in C when iterating arrays of structures, e.g.
CGPoint myPoints[4];
CGPoint* point = myPoints; //get the first point
for (NSUInteger i = 0; i < 4; i++) {
CGPoint currentPoint = *point;
point++; //moves to the next point, adding sizeof(CGPoint)
}
This is called pointer arithmetic and you can write it in different ways, e.g. pointer + 1 but also point[1] or 1[point] (the last two are actually equal to *(pointer + 1)).
Hi I am relatively new to programming on iOS and using objective C. Recently I have come across an issue I cannot seem to solve, I am writing a OBJ model loader to use within my iOS programming. For this I use two arrays as below:
static CGFloat modelVertices[360*9]={};
static CGFloat modelColours[360*12]={};
As can be seen the length is currently allocated with a hard coded value of 360 (the number of faces in a particular model). Is there no way this can be dynamically allocated from a value that has been calculated after reading the OBJ file as is done below?
int numOfVertices = //whatever this is read from file;
static CGFloat modelColours[numOfVertices*12]={};
I have tried using NSMutable arrays but found these difficult to use as when it comes to actually drawing the mesh gathered I need to use this code:
-(void)render
{
// load arrays into the engine
glVertexPointer(vertexStride, GL_FLOAT, 0, vertexes);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(colorStride, GL_FLOAT, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);
//render
glDrawArrays(renderStyle, 0, vertexCount);
}
As you can see the command glVertexPointer requires the values as a CGFloat array:
glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
You could use a c-style malloc to dynamically allocate space for the array.
int numOfVertices = //whatever this is read from file;
CGFloat *modelColours = (CGFloat *) malloc(sizeof(CGFloat) * numOfVertices);
When you declare a static variable, its size and initial value must be known at compile time. What you can do is declare the variable as a pointer instead of an array, the use malloc or calloc to allocate space for the array and store the result in your variable.
static CGFloat *modelColours = NULL;
int numOfVertices = //whatever this is read from file;
if(modelColours == NULL) {
modelColours = (CGFloat *)calloc(sizeof(CGFloat),numOfVertices*12);
}
I used calloc instead of malloc here because a static array would be filled with 0s by default, and this would ensure that the code was consistent.
Hello stackoverflow fellow members?
Struct Declaration in class A
struct PointSprite
{
GLfloat x;
GLfloat y;
GLfloat size;
Color4f color;
} ParticleSystems[MAXIMUM_PARTICLES_ON_SCREEN];
// I generally put some stuffs in ParticleSystem array.
// for ex) struct PointSprite *ps = &ParticleSystems[index];
// and it works well on the class A, but I want to get class B to access this array.
My question is, how am I suppose be return the array of 'ParticlelSystems' array so that other class can access to it? I have tried below code to return the pointer, but compiler gives me a warning.
- (struct ParticleSystems *) commitParticles
{
struct ParticleSystems *ptr = &ParticleSystems; // it said, assigning incompatible pointer type
return ptr;
}
Or should I need to allocate the 'ParticleSystems' array? Please help ! Thanks
If you are creating the array inside the function then you should dynamically allocate it using new and then return a pointer to it.
You cannot return arrays from a function, you will have to return a pointer to it.
Sample Code:
ParticleSystems* doSomethingInteresting()
{
ParticleSystems *ptr = new ParticleSystems[MAXIMUM_PARTICLES_ON_SCREEN];
//do the processing
return ptr;
}
The caller takes the ownership of the returned dynamically allocated array and needs to deallocate it to avoid memory leaks:
delete []ptr;
You can either return it, after allocating one, or you can fill one passed to you by the user. The latter leaves the responsibility to the user to provide a ParticleSystem to the method which receives the data. It can be a local array, or a malloced one.
- (void) commitParticles: (ParticleSystems *) sprites
{
// set members of the structs here
}
I prefer this kind of passing to returning a malloced array. Your mileage may vary.
You're getting the assigning incompatible pointer type compiler warning because your ptr declaration should be of type PointSprite *, not ParticleSystems *
I have a struct called Point
typedef struct {
GLfloat x;
GLfloat y;
} Point;
create an array of Points:
Point *sPoints;
for(int i=0 ... // define sPoints
somewhere else, I want to alter variables on those points. Why does this work:
sPoints[100].x+=10;
but this doesn't:
Point pt = sPoints[100];
pt.x +=10;
is there any way to create a temporary variable that refers to the Point structure and allows me to set properties of that struct? The really strange thing is that in my non working code (pt.x +=10) I can actually read pt.x fine, I just can't seem to assign it... any help appreciated.
It doesn't work because in C, that operation:
Point pt = sPoints[100];
creates a copy of the item on the right hand side, whereas the former does not copy.