|
TUTORIAL 4: 3DS LOADER |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
INTRODUCTION After this long wait it's
time to say goodbye to our dear cube! In this lesson we will develop a
routine to load 3ds objects, a file format very famous on the net and
supported by various 3d modelers.
For the one that doesn't know yet what a 3d modeler is, I immediately
say that, thanks to it, it's possible to create any type of object in a
more intuitive and human way rather than to define by hand the
coordinates of the vertices, it's an impossible thing for objects only
just a little bit more complexes than a cube. To say the truth I am
sorry to throw away the cube, a so simple and perfect figure, but, until
proved otherwise, the spaceships, the planets, the missiles and
everything that has something to do with a space simulator is completely
different from the cube!
THE 3DS FILE STRUCTURE A 3ds file contains a series of useful information to describe in every minimum detail a 3d scene composed by one or more objects. Internally a 3ds file is constituted by a series of blocks called Chunks. What is it contained in these blocks? Everything necessary to describe the scene: for each object is stored the name, the vertices coordinates, the mapping coordinates, the list of the polygons, the faces colors, the animation keyframes and so on... The chunks don't have a
linear structure, this means that some are closely dependent from others
and therefore they can be read only if their relative fathers are read
as well. Of course it's not necessary to read all the chunks, we
will consider only the most important ones!
From the last line we can
easily realize how it is possible to make dependent some chunks from
others: each chunk child is in fact entirely contained inside the field
"Sub-chunks" of the father. MAIN
CHUNK
0x4D4D Obviously if we want
to read a particular chunk we needs to be careful to read always its
fathers! To understand better let's imagine the 3ds file as a tree and
the chunk that we need a leaf... of course we are a little ant in the
ground! To reach the leaf it is necessary to walk from the trunk to all
the branches up to it. If we for example want to reach the chunk
VERTICES LIST we have to read the MAIN CHUNK, the 3D EDITOR CHUNK, the
OBJECT BLOCK and finally the TRIANGULAR MESH. The other chunks can
quietly be jumped... MAIN
CHUNK
0x4D4D Let's describe in detail these chunks:
Now that the 3ds format is enough clear we are going to analyze the code of this tutorial... What? You have understood nothing? =D Let's continue anyway! The chunks structure will be surely clearer to you continuing with the lesson, after all we are programmer and we understand better the C language rather than the usual chatters! ;) A SHORT BRIEFING The necessary steps to
load a 3ds object and save it in our structure are: FINALLY... CODE! As we have already done
for the last tutorial the first thing to do is to create the files that
will contain the new routines. #define
MAX_VERTICES 8000 We must increase the
number of vertices and polygons that our engine is able to manage. char
Load3DS (obj_type_ptr p_object, char *p_filename) The Load3DS routine
accepts as entry parameters the pointer to the object data structure and
the name of the file to open. Then it returns "0" if the file
has not been found or "1" if the file has been found and
readed. So let's open the file at last!
if ((l_file=fopen (p_filename, "rb"))== NULL) return 0; //Open
the file The while cycle is performed for the whole length of the file. The ftell function allows us to acquire the current file pointer position while filelength returns us the length of the file.
fread (&l_chunk_id, 2, 1, l_file); //Read the chunk header We have
extrapolated the identifier and the length of the chunk and have
respectively saved them in l_chunk_id and l_chunk_length.
switch (l_chunk_id) We have found the MAIN CHUNK! Cool! What are we going to do? Simple... nothing! In fact the MAIN CHUNK has not data, what is interesting are its sub-chunks, for this reason we have included this line of code. In fact, if we didn't include this "case", the whole chunk have been jumped! Mmmm why? The explanation is found in the "default case" at the end of this lesson... For now please don't worry, we will arrive to it soon... let's only say that jumping the length of the MAIN CHUNK would have meant to move the file pointer at the end! We didn't want this... or yes? ;) The same approach for the 3D EDITOR CHUNK: this is the secondary branch that is useful to reach the information that we need, it hasn't own data. So let's pretend to read it =) he will bring us to its child... the Object Block!
case 0x3d3d: Here is the chunk OBJECT BLOCK, this chunk finally has some interesting information: the name of the object, that we immediately store in the field name of the object structure. The while cycle exit if there is the character '\0' or the number of characters are more than 20. But... be careful! We have had to read all the data of this chunk because this has allowed us to move the pointer of the file to the next chunk.
case 0x4000: Another empty branch that however is the father of chunks that we must read...
case 0x4100: So here are the vertices! The chunk VERTICES LIST contains all the vertices of the object. We read first the value "quantity" and then we use it to create a for cycle to read all the vertices. We save all the information inside the object structure.
case 0x4110: The chunk FACES
DESCRIPTION contains the list of the object's polygons. As it
was explained in the tutorial 1 in this structure we don't memorize
coordinates but only numbers that point to elements of the
vertices list. To read this chunk we can exactly do the same we have
already done for the vertices chunk: at first we read the number of
faces and create a for cycle to read all the faces.
case 0x4120: Finally let's read the MAPPING COORDINATES LIST, as usual we read first the quantity and then the list of coordinates, this time however one point has two coordinates, in fact the mapping coordinates are bidimensional, u and v do you remember? No?? What are you doing here then? ;) Go back to the first tutorial!
case 0x4140: Great! The default case! This means that we are at the end of the routine! When we meet chunks that we don't want to read the fseek function help us, using the chunk_length information, it moves the file pointer to the beginning of the next chunk.
default: We have finished! Very little remains to be done: let's close the file and return 1! fclose
(l_file); // Closes the file stream
CONCLUSIONS The 3ds reader that we
have developed is the start point to realize more complex readers. Keep
in mind however that our routine can read only a 3ds scene if in it
there is only one object and it is exactly at the center. In the
next tutorials (the matrices tutorial), we will add the possibility to
load other objects. In fact we must necessarily include other
spaceships, in the opposite case we have not objectives to
destroy!
GO BACK TO DOWNLOAD THE SOURCE CODE... |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
©2000-2003 Damiano Vitulli. All Rights Reserved. No Portion Of This Site May Be Reproduced Without Permission. Best viewed at 1024x768. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||