Tag: Objective-C


iPhone SDK mesh COLLADA import

19 July 2009 — 5:46 PM

Software: Maya2008 COLLADA version 1. 4

COLLADA schema supports all the features that modern 3D interactive applications need, including programmable shader effects, animation and physic simulation.

Step 1.

Install and load COLLADA plug in for maya

Step 2.

Change all face of model into triangles: Mesh -> Triangulate. (OpenGL ES 1.x do not support QUADE draw).

Step 3.

Export model with mayaCollada, so I have a dae(digital asset exchange) file. In fact dae file is extended from XML file.

Step 4.

Go back to Xcode and import this .dae file into project, Open it with editor, we can find all information about 3D Model, like materials, effects, geometries… I focus my attention on tag ” library geometries” which include a sub tag “mesh”. The first line in this block define name of geometry <geometry id=”pCubeShape1″ name=”pCubeShape1″> then is the important tag <mesh>, in it there are 3 “source” and a “triangles” blocks, each of them include an array: <float_array id=”pCubeShape1-positions-array” count=”24″> (position of each vertex), <float_array id=”pCubeShape1-normals-array” count=”72″>, <source id=”pCubeShape1-map1″ name=”pCubeShape1-map1″>  (texture coordinats) and <p> ( please look at to Ps). They are all what we need to a simple model to iPhone SDK import.

Step 5.

Then I can parse this file with class NSXMLParser from SDK. In this example I draw model shape without texture, so I read out only positions array and the indices array from <p>.

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if(qName) {
elementName = qName;
}

if([elementName isEqualToString:@"accessor"]) {
NSString *accessorAtt = [attributeDict valueForKey:@"source"];
if([accessorAtt isEqualToString:@"#pCubeShape1-positions-array"]) {
NSString *sVertextCount = [attributeDict valueForKey:@"count"];
vertexCount = [sVertextCount intValue];
return;
}

else if([accessorAtt isEqualToString:@"#pCubeShape1-map1-array"]) {
NSString *sMapCount = [attributeDict valueForKey:@"count"];
mapCount = [sMapCount intValue];
return;
}
}

else if([elementName isEqualToString:@"triangles"]) {
NSString *sFaceCount = [attributeDict valueForKey:@"count"];
faceCount = [sFaceCount intValue];
return;
}

else if ([elementName isEqualToString:@"float_array"]) {
NSString *relAtt = [attributeDict valueForKey:@"id"];
if([relAtt isEqualToString:@"pCubeShape1-positions-array"]) {
contentProperty = [NSMutableString string];
array_id = id_positions;
NSLog(@”get positions”);

}

else if([relAtt isEqualToString:@"pCubeShape1-normals-array"]) {
contentProperty = [NSMutableString string];
array_id = id_normals;
NSLog(@”get normals”);
}

else if([relAtt isEqualToString:@"pCubeShape1-map1-array"]) {
contentProperty = [NSMutableString string];
array_id = id_maps;
NSLog(@”get maps”);
}
}

else if ([elementName isEqualToString:@"p"]) {
contentProperty = [NSMutableString string];
NSLog(@”get vertex”);
}

else {
contentProperty = nil;
}
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if (qName) {
elementName = qName;
}

if ([elementName isEqualToString:@"float_array"]) {
if(array_id == id_positions) {
msd.sPosition = contentProperty;
NSLog(@”set postion”);
array_id = -1;
}

if(array_id == id_normals) {
msd.sNormal = contentProperty;
NSLog(@”set normals”);
array_id = -1;
}

if(array_id == id_maps) {
msd.sMap = contentProperty;
NSLog(@”set maps”);
array_id = -1;
}
}

else if ([elementName isEqualToString:@"p"]) {
msd.sIndices = contentProperty;
NSLog(@”set vertex”);
}

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (contentProperty) {
[contentProperty appendString:string];
}
}

Step 6.

At last we can draw our model with OpenGL ES.

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, mVertices);

glDrawArrays(GL_TRIANGLES, 0, faceCount*3);

glDisableClientState(GL_VERTEX_ARRAY);

Ps:
The <p> contains indices that describe the vertex attributes for a number of triangles. The indices in a <p> element refer to different inputs depending on their order. The first index in a <p> element refers to all inputs with an offset of 0. The second index refers to all inputs with an offset of 1.
Each vertex of the triangle is made up of one index into each input. After each input is used, the next index again refers to the inputs with offset of 0 and begins a new vertex.
The winding order of vertices produced is counterclockwise and describes the front side of each triangle.
If the primitives are assembled without vertex normals then the application may generate per-primitive
normals to enable lighting.

Here is an example of a <triangles> element that describes two triangles. There are two <source> elements that contain the position and normal data, according to the <input> element semantics. The <p> element index values indicate the order in which the input values are used:

<mesh>
<source id=”position”/>
<source id=”normal”/>
<vertices id=”verts”>
<input semantic=”POSITION” source=”#position”/>
</vertices>
<triangles count=”2″ material=”Bricks”>
<input semantic=”VERTEX” source=”#verts” offset=”0″/>
<input semantic=”NORMAL” source=”#normal” offset=”1″/>
<p>
0 0 1 3 2 1
0 0 2 1 3 2
</p>
</triangles>
</mesh>

