• Tidak ada hasil yang ditemukan

Obyek Kompleks

Dalam dokumen EC5130 Grafika Komputer dan Pemrograman GPU (Halaman 42-63)

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); }

Dalam dokumen EC5130 Grafika Komputer dan Pemrograman GPU (Halaman 42-63)

Dokumen terkait