Hingga tahap ini obyek yang digunakan masih berangkat dari pemodelan manual
sehingga model yang dihasilkan masih sederhana. Kebutuhan untuk dapat menggunakan
model yang lebih kompleks sangat besar. Ada banyak aplikasi perangkat lunak yang
dapat digunakan untuk membuat model dengan lebih mudah. Contoh aplikasi untuk
pembuatan model 3D antara lain: 3DS Max, Blender, Maya, Milkshape dengan dibantu
aplikasi pemrosesan citra 2D seperti Photoshop, Corel dll. Format-format file standar
model 3D yang biasa digunakan antara lain .3ds, .obj, dll.
Persoalannya adalah bagaimana kita dapat menggunakan hasil dari aplikasi perangkat
lunak tersebut dalam program kita. Untuk itu kita membutuhkan kode untuk membaca
file tersebut dalam dan merepresentasikannya ke dalam program kita.
Tutorial 09 memberikan ilustrasi tentang bagaimana kita membaca file model 3D dan
menggunakannya dalam program berbasis openGL dan GLUT. Pertama file dalam
format .txt yang kita buat sendiri dan kemudian dengan format file .3ds. Model dengan
format 3DS sendiri awalnya merupakan file format pada versi-versi awal aplikasi 3D
Studio dari Autodesk Animation Ltd. sebelum berubah menjadi format file yang lebih
kompleks dengan aplikasinya menjadi 3D Studio Max. Format ini merupakan salah satu
format yang paling banyak dikenal.
Suatu set model 3D yang direpresentasikan oleh file .3ds biasanya ditemani oleh
beberapa file citra untuk texture dari model tersebut. Format file-nya disusun dengan
organisasi sebagai berikut:
Pada Program 13 kita membuat file model 3D dengan format kita sendiri. File format kita
adalah file .txt yang formatnya akan berupa aturan sebagai berikut:
- Kita dapat memasukkan baris kosong semau kita agar file lebih mudah dibaca
- Kita dapat memasukkan baris komentar dengan menambahkan “//” pada awal
baris
- Hanya terkait dengan satu file texture
- Primitif yang digunakan hanya GL_TRIANGLES
- Informasi awalnya akan berupa frasa NUMPOLLIES xx, dengan xx adalah
jumlah primitif
- Setelah itu kita harus memberi spesifikasi triangle-nya dengan menuliskan daftar
vertex perbaris dengan format baris sbb.
X Y Z S T
dengan X,Y, Z adalah posisi vertex sedangkan S, T adalah pixel texture yang
bersesuaian.
Contoh datanya juga diberikan pada bagian bawah dari Program 13.
Program 13
#include <windows.h>
#include <math.h> // Math Library Header File
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <GL/glut.h>
#include <GL/glaux.h>
const float piover180 = 0.0174532925f;
float heading;
float xpos;
float zpos;
GLfloat yrot; // Y Rotation GLfloat walkbias = 0;
GLfloat walkbiasangle = 0; GLfloat lookupdown = 0.0f;
GLfloat z=0.0f; // Depth Into The Screen
GLuint filter; // Which Filter To Use
GLuint texture[3]; // Storage For 3 Textures
typedef struct tagVERTEX {
float x, y, z;
float u, v; } VERTEX;
typedef struct tagTRIANGLE {
VERTEX vertex[3];
} TRIANGLE;
typedef struct tagSECTOR {
int numtriangles;
TRIANGLE* triangle; } SECTOR;
SECTOR sector1; // Our Model Goes Here:
void readstr(FILE *f,char *string) {
do
{
fgets(string, 255, f);
} while ((string[0] == '/') || (string[0] == '\n'));
return; } void SetupWorld() { float x, y, z, u, v; int numtriangles; FILE *filein; char oneline[255];
filein = fopen("data/world.txt", "rt"); // File To Load World Data From
sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles); sector1.triangle = new TRIANGLE[numtriangles]; sector1.numtriangles = numtriangles;
for (int loop = 0; loop < numtriangles; loop++) {
for (int vert = 0; vert < 3; vert++) {
readstr(filein,oneline);
sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v); sector1.triangle[loop].vertex[vert].x = x; sector1.triangle[loop].vertex[vert].y = y; sector1.triangle[loop].vertex[vert].z = z; sector1.triangle[loop].vertex[vert].u = u; sector1.triangle[loop].vertex[vert].v = v; } } fclose(filein); return; }
AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL }
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture
memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (TextureImage[0]=LoadBMP("Data/Mud.bmp")) {
Status=TRUE; // Set The Status To TRUE
glGenTextures(3, &texture[0]); // Create Three Textures
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create Linear Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, >sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_
NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); }
if (TextureImage[0]) // If Texture Exists {
if (TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
return Status; // Return The Status }
void resize(int width, int height) // Resize And Initialize The GL Window
{
if (height==0)
{
height=1;
// Making Height Equal One }
glViewport(0,0,width,height); // Reset
The Current Viewport
glMatrixMode(GL_PROJECTION); // Select
The Projection Matrix
glLoadIdentity(); //
Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); //
Select The Modelview Matrix
glLoadIdentity(); //
Reset The Modelview Matrix }
void init() // All
Setup For OpenGL Goes Here {
if (!LoadGLTextures()) //
Jump To Texture Loading Routine {
return; //
If Texture Didn't Load Return FALSE }
glEnable(GL_TEXTURE_2D); //
Enable Texture Mapping
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Set
The Blending Function For Translucency
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This
Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); //
The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); //
Enables Depth Testing
glShadeModel(GL_SMOOTH); //
Enables Smooth Color Shading
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
SetupWorld();
return; //
Initialization Went OK }
{
// called if timer event
// ...advance the state of animation incrementally... //rot+=1;
glutPostRedisplay(); // request redisplay
glutTimerFunc(100, myTimeOut, 0); // request next timer event }
void myKeyboard(unsigned char key,int x, int y) {
}
void mySpecialKeyboard(int key,int x, int y) {
if(key==GLUT_KEY_UP) {
xpos -= (float)sin(heading*piover180) * 0.05f; zpos -= (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle >= 359.0f) { walkbiasangle = 0.0f; } else { walkbiasangle+= 10; }
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
}
else if(key==GLUT_KEY_DOWN) {
xpos += (float)sin(heading*piover180) * 0.05f; zpos += (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle <= 1.0f) { walkbiasangle = 359.0f; } else { walkbiasangle-= 10; }
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
} else if(key==GLUT_KEY_RIGHT) { heading -= 1.0f; yrot = heading; } else if(key==GLUT_KEY_LEFT) { heading += 1.0f; yrot = heading; } else if(key==GLUT_KEY_PAGE_UP) {
z-=0.02f; lookupdown-= 1.0f; } else if(key==GLUT_KEY_PAGE_DOWN) { z+=0.02f; lookupdown+= 1.0f; } }
void mydisplay(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); //
Reset The View
GLfloat x_m, y_m, z_m, u_m, v_m; GLfloat xtrans = -xpos;
GLfloat ztrans = -zpos;
GLfloat ytrans = -walkbias-0.25f; GLfloat sceneroty = 360.0f - yrot;
int numtriangles;
glRotatef(lookupdown,1.0f,0,0); glRotatef(sceneroty,0,1.0f,0);
glTranslatef(xtrans, ytrans, ztrans);
glBindTexture(GL_TEXTURE_2D, texture[filter]); numtriangles = sector1.numtriangles;
// Process Each Triangle
for (int loop_m = 0; loop_m < numtriangles; loop_m++) { glBegin(GL_TRIANGLES); glNormal3f( 0.0f, 0.0f, 1.0f); x_m = sector1.triangle[loop_m].vertex[0].x; y_m = sector1.triangle[loop_m].vertex[0].y; z_m = sector1.triangle[loop_m].vertex[0].z; u_m = sector1.triangle[loop_m].vertex[0].u; v_m = sector1.triangle[loop_m].vertex[0].v; glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m); x_m = sector1.triangle[loop_m].vertex[1].x; y_m = sector1.triangle[loop_m].vertex[1].y; z_m = sector1.triangle[loop_m].vertex[1].z; u_m = sector1.triangle[loop_m].vertex[1].u; v_m = sector1.triangle[loop_m].vertex[1].v; glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m); x_m = sector1.triangle[loop_m].vertex[2].x; y_m = sector1.triangle[loop_m].vertex[2].y; z_m = sector1.triangle[loop_m].vertex[2].z; u_m = sector1.triangle[loop_m].vertex[2].u; v_m = sector1.triangle[loop_m].vertex[2].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m); glEnd(); } glFlush(); glutSwapBuffers(); }
int main(int argc, char** argv) {
glutInit(&argc,argv);
glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("simple"); // callbacks glutDisplayFunc(mydisplay); glutKeyboardFunc(myKeyboard); glutSpecialFunc(mySpecialKeyboard); glutTimerFunc(100, myTimeOut, 0); glutReshapeFunc(resize); init(); glutMainLoop(); return 0; }
World.txt
NUMPOLLIES 36 // Floor 1 -3.0 0.0 -3.0 0.0 6.0 -3.0 0.0 3.0 0.0 0.0 3.0 0.0 3.0 6.0 0.0 -3.0 0.0 -3.0 0.0 6.0 3.0 0.0 -3.0 6.0 6.0 3.0 0.0 3.0 6.0 0.0 // Ceiling 1 -3.0 1.0 -3.0 0.0 6.0 -3.0 1.0 3.0 0.0 0.0 3.0 1.0 3.0 6.0 0.0 -3.0 1.0 -3.0 0.0 6.0 3.0 1.0 -3.0 6.0 6.0 3.0 1.0 3.0 6.0 0.0 // A1-2.0 1.0 -2.0 0.0 1.0 -2.0 0.0 -2.0 0.0 0.0 -0.5 0.0 -2.0 1.5 0.0 -2.0 1.0 -2.0 0.0 1.0 -0.5 1.0 -2.0 1.5 1.0 -0.5 0.0 -2.0 1.5 0.0 // A2 2.0 1.0 -2.0 2.0 1.0 2.0 0.0 -2.0 2.0 0.0 0.5 0.0 -2.0 0.5 0.0 2.0 1.0 -2.0 2.0 1.0 0.5 1.0 -2.0 0.5 1.0 0.5 0.0 -2.0 0.5 0.0 // B1 -2.0 1.0 2.0 2.0 1.0 -2.0 0.0 2.0 2.0 0.0 -0.5 0.0 2.0 0.5 0.0 -2.0 1.0 2.0 2.0 1.0 -0.5 1.0 2.0 0.5 1.0 -0.5 0.0 2.0 0.5 0.0 // B2 2.0 1.0 2.0 2.0 1.0 2.0 0.0 2.0 2.0 0.0 0.5 0.0 2.0 0.5 0.0 2.0 1.0 2.0 2.0 1.0 0.5 1.0 2.0 0.5 1.0 0.5 0.0 2.0 0.5 0.0 // C1 -2.0 1.0 -2.0 0.0 1.0 -2.0 0.0 -2.0 0.0 0.0 -2.0 0.0 -0.5 1.5 0.0 -2.0 1.0 -2.0 0.0 1.0 -2.0 1.0 -0.5 1.5 1.0 -2.0 0.0 -0.5 1.5 0.0 // C2 -2.0 1.0 2.0 2.0 1.0 -2.0 0.0 2.0 2.0 0.0 -2.0 0.0 0.5 0.5 0.0 -2.0 1.0 2.0 2.0 1.0 -2.0 1.0 0.5 0.5 1.0 -2.0 0.0 0.5 0.5 0.0 // D1 2.0 1.0 -2.0 0.0 1.0 2.0 0.0 -2.0 0.0 0.0 2.0 0.0 -0.5 1.5 0.0
2.0 1.0 -2.0 0.0 1.0 2.0 1.0 -0.5 1.5 1.0 2.0 0.0 -0.5 1.5 0.0 // D2 2.0 1.0 2.0 2.0 1.0 2.0 0.0 2.0 2.0 0.0 2.0 0.0 0.5 0.5 0.0 2.0 1.0 2.0 2.0 1.0 2.0 1.0 0.5 0.5 1.0 2.0 0.0 0.5 0.5 0.0 // Upper hallway - L -0.5 1.0 -3.0 0.0 1.0 -0.5 0.0 -3.0 0.0 0.0 -0.5 0.0 -2.0 1.0 0.0 -0.5 1.0 -3.0 0.0 1.0 -0.5 1.0 -2.0 1.0 1.0 -0.5 0.0 -2.0 1.0 0.0 // Upper hallway - R 0.5 1.0 -3.0 0.0 1.0 0.5 0.0 -3.0 0.0 0.0 0.5 0.0 -2.0 1.0 0.0 0.5 1.0 -3.0 0.0 1.0 0.5 1.0 -2.0 1.0 1.0 0.5 0.0 -2.0 1.0 0.0 // Lower hallway - L -0.5 1.0 3.0 0.0 1.0 -0.5 0.0 3.0 0.0 0.0 -0.5 0.0 2.0 1.0 0.0 -0.5 1.0 3.0 0.0 1.0 -0.5 1.0 2.0 1.0 1.0 -0.5 0.0 2.0 1.0 0.0 // Lower hallway - R 0.5 1.0 3.0 0.0 1.0 0.5 0.0 3.0 0.0 0.0 0.5 0.0 2.0 1.0 0.0 0.5 1.0 3.0 0.0 1.0 0.5 1.0 2.0 1.0 1.0 0.5 0.0 2.0 1.0 0.0 // Left hallway - Lw -3.0 1.0 0.5 1.0 1.0 -3.0 0.0 0.5 1.0 0.0 -2.0 0.0 0.5 0.0 0.0 -3.0 1.0 0.5 1.0 1.0 -2.0 1.0 0.5 0.0 1.0 -2.0 0.0 0.5 0.0 0.0 // Left hallway - Hi
-3.0 1.0 -0.5 1.0 1.0 -3.0 0.0 -0.5 1.0 0.0 -2.0 0.0 -0.5 0.0 0.0 -3.0 1.0 -0.5 1.0 1.0 -2.0 1.0 -0.5 0.0 1.0 -2.0 0.0 -0.5 0.0 0.0 // Right hallway - Lw 3.0 1.0 0.5 1.0 1.0 3.0 0.0 0.5 1.0 0.0 2.0 0.0 0.5 0.0 0.0 3.0 1.0 0.5 1.0 1.0 2.0 1.0 0.5 0.0 1.0 2.0 0.0 0.5 0.0 0.0 // Right hallway - Hi 3.0 1.0 -0.5 1.0 1.0 3.0 0.0 -0.5 1.0 0.0 2.0 0.0 -0.5 0.0 0.0 3.0 1.0 -0.5 1.0 1.0 2.0 1.0 -0.5 0.0 1.0 2.0 0.0 -0.5 0.0 0.0
Perhatikan loop rendering yang terjadi pada void mydisplay() yang memperlihatkan
bagaimana suatu model di render secara otomatis.
TUGAS: Coba untuk merancang model 3D dengan membuat file dengan format di atas.
Program 14 memberi ilustrasi tentang bagaimana suatu file .3ds dibaca dan dirender.
Carilah model 3D dalam format .3ds lengkap dengan texture yang berkaitan. Perhatikan
pula loop renderingnya.
TUGAS: Dari membaca file 3dsloader.h dan 3dsloader.cpp, terangkan format dari file
.3ds yang dapat dibaca oleh Program 14.
Program 14.
Tutorial4.h
/********************************************************** * * TYPES DECLARATION * *********************************************************/#define MAX_VERTICES 8000 // Max number of vertices (for each object)
#define MAX_POLYGONS 8000 // Max number of polygons (for each object)
// Our vertex type
float x,y,z; }vertex_type;
// The polygon (triangle), 3 numbers that aim 3 vertices
typedef struct{ int a,b,c; }polygon_type;
// The mapcoord type, 2 texture coordinates for each vertex
typedef struct{ float u,v; }mapcoord_type; // The object type
typedef struct { char name[20]; int vertices_qty; int polygons_qty; vertex_type vertex[MAX_VERTICES]; polygon_type polygon[MAX_POLYGONS]; mapcoord_type mapcoord[MAX_VERTICES]; int id_texture; } obj_type, *obj_type_ptr;
Texture.h
extern int num_texture;
extern int LoadBitmap(char *filename);
Texture.cpp
#include <stdio.h> #include <windows.h> #include <GL/glut.h> #include "texture.h" /********************************************************** * * VARIABLES DECLARATION * *********************************************************/int num_texture=-1; //Counter to keep track of the last loaded texture
/********************************************************** *
* FUNCTION LoadBitmap(char *) *
* This function loads a bitmap file and return the OpenGL reference ID to use that texture
*
*********************************************************/
int LoadBitmap(char *filename) {
int i, j=0; //Index variables FILE *l_file; //File pointer
unsigned char *l_texture; //The pointer to the memory zone in which we will load the texture
// windows.h gives us these types to work with the Bitmap files BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoheader; RGBTRIPLE rgb;
num_texture++; // The counter of the current texture is increased if( (l_file = fopen(filename, "rb"))==NULL) return (-1); // Open the file for reading
fread(&fileheader, sizeof(fileheader), 1, l_file); // Read the fileheader
fseek(l_file, sizeof(fileheader), SEEK_SET); // Jump the fileheader fread(&infoheader, sizeof(infoheader), 1, l_file); // and read the infoheader
// Now we need to allocate the memory for our image (width * height * color deep)
l_texture = (byte *) malloc(infoheader.biWidth * infoheader.biHeight * 4);
// And fill it with zeros
memset(l_texture, 0, infoheader.biWidth * infoheader.biHeight * 4);
// At this point we can read every pixel of the image for (i=0; i < infoheader.biWidth*infoheader.biHeight; i++) {
// We load an RGB value from the file fread(&rgb, sizeof(rgb), 1, l_file);
// And store it
l_texture[j+0] = rgb.rgbtRed; // Red component l_texture[j+1] = rgb.rgbtGreen; // Green component l_texture[j+2] = rgb.rgbtBlue; // Blue component l_texture[j+3] = 255; // Alpha value
j += 4; // Go to the next position }
fclose(l_file); // Closes the file stream
glBindTexture(GL_TEXTURE_2D, num_texture); // Bind the ID texture specified by the 2nd parameter
// The next commands sets the texture parameters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // If the u,v coordinates overflow the range 0,1 the image is repeated
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // The magnification function ("linear" produces better results)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //The minifying function
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // We don't combine the color with the original surface color, use only the texture map.
// Finally we define the 2d texture
glTexImage2D(GL_TEXTURE_2D, 0, 4, infoheader.biWidth, infoheader.biHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, l_texture); // And create 2d mipmaps for the minifying function
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, infoheader.biWidth, infoheader.biHeight, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);
free(l_texture); // Free the memory we used to load the texture return (num_texture); // Returns the current texture OpenGL ID }
3dsloader.h
/********************************************************** *
* FUNCTION Load3DS (obj_type_ptr, char *) *
* This function loads a mesh from a 3ds file.
* Please note that we are loading only the vertices, polygons and mapping lists.
* If you need to load meshes with advanced features as for example: * multi objects, materials, lights and so on, you must insert other chunk parsers.
*
*********************************************************/
extern char Load3DS (obj_type_ptr ogg, char *filename);
3dsloader.cpp
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <io.h> #include "tutorial4.h" #include "3dsloader.h" /********************************************************** ** FUNCTION Load3DS (obj_type_ptr, char *) *
* This function loads a mesh from a 3ds file.
* Please note that we are loading only the vertices, polygons and mapping lists.
* If you need to load meshes with advanced features as for example: * multi objects, materials, lights and so on, you must insert other chunk parsers.
*
*********************************************************/
char Load3DS (obj_type_ptr p_object, char *p_filename) {
int i; //Index variable
FILE *l_file; //File pointer
unsigned short l_chunk_id; //Chunk identifier
unsigned int l_chunk_lenght; //Chunk lenght
unsigned char l_char; //Char variable
unsigned short l_qty; //Number of elements in each chunk
unsigned short l_face_flags; //Flag that stores some face information
if ((l_file=fopen (p_filename, "rb"))== NULL) return 0; //Open the file
while (ftell (l_file) < filelength (fileno (l_file))) //Loop to scan the whole file
{
//getche(); //Insert this command for debug (to wait for keypress for each chuck reading)
fread (&l_chunk_id, 2, 1, l_file); //Read the chunk header printf("ChunkID: %x\n",l_chunk_id);
fread (&l_chunk_lenght, 4, 1, l_file); //Read the lenght of the chunk
printf("ChunkLenght: %x\n",l_chunk_lenght);
switch (l_chunk_id) {
//--- MAIN3DS --- // Description: Main chunk, contains all the other chunks
// Chunk ID: 4d4d
// Chunk Lenght: 0 + sub chunks
//---
case 0x4d4d:
break;
//--- EDIT3DS ---
// Description: 3D Editor chunk, objects layout info // Chunk ID: 3d3d (hex)
// Chunk Lenght: 0 + sub chunks
//---
case 0x3d3d:
break;
//--- EDIT_OBJECT --- // Description: Object block, info for each object
// Chunk ID: 4000 (hex)
// Chunk Lenght: len(object name) + sub chunks //---
case 0x4000: i=0;
do
{
fread (&l_char, 1, 1, l_file); p_object->name[i]=l_char;
i++;
}while(l_char != '\0' && i<20);
break;
//--- OBJ_TRIMESH ---
// Description: Triangular mesh, contains chunks for 3d mesh info
// Chunk ID: 4100 (hex)
// Chunk Lenght: 0 + sub chunks
//---
case 0x4100:
break;
//--- TRI_VERTEXL --- // Description: Vertices list
// Chunk ID: 4110 (hex)
// Chunk Lenght: 1 x unsigned short (number of vertices)
// + 3 x float (vertex coordinates) x (number of vertices)
// + sub chunks
//---
case 0x4110:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
p_object->vertices_qty = l_qty;
printf("Number of vertices: %d\n",l_qty); for (i=0; i<l_qty; i++)
{
fread (&p_object->vertex[i].x,
sizeof(float), 1, l_file);
printf("Vertices list x: %f\n",p_object->vertex[i].x);
fread (&p_object->vertex[i].y, sizeof(float), 1, l_file);
printf("Vertices list y: %f\n",p_object->vertex[i].y);
fread (&p_object->vertex[i].z,
sizeof(float), 1, l_file);
printf("Vertices list z: %f\n",p_object->vertex[i].z);
}
break;
//--- TRI_FACEL1 --- // Description: Polygons (faces) list
// Chunk ID: 4120 (hex)
polygons)
// + 3 x unsigned short (polygon points) x (number of polygons)
// + sub chunks
//---
case 0x4120:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
p_object->polygons_qty = l_qty;
printf("Number of polygons: %d\n",l_qty); for (i=0; i<l_qty; i++)
{
fread (&p_object->polygon[i].a, sizeof
(unsigned short), 1, l_file);
printf("Polygon point a: %d\n",p_object->polygon[i].a);
fread (&p_object->polygon[i].b, sizeof
(unsigned short), 1, l_file);
printf("Polygon point b: %d\n",p_object->polygon[i].b);
fread (&p_object->polygon[i].c, sizeof
(unsigned short), 1, l_file);
printf("Polygon point c: %d\n",p_object->polygon[i].c);
fread (&l_face_flags, sizeof (unsigned short), 1, l_file);
printf("Face flags: %x\n",l_face_flags); }
break;
//--- TRI_MAPPINGCOORS --- // Description: Vertices list
// Chunk ID: 4140 (hex)
// Chunk Lenght: 1 x unsigned short (number of mapping points)
// + 2 x float (mapping coordinates) x (number of mapping points)
// + sub chunks
//---
case 0x4140:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
for (i=0; i<l_qty; i++) {
fread (&p_object->mapcoord[i].u, sizeof
(float), 1, l_file);
printf("Mapping list u: %f\n",p_object->mapcoord[i].u);
fread (&p_object->mapcoord[i].v, sizeof (float), 1, l_file);
printf("Mapping list v: %f\n",p_object->mapcoord[i].v);
} break;
//--- Skip unknow chunks --- //We need to skip all the chunks that currently we
don't use
//We use the chunk lenght information to set the file pointer
//to the same level next chunk
//---
default:
fseek(l_file, l_chunk_lenght-6, SEEK_CUR); }
}
fclose (l_file); // Closes the file stream
return (1); // Returns ok }
Main.h
#define MAX_VERTICES 8000 // Max number of vertices (for each object)
#define MAX_POLYGONS 8000 // Max number of polygons (for each object)
// Our vertex type
typedef struct{ float x,y,z; }vertex_type;
// The polygon (triangle), 3 numbers that aim 3 vertices
typedef struct{ int a,b,c; }polygon_type;
// The mapcoord type, 2 texture coordinates for each vertex
typedef struct{ float u,v; }mapcoord_type; // The object type
typedef struct { char name[20]; int vertices_qty; int polygons_qty; vertex_type vertex[MAX_VERTICES]; polygon_type polygon[MAX_POLYGONS]; mapcoord_type mapcoord[MAX_VERTICES]; int id_texture; } obj_type, *obj_type_ptr;
Main.cpp
#include <windows.h> #include <GL/glut.h> #include "tutorial4.h" #include "texture.h" #include "3dsloader.h"// The width and height of your window, change them as you like
int screen_width=640;
int screen_height=480;
// Absolute rotation values (0-359 degrees) and rotation increments for each frame
double rotation_x=0, rotation_x_increment=0.1;
double rotation_y=0, rotation_y_increment=0.05;
double rotation_z=0, rotation_z_increment=0.03;
// Flag for rendering as lines or filled polygons
int filling=1; //0=OFF 1=ON
//Now the object is generic, the cube has annoyed us a little bit, or not?
obj_type object;
void init(void) {
glClearColor(0.0, 0.0, 0.0, 0.0); // This clear the background color to black
glShadeModel(GL_SMOOTH); // Type of shading for the polygons
// Viewport transformation
glViewport(0,0,screen_width,screen_height); // Projection transformation
glMatrixMode(GL_PROJECTION); // Specifies which matrix stack is the target for matrix operations
glLoadIdentity(); // We initialize the projection matrix as identity
gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,10.0f, 10000.0f); // We define the "viewing volume"
glEnable(GL_DEPTH_TEST); // We enable the depth test (also called z buffer)
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); // Polygon rasterization mode (polygon filled)
glEnable(GL_TEXTURE_2D); // This Enable the Texture mapping Load3DS (&object,"spaceship.3ds");
object.id_texture=LoadBitmap("spaceshiptexture.bmp"); // The Function LoadBitmap() return the current texture ID
// If the last function returns -1 it means the file was not found so we exit from the program
if (object.id_texture==-1) {
MessageBox(NULL,"Image file: spaceshiptexture.bmp not found", "Zetadeck",MB_OK | MB_ICONERROR);
exit (0); }
}
{
screen_width=width; // We obtain the new screen width values and store it
screen_height=height; // Height value
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We clear both the color and the depth buffer so to draw the next frame
glViewport(0,0,screen_width,screen_height); // Viewport transformation
glMatrixMode(GL_PROJECTION); // Projection transformation
glLoadIdentity(); // We initialize the projection matrix as identity
gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,10.0f, 10000.0f);
glutPostRedisplay (); // This command redraw the scene (it calls the same routine of glutDisplayFunc)
}
void keyboard (unsigned char key, int x, int y) { switch (key) { case ' ': rotation_x_increment=0; rotation_y_increment=0; rotation_z_increment=0; break; case 'r': case 'R': if (filling==0) {
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); // Polygon rasterization mode (polygon filled)
filling=1; }
else {
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); // Polygon rasterization mode (polygon outlined)
filling=0; }
break; }
}
void keyboard_s (int key, int x, int y) { switch (key) { case GLUT_KEY_UP: rotation_x_increment = rotation_x_increment +0.005; break; case GLUT_KEY_DOWN:
rotation_x_increment = rotation_x_increment -0.005; break; case GLUT_KEY_LEFT: rotation_y_increment = rotation_y_increment +0.005; break; case GLUT_KEY_RIGHT: rotation_y_increment = rotation_y_increment -0.005; break; } }
void display(void) {
int l_index;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); // Modeling transformation
glLoadIdentity(); // Initialize the model matrix as identity
glTranslatef(0.0,0.0,-300); // We move the object forward (the model matrix is multiplied by the translation matrix)
rotation_x = rotation_x + rotation_x_increment; rotation_y = rotation_y + rotation_y_increment; rotation_z = rotation_z + rotation_z_increment; if (rotation_x > 359) rotation_x = 0;
if (rotation_y > 359) rotation_y = 0; if (rotation_z > 359) rotation_z = 0;
glRotatef(rotation_x,1.0,0.0,0.0); // Rotations of the object (the model matrix is multiplied by the rotation matrices)
glRotatef(rotation_y,0.0,1.0,0.0); glRotatef(rotation_z,0.0,0.0,1.0);
glBindTexture(GL_TEXTURE_2D, object.id_texture); // We set the active texture
glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
for (l_index=0;l_index<object.polygons_qty;l_index++) {
//--- FIRST VERTEX --- // Texture coordinates of the first vertex
glTexCoord2f( object.mapcoord[ object.polygon[l_index].a ].u, object.mapcoord[ object.polygon[l_index].a ].v); // Coordinates of the first vertex
glVertex3f( object.vertex[ object.polygon[l_index].a ].x, object.vertex[ object.polygon[l_index].a ].y, object.vertex[ object.polygon[l_index].a ].z); //Vertex definition
//--- SECOND VERTEX --- // Texture coordinates of the second vertex
glTexCoord2f( object.mapcoord[ object.polygon[l_index].b ].u, object.mapcoord[ object.polygon[l_index].b ].v); // Coordinates of the second vertex
glVertex3f( object.vertex[ object.polygon[l_index].b ].x, object.vertex[ object.polygon[l_index].b ].y, object.vertex[ object.polygon[l_index].b ].z);
//--- THIRD VERTEX --- // Texture coordinates of the third vertex
glTexCoord2f( object.mapcoord[ object.polygon[l_index].c ].u, object.mapcoord[ object.polygon[l_index].c ].v); // Coordinates of the Third vertex
glVertex3f( object.vertex[ object.polygon[l_index].c ].x, object.vertex[ object.polygon[l_index].c ].y, object.vertex[ object.polygon[l_index].c ].z); }
glEnd();
glFlush(); // This force the execution of OpenGL commands glutSwapBuffers(); // In double buffered mode we invert the positions of the visible buffer and the writing buffer
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(screen_width,screen_height); glutInitWindowPosition(0,0); glutCreateWindow("simple"); glutDisplayFunc(display); glutIdleFunc(display); glutReshapeFunc (resize); glutKeyboardFunc (keyboard); glutSpecialFunc (keyboard_s); init(); glutMainLoop(); return(0); }