Comment » | Allgemein

Propertys for accessors

3 June 2009 — 10:32 AM

Encapsulation is one of the most important concepts in object-oriented programming. To ensure Encapsulation, setter and getter methods (accessors) have to be written for every instance-variable. This could be very time-consuming and boring, because the most accessors are quite the same, except the instance-variable name. Therefore the decision is obvious to let the compiler generate accessors for us. This proceeding is called synthesize and was implemented with Objective-C 2.0 with so called properties.

Propertys generel syntax:

header
@property (attribute1, attribute2, attribute3, attribute4) datatype variablename;

implementation
@syntesize variablename;

If the instance-variable is synthesized, the access is:

standard-syntax
[Obj setVariablename:value]
printf(„The Value: %i“, [Obj variablename]);

point-syntax
Obj.variablename = value;
printf(„The Value:  %i“, Obj.variablename);

Annotation:
The Dot-Syntax exists without dependence on properties. Its possible to write accessors without properties and access them via Dot-Syntax.

The 4 attributes define following:
-access-type (readonly, readwrite)
-setter-semantik (assign, retain, copy)
-atomicity
-setter- and getter-name

Access-type

In case of readonly only the getter is synthesized. With readwrite both, getter and setter, are synthesized.

Setter-semantic

Assign

Assign is the standard setter-semantic. If you leave the setter-sematic attribute empty, the compiler choose automatically the assign semantic.Assign is the simplest setter-semantic. The new value is simply assigned to the instance-variable, nothing else. The reference-counter is not increased and thereby there is no need to decrease an older increasement. The consequence is, that the receiver-class isnt an object-owner. If the sender-class decrease the reference-counter, the object will be deleted and the receiver-class no longer has access to it. Offcourse this could happen inversely, too. Because of this, propertys with assign-semantic shouldnt be released in the dealloc-method (because its never been retained).

Example (compiler-generated code)
-(void)setVariablenname:(id)senderValue
{
 instanceValue = senderValue;
}

assign

Retain

Retain solves the problem of the assign-semantik. First the instance-variable is released, because it maybe points already to an other object. Then the new value is assigned to the instance-variable. In the last step the instance-variable is retained. This means that the receiver-class is now an object-owner. The sender-class is now free to release the object and it still stays alive and accessible to the receiver-class. As the retain-semantic retains the instance-variable, it has to be released in the dealloc-method. Both classes (receiver and sender) point to the same object. If one of the classes change the object it is also changed to the other class.

Example (compiler-generated code)
-(void)setVariablenname:(id)senderValue
{
if(instanceValue != senderValue)
  {
   [instanceValue release];
   instanceValue = senderValue;
   [instanceValue retain];
}
}

retain

Copy

Copy allows a class to be the only owner of an object. The submitted object is first copied and then assigned to the instace-variable. The advantage is the independance of the object. If the sender-class changes the object, it has no consequences to the copied object from the receiver-class.

Example (compiler-generated code)
-(void)setVariablenname:(id)senderValue
{
if(instanceValue != senderValue)
  {
   [instanceValue release];
   instanceValue = [senderValue copy];
}
}

copy

Atomicity

Atomicity assure safe access of multiple threads. Only one thread is allowed to access the accessors at the same time.To avoid this the attribute „nonatomic“ has to be named. More at friday.com

Setter- and getter-names

As described above the standard names are „setVariablename:“ (setter) and „variablename (getter). This can be changed. As example, in case of boolean-variables, its nice to have a getter like „isInitial“. To manage this the attribute „getter = isInitial“ have to be named in the property definition. Thereby the boolean-variable can be accessed like this:

[Object isInitial];
Object.isInitial;

If the access-type is „readwrite“,  its also possible to change the standardame for the setter-method with the attribute „setter = otherName“.

Source
developer.apple.com

3 comments » | ObjC

Messages VS Methodcalls

12 May 2009 — 4:22 PM

I write this post to make the transfer between C++ or Java to ObjC (Objective-C) a little bit easier.

One of the biggest differences between ObjC (Objective-C) and C++ or Java is the philosophy behind functioncalls. While you speak about methodcalls in context of Java or C++, in ObjC its called messages to objects.

With a methodcall under C++ or Java the method is binded before the programm starts. This means that the objects method must exist, otherwhise there would be an compilererror and starting the programm would be impossible. This early binding has the benefit of preventing mistakes due programming of methodcalls. However early binding is very unflexible.

Among ObjC you send messages to objects. This comes from Smalltalk. Messages are send during the runtime, enabling late binding. The object interprets the messages while runtime and decides which function to call. This means that the compiler dont check the existence of the function before runtime. Late binding hold the drawback of making mistakes while programming functioncalls. But the big advantage of flexibility.

This Example looks very simple but wouldnt work on C++ or Java:

implementation ClassOne

-(void)doSomeThing
{…}
@end

implementation ClassTwo

-(void)doSomeThing
{…}
@end

int main(…)
{
id *object = [[ClassOne alloc]init]; //id stands for any type of object
[object doSomeThing]; //call ClassOne`s method
[object release];
object = [[ClassTwo alloc]init];
[object doSomeThing]; //call ClassTwo`s method
}

1 comment » | ObjC

Back to top