C Programming for Graphics (Msc CAGTA) Report - Jason Mahdjoub

Jan 21, 2005 - File structure has been chosen to been the simplest: [Number of .... unsigned int *ptfaces; //pointer to start of the vector containing. 'numfaces' ...
288KB taille 36 téléchargements 271 vues
C Programming for Graphics (Msc CAGTA) Report (January, 21th2005)

Jason MAHDOUB Course leader: Suresh Keswani

Summary

Summary ...................................................................2 Introduction ..............................................................3 Project analysis ........................................................3 Transformations ........................................................... Screens ........................................................................ GLUI interface .............................................................. Matrix structure and tools used ..................................

3 3 4 4

Design .......................................................................6

File structure................................................................ 6 Program structure ........................................................ 7

Technical part ..........................................................8

Normals calculation ..................................................... 8 Diagrammatic representation of the program............. 9

Program test ...........................................................10 Source Code ...........................................................11 defines.h ..................................................................... main.c ......................................................................... algebra.h..................................................................... algebra.c..................................................................... other_functions.h ....................................................... other_functions.c ....................................................... object_management.h................................................ object_management.c................................................ glut_functions.h.......................................................... glut_functions.c.......................................................... glui_functions.h .......................................................... glui functions.c...........................................................

Jason MAHDJOUB

2

11 11 15 16 19 19 21 21 26 27 34 34

University of TEESSIDE

Introduction

The aim of this project is to develop an application capable to load an object whose structure had to be defined, and to apply transformations swan on the mathematic module. The application had to help students to understand the matrix transformations. This report expose the analysis of the project, how choices have been made, how the program is structured, what algorithms were used, what problems have been found.

Project analysis Transformations All transformation relative to the mathematic module has been implemented: • Translation • Rotations around the X axis, the Y axis and the Z axis • Scale and over scale When a transformation is added, an animation is played to move to object onto its new position. All animations take exactly 2 seconds. Thus, the clock system was used to make animations during the same time.

Screens The window is divided in 4 screens to offer several views: • The 3D view on the top left enables you to see the object without any transformation. • The 3D view on the top right with the applied transformations • The top view on the down left • The front view on the down right

Jason MAHDJOUB

3

University of TEESSIDE

All the views, except the top left view, display the object with transformations applied on it. The top view and the front view use an orthogonal projection, whereas the others use a perspective projection. On each screen, it is possible to move the camera (translation, rotation and zoom) to have a better vision angle. Cameras are automatically repositioned when a new file is loaded.

GLUI interface As, it has been authorized on the brief, a GLUI interface has been used to make the program more intuitive. Thus, you can: • Load and save a file • Switch the dimension between 2D object and 3D object • Reset the camera’s positions. • Push and pop a transformation • Screen on the console current matrices.

Matrix structure and tools used A choice has been made for the matrix structure. On OPEN GL, matrices are represented by a 16 cells array, as the matrix represented in the right picture. Translations are done with the cells a12, a13 and a14 representing the 3D vector of translation (x,y,z). But, in the English mathematical convention, translations are represented by the values a3, a7 and a11. The last line is replaced by the last column and conversely. This has a consequence on matrix multiplication order. For instance, if you have a first transformation A applied to the object loaded, and a second transformation named B, the global matrix representing the two transformations is calculated by multiplying B per A in the OPEN GL convention and by multiplying A per B in the English mathematical convention. The matrix multiplication order between the two conventions is inversed. Another problem has appeared: It was asked for the project to manage all the matrices (projection, camera and transformations) and to multiply them to each vertex with our own tools without using the OPENG GL functions. With such method, you don’t use all graphical card acceleration possibilities and the

Jason MAHDJOUB

4

University of TEESSIDE

refresh may be lowest when you play animation or when you move the camera…especially if you have 4 screens to refresh! So it has been decided to multiply matrices throw OPEN GL function (glMultMatrix) in order to use more the graphical card. It has also been decided to respect the OPEN GL matrix multiplication order. Consequently, English mathematical conventions were not respected on the calculation. However, when you screen the current matrices, the English conventions are used. Thus, the English user will not see any difference.

What about using our own tools? All matrices are generated by personal functions. They aren’t applied to vertices during the display with personal functions because of the reasons invocated previously, but they are applied during the object safeguard. It’s proof that personal function work as well as if there were applied directly on the display’s phase.

What about the 2D transformations? A 2D transformation is a 3D transformation without considering the third dimension. Thus, 4x4 matrices have been used for the 2D transformations. The users don’t see any thing because Z value can’t be set on the translation and the scale, and only the rotation around the Z axis can be applied. So, don’t working with 3x3 matrices avoid to duplicate all functions working with 4x4 matrices and to overload the source code. Moreover, OPEN GL works only with 4x4 matrices!

Jason MAHDJOUB

5

University of TEESSIDE

Design File structure Files had to contain a 2D object and a 3D object. Extension chosen was TXT. File structure has been chosen to been the simplest:

[Number of 3D vertices] [Number of 3D faces] [3D vertices] . . . [3D vertices] [3D faces] . . . [3D faces] [Number of 2D vertices] [2D vertices] . . . [2D vertices]

3D vertices are represented as next: X Y Z 2D vertices are represented as next: X Y 3D faces are represented as next: 3

INDEX_OF_POINT1

INDEX_OF_POINT2

INDEX_OF_POINT3

Normals are generated throw a personal function.

Jason MAHDJOUB

6

University of TEESSIDE

Program structure main.c contains the main function which initialises some global variables, creates and sets all the glut windows. The global variables are declared on the main.c file and initialised on the main function. They are declared as external on the others files. glut_functions.h and glut_functions.c contain functions (display, reshape, mouse, motion etc…) which are called back by GLUT. glui_functions.h and glui_functions.c contain functions which are in relation with GLUI: • glui_init incorporate the GLUI window onto the main window and create all the necessary widgets. • glui_control is call back by the GLUI buttons (or other widgets) when you click on its. • manage_widgets: when this function is called, widgets are enabled or disabled. It depends of the program status. For example, if no object is loaded, you can’t add translation or other transformations. object_management.h and object_management.c contain functions which enable to load objects, to save objects, and to generate normals. algebra.h and algebra.c contain mathematical structures and functions. It’s here where you can find the functions which enable you, for example, to get a dot product, a cross product, a multiplication between a matrix and a point or between two matrices etc… other_functions.h and other_functions.c contain functions which push or pop transformations, which update the global matrices or manage the chronometer (useful for the animation).

Jason MAHDJOUB

7

University of TEESSIDE

Technical part Normals calculation The aim is to calculate the normal of each vertex in order to enable the object to be lighted. The exact steps of the algorithm are described in the source code, so it will be presented here the general algorithm. In the one hand, the normal of each faces is calculated by doing a cross product:

Normal

A Here, the normal is obtained by doing a cross product between the vectors AB and AC. The normal vector is a unit vector.

C

B On the other hand, when all the normals of each face are got, we can calculate the normal of each point by making the faces normal average whose faces are adjacent to the current point:

N3

Here, the normal N is obtained by making the average with N1, N2, N3 and N4. To perfect the orientation of the normal, each adjacent normal to face is multiplied by the angle (in radian) formed at the concerned point. So the result is obtained as next: N=N1*A1+N2*A2+N3*A3+N4*A4

Jason MAHDJOUB

8

N4

N1

A3

A2

A1

A4

N

N2

University of TEESSIDE

Diagrammatic representation of the program

Jason MAHDJOUB

9

University of TEESSIDE

Program test

The program was test on different steps. First, the four screens with there cameras were created and tested with a “glutSolidCube()” as first object. GLUI widgets have been included at the same time, but without any effect on the program. Events of the button were developed progressively. Then, object loader and saver, the normal calculation function were developed (and tested). Exceptions were managed: for example, if you try to load a file which doesn’t exist, an error message will be screened. To test the functions which return projection matrix (orthogonal or perspective) or camera matrix, displays were compared with the OPEN GL original functions (glFrustum, glOrtho and gluLookAt). The content of these matrices was exactly the same content of the OPEN GL matrices. Their definitions were found on the MSDN website. At least, animation has been realised with other some perfection of the program. The program has no apparent bug, and all envisaged parts of the project have been realised. There is no problem to announce.

Jason MAHDJOUB

10

University of TEESSIDE

Source Code defines.h #ifndef ___DEFINES___ #define ___DEFINES___ /*Defines*/ #define WIDTH_MAIN_WINDOW 1024 //width of the main window #define HEIGHT_MAIN_WINDOW 600 //height of the main window #define MAX_ANIM_TIME 2000 //define the maximum time the animatation take when a transformation is added //glui_control function's defines #define ALTER_NUM_DIMENSION 0 #define LOAD_FILE 1 #define SAVE_FILE 2 #define RESET 4 #define ADD_TRANSLATION 7 #define ADD_ROTATIONX 8 #define ADD_ROTATIONY 9 #define ADD_ROTATIONZ 10 #define ADD_SCALE 11 #define ADD_SCALE_OVERALL 12 #define FINISH_ADD_TRANSLATION 15 #define FINISH_ADD_ROTATIONX 16 #define FINISH_ADD_ROTATIONY 17 #define FINISH_ADD_ROTATIONZ 18 #define FINISH_ADD_SCALE 19 #define FINISH_ADD_SCALE_OVERALL 20 #define FINISH_ADD_TRANSFORMATION 21 #define PRINT_PROJECTION_MATRIX 22 #define PRINT_CAM_MATRIX 23 #define PRINT_GLOBAL_TRANSFORMATION_MATRIX 24 #define RESET_TOP_LEFT 25 #define RESET_TOP_RIGHT 26 #define RESET_DOWN_LEFT 27 #define RESET_DOWN_RIGHT 28 #define CLEAR_TRANSFORMS 29 #define DEL_LAST_TRANSFORM 30 /*-------*/ #endif

main.c /*Inclusion of libraries*/ #include #include "GL/glui.h" #include "defines.h" #include "object_management.h" #include "algebre.h" #include "glut_functions.h" #include "glui_functions.h" #include "other_functions.h" /*----------------------*/ using namespace std; /*Definition of global variables*/ int id_main_window;//identifiate the main glut window int id_top_left_subwindow;//identifiate the top left glut window (containing the object to visualise without any transformation, perspective projection, 3d view) int id_top_right_subwindow;//identifiate the top right glut window (containing the transformed object to visualise, perspective projection, 3d view) int id_down_left_subwindow;//identifiate the down left glut window (containing the transformed object to visualise, orthogonal projection, top view) int id_down_right_subwindow;//identifiate the down right glut window (containing the transformed object to visualise, orthogonal projection, front view) GLUI *glui_window(NULL), *glui_translate_window(NULL), *glui_rotatex_window(NULL), *glui_rotatey_window(NULL), *glui_rotatez_window(NULL), *glui_scale_window(NULL), *glui_scaleoverall_window(NULL);//point to the glui window. That here were is defined the panel control GLUI_Rollout *rollout_file,*rollout_screen,*rollout_add_tr,*rollout_print; GLUI_Listbox *listbox_dim; GLUI_EditText *edittext_filename; GLUI_Spinner *translate_spinner_a, *translate_spinner_b, *translate_spinner_c, *scale_spinner_a, *scale_spinner_b, *scale_spinner_c, *scale_over_all_spinner, *rotationx_spinner, *rotationy_spinner, *rotationz_spinner;

Jason MAHDJOUB

11

University of TEESSIDE

GLUI_Button *button_translation, *button_rotationx, *button_rotationy, *button_rotationz, *button_scale, *button_scale_overall, *button_del_trans, *button_clear_trans, *button_print_proj, *button_print_cam, *button_print_global; int current_glui_transform_window; float light_position[]={10,10,10,0}; //camera //camera for the perpective projections pR3 pos_cam_top_left; pR3 ref_cam_top_left; vR3 vUp_cam_top_left; pR3 pos_cam_top_right; pR3 ref_cam_top_right; vR3 vUp_cam_top_right; //camera for the orthogonal projections pR3 pos_cam_down_left; pR3 pos_cam_down_right; //default parameters of the cameras pR3 default_pos_cam; pR3 default_ref_cam; vR3 default_vUp_cam; //matrices float m_proj_ortho[16];//projection's matrix float m_proj_pers[16];//projection's matrix float m_cam_top_left[16];//matrix which place the camera on top left screen float m_cam_top_right[16];//matrix which place the camera on top right screen float m_cam_down_left[16];//matrix which place the camera on down left screen float m_cam_down_right[16];//matrix which place the camera on down right screen float m_global_transformed[16];//global 3d transformtion matrix float m_global_transformed_2d[16];//global 2d transformtion matrix Transformation *pt_tr;//transformations applied to the object unsigned int numTransformation;//number of transformation applied Transformation *pt_tr_2d;//transformations applied to the object unsigned int numTransformation_2d;//number of transformation applied //this variables concerne the 3D object data unsigned int numvertices;//number of 3D object's vertices unsigned int numfaces; //number of 3D object's faces float *ptvertices; //pointer to start of the vector containing 'numvertices' vertices, that is to say '3*numvertices' floats float *ptnormals; //pointer to start of the vector containing 'numvertices' normals, that is to say '3*numvertices' floats unsigned int *ptfaces; //pointer to start of the vector containing 'numfaces' faces, that is to say '3*numfaces' unsigned int unsigned int gl_num_list_3d;//give a number for the OPEN GL's list of the 3d object //this variables concerne the 2D object data unsigned int num2dvertices;//number of 2D object's vertices float *pt2dvertices; //pointer to start of the vector containing 'num2dvertices' vertices, that is to say '2*numvertices' floats unsigned int gl_num_list_2d;//give a number for the OPEN GL's list of the 2d object //current parameters Transformation **current_pt_tr;//transformations (for the 2d or the 3d objects) applied to the object unsigned int *current_numTransformation;//number of transformation (for the 2d or the 3d objects) applied float *current_m_global_transformed;//global right matrix (for the 2d or the 3d objects)(include the transformations) unsigned int *current_gl_num_list; /*------------------------------*/ int main(int argc, char *argv[]) { puts("\n|-------------------------Guide--------------------------|"); puts("|Use the left button to make a translation of the camera.|"); puts("|Use the middle button to make a zoom of the camera. |"); puts("|Use the right button to make a rotation of the camera. |"); puts("|--------------------------------------------------------|\n"); /*initialisation of variables*/ { numvertices=0; numfaces=0; ptvertices=NULL; ptnormals=NULL; ptfaces=NULL;

Jason MAHDJOUB

12

University of TEESSIDE

numTransformation=0; numTransformation_2d=0; current_pt_tr=&pt_tr; current_numTransformation=&numTransformation; current_m_global_transformed=m_global_transformed; current_gl_num_list=&gl_num_list_3d; num2dvertices=0; current_glui_transform_window=0; default_pos_cam.x=10.0f; default_pos_cam.y=10.0f; default_pos_cam.z=10.0f; default_ref_cam.x=0.0f; default_ref_cam.y=0.0f; default_ref_cam.z=0.0f; default_vUp_cam.x=0.0f; default_vUp_cam.y=1.0f; default_vUp_cam.x=0.0f; vR3 v_tmp,v_tmp2; v_tmp.x=default_ref_cam.x-default_pos_cam.x; v_tmp.y=default_ref_cam.y-default_pos_cam.y; v_tmp.z=default_ref_cam.z-default_pos_cam.z; v_tmp2=getUnitNormal(v_tmp,default_vUp_cam); default_vUp_cam=getUnitNormal(v_tmp2,v_tmp); pos_cam_top_left.x=default_pos_cam.x; pos_cam_top_left.y=default_pos_cam.y; pos_cam_top_left.z=default_pos_cam.z; ref_cam_top_left.x=default_ref_cam.x; ref_cam_top_left.y=default_ref_cam.y; ref_cam_top_left.z=default_ref_cam.z; vUp_cam_top_left.x=default_vUp_cam.x; vUp_cam_top_left.y=default_vUp_cam.y; vUp_cam_top_left.z=default_vUp_cam.z; getCameraMatrix(m_cam_top_left,pos_cam_top_left,ref_cam_top_left,vUp_cam_top_left); pos_cam_top_right.x=default_pos_cam.x; pos_cam_top_right.y=default_pos_cam.y; pos_cam_top_right.z=default_pos_cam.z; ref_cam_top_right.x=default_ref_cam.x; ref_cam_top_right.y=default_ref_cam.y; ref_cam_top_right.z=default_ref_cam.z; vUp_cam_top_right.x=default_vUp_cam.x; vUp_cam_top_right.y=default_vUp_cam.y; vUp_cam_top_right.z=default_vUp_cam.z; getCameraMatrix(m_cam_top_right,pos_cam_top_right,ref_cam_top_right,vUp_cam_top_right); pos_cam_down_left.x=0.0f; pos_cam_down_left.y=10.0f; pos_cam_down_left.z=0.0f; pR3 p_tmp_ref; p_tmp_ref.x=p_tmp_ref.y=p_tmp_ref.z=0.0f; vR3 v_tmp_vUp; v_tmp_vUp.x=v_tmp_vUp.y=0.0f; v_tmp_vUp.z=-1.0f; update_matrix_cam_down_left(); pos_cam_down_right.x=0.0f; pos_cam_down_right.y=0.0f; pos_cam_down_right.z=10.f; v_tmp_vUp.y=1.0f; v_tmp_vUp.z=0.0f; update_matrix_cam_down_right(); }

updateTransformMatrix();

/*---------------------------*/ glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); /*creating and initialising of the main window*/ glutInitWindowSize (WIDTH_MAIN_WINDOW,HEIGHT_MAIN_WINDOW); glutInitWindowPosition (50 ,50); id_main_window=glutCreateWindow ("Graphical Mathematics Visualiser (Jason MAHDJOUB MSc CAGTA 2004/2005)"); getGLUI_Master().set_glutDisplayFunc(display_main); getGLUI_Master().set_glutReshapeFunc(reshape_main); glutPostRedisplay(); /*------------------------------------------*/ glui_init();//creating the glui panel control /*creating the top left window (screens objets whitout transformation)*/

Jason MAHDJOUB

13

University of TEESSIDE

id_top_left_subwindow=glutCreateSubWindow(id_main_window, 0, 0, (WIDTH_MAIN_WINDOWglui_window->getWidth())/2, HEIGHT_MAIN_WINDOW/2); glutDisplayFunc(pre_display_top_left); glutReshapeFunc(reshape_perspective_common); glutMouseFunc(mouse_top_left); glutMotionFunc(motion_perspective_common); glEnable(GL_DEPTH_TEST); /*Lights configuration*/ glEnable(GL_LIGHT0); float coul[]={0.9f,0.9f,0.9f,1.0f}; glLightfv(GL_LIGHT0,GL_SPECULAR,coul); glLightfv(GL_LIGHT0,GL_DIFFUSE,coul); coul[0]=coul[1]=coul[2]=0.1f; glLightfv(GL_LIGHT0,GL_AMBIENT,coul);

glEnable(GL_LIGHTING); /*--------------------*/ /*-------------------------------------------------*/ /*creating the top right subwindow (sreen the transformed objets)*/ id_top_right_subwindow=glutCreateSubWindow(id_main_window, (WIDTH_MAIN_WINDOWglui_window->getWidth())/2, 0, (WIDTH_MAIN_WINDOW-glui_window->getWidth())/2, HEIGHT_MAIN_WINDOW/2); glClearColor(0.4f,0.4f,0.4f,1.0f); glutDisplayFunc(pre_display_top_right); glutReshapeFunc(reshape_perspective_common); glutMouseFunc(mouse_top_right); glutMotionFunc(motion_perspective_common); glEnable(GL_DEPTH_TEST); /*Lights configuration*/ glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0,GL_AMBIENT,coul); coul[0]=coul[1]=coul[2]=0.9f; glLightfv(GL_LIGHT0,GL_SPECULAR,coul); glLightfv(GL_LIGHT0,GL_DIFFUSE,coul); glEnable(GL_LIGHTING); /*--------------------*/ /*-----------------------------------------------------------*/ /*creating the down right subwindow (screens the transformed object to visualise, orthogonal projection, top view)*/ id_down_left_subwindow=glutCreateSubWindow(id_main_window,0, HEIGHT_MAIN_WINDOW/2, (WIDTH_MAIN_WINDOW-glui_window->getWidth())/2, HEIGHT_MAIN_WINDOW/2); glClearColor(0.4f,0.4f,0.4f,1.0f); glutDisplayFunc(pre_display_down_left); glutReshapeFunc(reshape_ortho_common); glutMouseFunc(mouse_down_left); glutMotionFunc(motion_ortho_down_left); glEnable(GL_DEPTH_TEST); /*-----------------------------------------------------------*/ /*creating the down right subwindow (screens the transformed object to visualise, orthogonal projection, front view)*/ id_down_right_subwindow=glutCreateSubWindow(id_main_window, (WIDTH_MAIN_WINDOWglui_window->getWidth())/2, HEIGHT_MAIN_WINDOW/2, (WIDTH_MAIN_WINDOW-glui_window>getWidth())/2, HEIGHT_MAIN_WINDOW/2); glClearColor(0.4f,0.4f,0.4f,1.0f); glutDisplayFunc(pre_display_down_right); glutReshapeFunc(reshape_ortho_common); glutMouseFunc(mouse_down_right); glutMotionFunc(motion_ortho_down_right); glEnable(GL_DEPTH_TEST); /*-----------------------------------------------------------*/ /*generating OPEN GL's lists*/ gl_num_list_3d=glGenLists(1); gl_num_list_2d=glGenLists(1); /*---------------------------*/ manage_widgets(); glutMainLoop(); }

return 0;

Jason MAHDJOUB

14

University of TEESSIDE

algebra.h #ifndef ___ALGEBRE___ #define ___ALGEBRE___ #include #ifndef PI #define PI 3.141592653589793238462643383280f #endif #define #define #define #define #define #define

TRANSLATION 0 X_ROTATION 1 Y_ROTATION 2 Z_ROTATION 3 SCALE 4 SCALE_OVERALL 5

struct pR3 //represent en vertice in 3D { float x,y,z; }; struct vR3 //represent a vector in 3D { float x,y,z; }; /*return the vector ab with the points a and b*/ vR3 getVR3(const pR3 &a, const pR3 &b); /*return the distance between the points a and b*/ float getDist(const pR3 &a, const pR3 &b); /*return the dot product between the vectors a and b*/ float getDotProduct(const vR3 &a, const vR3 &b); /*=a^b. return the cross product between the vectors a and b*/ vR3 getNormal(const vR3 &a,const vR3 &b); /*=a^b. return the cross product between the vectors a and b. The normal returned is a unit vector.*/ vR3 getUnitNormal(const vR3 &a,const vR3 &b); /*normalize the vector passed as argument*/ void normalize(vR3 &); /*=a*m return the product between the point a and the matrix m*/ pR3 multiply_pR3_matrix(const pR3 &a, const float *m); /*=a*m return the product between the vector a and the matrix m*/ vR3 multiply_vR3_matrix(const vR3 &a, const float *m); /*=a*m the product between the point a and the matrix m is saved onto res*/ void multiply_pR3_matrixv(const float *a, const float *m, float *res); /*=a*m the product between the vector a and the matrix m is saved onto res*/ void multiply_vR3_matrixv(const float *a, const float *m, float *res); /*=m*a the product between the point a and the matrix m is saved onto res*/ void multiply_matrix_pR3v(const float *m, const float *a, float *res); /*=m*a the product between the vector a and the matrix m is saved onto res*/ void multiply_matrix_vR3v(const float *m, const float *a, float *res); /*res=a*b save the result of the product between a and b onto res*/ void multiply_matrix_matrix(const float *a, const float *b, float *res); /*return the matrix which correspond to camara whose coordinates are passed as argument*/ void getCameraMatrix(float *mat, const pR3 &pos, const pR3 &ref, vR3 vUP); /*generate a matrix of projection (perspective or orthogonal)*/ void getProjectionMatrix(float *m, float left,float right,float bottom,float top, float near,float far,bool frustum); struct Transformation /* can represent a tranlation, a rotation or scale*/ { char type;/*0 define the type of the transformation (TRANSLATION, [X | Y | Z]_ROTATION SCALE or SCALE_OVERALL)*/ /*if this transformation translation's vector if this transformation if this transformation if this transformation float a,b,c; };

reprensent a translation, a b and c will the coordinate represent a rotation, a will reprensent the angle (radian) represent a scale, a b and c will reprent the scale on the 3 axis represent a scale_overall, a will be the overall coefficient*/

/*return the matrix which correspond to the transformation passed as arguement. coeff had to take a value a value between 0.0f and 1.0f. At 0.0f the matrix returned will correspond to the identity matrix. And at 1.0f, it will correspond to the transformation passed as argument. There is an interpolation between the two values. It's usefull for the for animation of the transformation. */ void getMatrix(float *m, const Transformation &tr, float coeff); /*fucntions which create different transformations*/ void createTranslation(Transformation &tr, const vR3 &); void createX_Rotation(Transformation &tr, float angle); void createY_Rotation(Transformation &tr, float angle); void createZ_Rotation(Transformation &tr, float angle); void createScale(Transformation &tr, float x_scale, float y_scale, float z_scale); void createScaleOverall(Transformation &tr, float overall_scale); /*return a matrice of rotation. You can give the axe of rotation and the center of rotation*/ void getMatrixRotationC(float angle, const vR3 &axe, const pR3 ¢re, float *res); #endif

Jason MAHDJOUB

15

University of TEESSIDE

algebra.c #include "algebre.h" #include vR3 getVR3(const pR3 &a, const pR3 &b) { vR3 res; res.x=b.x-a.x; res.y=b.y-a.y; res.z=b.z-a.z; return res; } float getDist(const pR3 &a, const pR3 &b) { return sqrtf((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y)+(b.z-a.z)*(b.z-a.z)); } float getDotProduct(const vR3 &a, const vR3 &b) { return a.x*b.x+a.y*b.y+a.z*b.z; } void normalize(vR3 &v) { float val=sqrtf(v.x*v.x+v.y*v.y+v.z*v.z); v.x/=val; v.y/=val; v.z/=val; } vR3 getNormal(const vR3 &a,const vR3 &b) { vR3 res; res.x=a.y*b.z-a.z*b.y; res.y=a.z*b.x-a.x*b.z; res.z=a.x*b.y-a.y*b.x; return res; } vR3 getUnitNormal(const vR3 &a,const vR3 &b) { vR3 res; res.x=a.y*b.z-a.z*b.y; res.y=a.z*b.x-a.x*b.z; res.z=a.x*b.y-a.y*b.x; float i=sqrtf(res.x*res.x+res.y*res.y+res.z*res.z); res.x/=i; res.y/=i; res.z/=i; return res; } pR3 multiply_pR3_matrix(const pR3 &a, const float *m) { pR3 res; res.x=(a.x*m[0]+a.y*m[1]+a.z*m[2]+m[3])/m[15]; res.y=(a.x*m[4]+a.y*m[5]+a.z*m[6]+m[7])/m[15]; res.z=(a.x*m[8]+a.y*m[9]+a.z*m[10]+m[11])/m[15]; return res; } vR3 multiply_vR3_matrix(const vR3 &a, const float *m) { vR3 res; res.x=(a.x*m[0]+a.y*m[1]+a.z*m[2])/m[15]; res.y=(a.x*m[4]+a.y*m[5]+a.z*m[6])/m[15]; res.z=(a.x*m[8]+a.y*m[9]+a.z*m[10])/m[15]; return res; } void multiply_pR3_matrixv(const float *a, const float *m, float *res) { res[0]=(a[0]*m[0]+a[1]*m[1]+a[2]*m[2]+m[3])/m[15]; res[1]=(a[0]*m[4]+a[1]*m[5]+a[2]*m[6]+m[7])/m[15]; res[2]=(a[0]*m[8]+a[1]*m[9]+a[2]*m[10]+m[11])/m[15]; } void multiply_vR3_matrixv(const vR3 &a, const float *m, float *res) { res[0]=(a.x*m[0]+a.y*m[1]+a.z*m[2])/m[15]; res[1]=(a.x*m[4]+a.y*m[5]+a.z*m[6])/m[15]; res[2]=(a.x*m[8]+a.y*m[9]+a.z*m[10])/m[15]; } void multiply_matrix_pR3v(const float *m, const float *a, float *res) { res[0]=(m[0]*a[0]+m[4]*a[1]+m[8]*a[2]+m[12])/m[15]; res[1]=(m[1]*a[0]+m[5]*a[1]+m[9]*a[2]+m[13])/m[15]; res[2]=(m[2]*a[0]+m[6]*a[1]+m[10]*a[2]+m[14])/m[15]; } void multiply_matrix_vR3v(const float *m, const float *a,float *res) { res[0]=(m[0]*a[0]+m[4]*a[1]+m[8]*a[2])/m[15]; res[1]=(m[1]*a[0]+m[5]*a[1]+m[9]*a[2])/m[15]; res[2]=(m[2]*a[0]+m[6]*a[1]+m[10]*a[2])/m[15]; } void

multiply_matrix_matrix(const float *a, const float *b, float *res)

Jason MAHDJOUB

16

University of TEESSIDE

{

res[0]=a[0]*b[0]+a[4]*b[1]+a[8]*b[2]+a[12]*b[3]; res[1]=a[1]*b[0]+a[5]*b[1]+a[9]*b[2]+a[13]*b[3]; res[2]=a[2]*b[0]+a[6]*b[1]+a[10]*b[2]+a[14]*b[3]; res[3]=a[3]*b[0]+a[7]*b[1]+a[11]*b[2]+a[15]*b[3]; res[4]=a[0]*b[4]+a[4]*b[5]+a[8]*b[6]+a[12]*b[7]; res[5]=a[1]*b[4]+a[5]*b[5]+a[9]*b[6]+a[13]*b[7]; res[6]=a[2]*b[4]+a[6]*b[5]+a[10]*b[6]+a[14]*b[7]; res[7]=a[3]*b[4]+a[7]*b[5]+a[11]*b[6]+a[15]*b[7]; res[8]=a[0]*b[8]+a[4]*b[9]+a[8]*b[10]+a[12]*b[11]; res[9]=a[1]*b[8]+a[5]*b[9]+a[9]*b[10]+a[13]*b[11]; res[10]=a[2]*b[8]+a[6]*b[9]+a[10]*b[10]+a[14]*b[11]; res[11]=a[3]*b[8]+a[7]*b[9]+a[11]*b[10]+a[15]*b[11]; res[12]=a[0]*b[12]+a[4]*b[13]+a[8]*b[14]+a[12]*b[15]; res[13]=a[1]*b[12]+a[5]*b[13]+a[9]*b[14]+a[13]*b[15]; res[14]=a[2]*b[12]+a[6]*b[13]+a[10]*b[14]+a[14]*b[15]; res[15]=a[3]*b[12]+a[7]*b[13]+a[11]*b[14]+a[15]*b[15];

} void getCameraMatrix(float *m, const pR3 &pos, const pR3 &ref, vR3 vUP) { //the formula have been got from the msdn website vR3 F=getVR3(pos,ref); float f_tmp; f_tmp=sqrtf(F.x*F.x+F.y*F.y+F.z*F.z); F.x/=f_tmp; F.y/=f_tmp; F.z/=f_tmp; vR3 s=getUnitNormal(F,vUP); vR3 u=getUnitNormal(s,F); m[0]=s.x; m[1]=u.x; m[2]=-F.x; m[3]=0.0f; m[4]=s.y; m[5]=u.y; m[6]=-F.y; m[7]=0.0f; m[8]=s.z; m[9]=u.z; m[10]=-F.z; m[11]=0.0f; m[12]=-pos.x*s.x-pos.y*s.y-pos.z*s.z; m[13]=-pos.x*u.x-pos.y*u.y-pos.z*u.z; m[14]=pos.x*F.x+pos.y*F.y+pos.z*F.z; m[15]=1.0f; } void getProjectionMatrix(float *m, float left,float right,float bottom,float top, float near,float far,bool frustum) { //the formula have been got from the msdn website if (frustum) { m[1]=m[2]=m[3]=m[4]=m[6]=m[7]=m[12]=m[13]=m[15]=0.0f; m[0]=(2.0f*near)/(right-left); m[5]=(2.0f*near)/(top-bottom); m[8]=(right+left)/(right-left); m[9]=(top+bottom)/(top-bottom); m[10]=-(far+near)/(far-near); m[11]=-1.0f; m[14]=-(2.0f*far*near)/(far-near); } else { m[1]=m[2]=m[3]=m[4]=m[6]=m[7]=m[8]=m[9]=m[11]=0.0f; m[0]=2.0f/(right-left); m[5]=2.0f/(top-bottom); m[10]=-2.0f/(far-near); m[12]=(right+left)/(right-left); m[13]=(top+bottom)/(top-bottom); m[14]=-(far+near)/(far-near); m[15]=1.0f; } } void getMatrix(float *m, const Transformation &tr, float coeff) { if (coeff1.0f) coeff=1.0f; m[12]=m[13]=m[14]=0.0f; switch (tr.type) { case TRANSLATION: m[0]=m[5]=m[10]=m[15]=1.0f; m[1]=m[2]=m[3]=m[4]=m[6]=m[7]=m[8]=m[9]=m[11]=0.0f; m[12]=tr.a*coeff; m[13]=tr.b*coeff; m[14]=tr.c*coeff; break; case X_ROTATION: m[0]=m[15]=1.0f;

Jason MAHDJOUB

17

University of TEESSIDE

m[1]=m[2]=m[3]=m[4]=m[7]=m[8]=m[11]=m[12]=m[13]=m[14]=0.0f; m[5]=m[10]=cosf(tr.a*coeff); m[6]=-(m[9]=sinf(tr.a*coeff)); break; case Y_ROTATION: m[5]=m[15]=1.0f; m[1]=m[3]=m[4]=m[6]=m[7]=m[9]=m[11]=m[12]=m[13]=m[14]=0.0f; m[0]=m[10]=cosf(tr.a*coeff); m[8]=-(m[2]=sinf(tr.a*coeff)); break; case Z_ROTATION: m[10]=m[15]=1.0f; m[2]=m[3]=m[6]=m[7]=m[8]=m[9]=m[11]=m[12]=m[13]=m[14]=0.0f; m[0]=m[5]=cosf(tr.a*coeff); m[1]=-(m[4]=sinf(tr.a*coeff)); break; case SCALE: m[1]=m[2]=m[3]=m[4]=m[6]=m[7]=m[8]=m[9]=m[11]=m[12]=m[13]=m[14]=0.0f; m[15]=1.0f; m[0]=coeff*(tr.a-1)+1; m[5]=coeff*(tr.b-1)+1; m[10]=coeff*(tr.c-1)+1; break; case SCALE_OVERALL: m[1]=m[2]=m[3]=m[4]=m[6]=m[7]=m[8]=m[9]=m[11]=m[12]=m[13]=m[14]=0.0f; m[0]=m[5]=m[10]=1.0f; m[15]=coeff*(tr.a-1)+1; break;

} } void createTranslation(Transformation &tr, const vR3 &v) { tr.type=TRANSLATION; tr.a=v.x; tr.b=v.y; tr.c=v.z; } void createX_Rotation(Transformation &tr, float angle) { tr.type=X_ROTATION; tr.a=angle; } void createY_Rotation(Transformation &tr, float angle) { tr.type=Y_ROTATION; tr.a=angle; } void createZ_Rotation(Transformation &tr, float angle) { tr.type=Z_ROTATION; tr.a=angle; }

void createScale(Transformation &tr, float x_scale, float y_scale, float z_scale) { tr.type=SCALE; tr.a=x_scale; tr.b=y_scale; tr.c=z_scale; } void createScaleOverall(Transformation &tr, float overall_scale) { tr.type=SCALE_OVERALL; tr.a=overall_scale; } void getMatrixRotationC(float angle, const vR3 &axe, const pR3 ¢re, float *res) { float cosa(cosf(angle)); float uncosa(1.0f-cosa); float sina(sinf(angle)); float *pt(res); *pt=(axe.x*axe.x)+cosa*(1.0f-(axe.x*axe.x)); *(++pt)=axe.x*axe.y*uncosa+(axe.z*sina); *(++pt)=axe.x*axe.z*uncosa-(axe.y*sina); *(++pt)=0.0f; *(++pt)=axe.x*axe.y*uncosa-(axe.z*sina); *(++pt)=axe.y*axe.y+cosa*(1.0f-(axe.y*axe.y)); *(++pt)=axe.y*axe.z*uncosa+(axe.x*sina); *(++pt)=0.0f; *(++pt)=axe.x*axe.z*uncosa+(axe.y*sina); *(++pt)=axe.y*axe.z*uncosa-(axe.x*sina); *(++pt)=axe.z*axe.z+cosa*(1.0f-(axe.z*axe.z)) ; *(++pt)=0.0f; *(++pt)=((1.0f-res[0])*centre.x)-(res[4]*centre.y)-(res[8]*centre.z); *(++pt)=-(res[1]*centre.x)+((1.0f-res[5])*centre.y)-(res[9]*centre.z); *(++pt)=-(res[2]*centre.x)-(res[6]*centre.y)+((1.0f-res[10])*centre.z); *(++pt)=1.0f; }

Jason MAHDJOUB

18

University of TEESSIDE

other_functions.h #ifndef ___OTHER_FUNCTIONS___ #define ___OTHER_FUNCTIONS___ #include "algebre.h" /*push a new transformation of the stack*/ void pushTransformation(const Transformation &tr); /*pop the last transformation added on the stack*/ void popTransformation(); /*clear the stack of transformations*/ void clearTransformations(); /*update global transform matrix...if animation is runned, the arguement t will be variable to made the last variation variable according the time ellapsed*/ void updateTransformMatrix(float t=1.0f); /*print the matrix passed as argument*/ void printMatrix(const float *); /*start the chronomether to 0*/ void startChronometer(); /*get elapsed time (millisecond) from the previous chronometer starting*/ unsigned long getTimeElapsed(); #endif

other_functions.c #include #include #include #include #include #include #include

"other_functions.h" "GL/glui.h" "defines.h"

/*-----------external variables---------------------------*/ … … … /*--------------------------------------------------------*/ void pushTransformation(const Transformation &tr) { Transformation *pt_tr_tmp; //allocation of an array larger then 1 cell pt_tr_tmp=(Transformation*)malloc(((*current_numTransformation)+1)*sizeof(Transformatio n)); //copying the old array memcpy(pt_tr_tmp,*current_pt_tr,(*current_numTransformation)*sizeof(Transformation)); //saving the new transformation pt_tr_tmp[(*current_numTransformation)++]=tr; //free the old array free(*current_pt_tr); //updating pointers *current_pt_tr=pt_tr_tmp; puts("A transformations has just been added:"); //screening the transform matrix which has just been added getMatrix(current_m_global_transformed,tr,1.0f); printMatrix(current_m_global_transformed); //updating global tranform matrices updateTransformMatrix();

} void popTransformation() { if ((*current_numTransformation)>0) { Transformation *pt_tr_tmp; //allocation of an array smaller than 1 cell pt_tr_tmp=(Transformation*)malloc((-(*current_numTransformation))*sizeof(Transformation)); //copying the old array memcpy(pt_tr_tmp,*current_pt_tr,(*current_numTransformation)*sizeof(Transformation)); //copying the old array free(*current_pt_tr); //updating pointers *current_pt_tr=pt_tr_tmp; //updating global tranform matrices updateTransformMatrix(); } } void clearTransformations() { /*clear all transform matrices*/ if (numTransformation)

Jason MAHDJOUB

19

University of TEESSIDE

{

free(pt_tr); numTransformation=0;

} if (numTransformation_2d) { free(pt_tr_2d); numTransformation_2d=0; } /*global matrices are unit matrices*/ m_global_transformed[1]=m_global_transformed[2]=m_global_transformed[3]=m_global_trans formed[4]=m_global_transformed[6]=m_global_transformed[7]=m_global_transformed[8]=m_gl obal_transformed[9]=m_global_transformed[11]=m_global_transformed[12]=m_global_transfo rmed[13]=m_global_transformed[14]=0.0f; m_global_transformed[0]=m_global_transformed[5]=m_global_transformed[10]=m_global_tran sformed[15]=1.0f; m_global_transformed_2d[1]=m_global_transformed_2d[2]=m_global_transformed_2d[3]=m_glo bal_transformed_2d[4]=m_global_transformed_2d[6]=m_global_transformed_2d[7]=m_global_t ransformed_2d[8]=m_global_transformed_2d[9]=m_global_transformed_2d[11]=m_global_trans formed_2d[12]=m_global_transformed_2d[13]=m_global_transformed_2d[14]=0.0f; m_global_transformed_2d[0]=m_global_transformed_2d[5]=m_global_transformed_2d[10]=m_gl obal_transformed_2d[15]=1.0f; } void updateTransformMatrix(float t) { if (*current_numTransformation) { static float m_tmp[16],m_tmp2[16]; static unsigned int num; num=(*current_numTransformation)-1; /*get the first transform matrix added, considering the animation time t (default equal to 1)*/ getMatrix(current_m_global_transformed,(*current_pt_tr)[num],t);

} else {

while (num--) { /*get all transform matrices added, considering the animation time t (default equal to 1)*/ getMatrix(m_tmp2,(*current_pt_tr)[num],1.0f); /*multiply the current matrice with the global matrice*/ multiply_matrix_matrix(current_m_global_transformed,m_tmp2,m_tmp); memcpy(current_m_global_transformed,m_tmp,16*sizeof(float)); } /*no transformation was added, so unit matrix are set up*/ current_m_global_transformed[1]=current_m_global_transformed[2]=current_m_global_tr ansformed[3]=current_m_global_transformed[4]=current_m_global_transformed[6]=curren t_m_global_transformed[7]=current_m_global_transformed[8]=current_m_global_transfor med[9]=current_m_global_transformed[11]=current_m_global_transformed[12]=current_m_ global_transformed[13]=current_m_global_transformed[14]=0.0f;

}

}

current_m_global_transformed[0]=current_m_global_transformed[5]=current_m_global_tr ansformed[10]=current_m_global_transformed[15]=1.0f;

void printMatrix(const float *m) { if (listbox_dim->curr_text[0]=='3') { /*we are in 3d mode, so we print a 4x4 matrix*/ printf("\t[ %f\t%f\t%f\t%f ]\n",m[0],m[4],m[8],m[3]); printf("\t[ %f\t%f\t%f\t%f ]\n",m[1],m[5],m[9],m[7]); printf("\t[ %f\t%f\t%f\t%f ]\n",m[2],m[6],m[10],m[11]); printf("\t[ %f\t%f\t%f\t%f ]\n",m[12],m[13],m[14],m[15]); } else { /*we are in 2d mode, so we print a 3x3 matrix*/ printf("\t[ %f\t%f\t%f ]\n",m[0],m[4],m[3]); printf("\t[ %f\t%f\t%f ]\n",m[1],m[5],m[7]); printf("\t[ %f\t%f\t%f ]\n",m[12],m[13],m[15]); } } void startChronometer() { timeb pttimeb; ftime(&pttimeb); starttime=pttimeb.millitm+(pttimeb.time)*1000; } unsigned long getTimeElapsed() { if (starttime) { timeb pttimeb; ftime((&pttimeb));

Jason MAHDJOUB

20

University of TEESSIDE

}

return (pttimeb.millitm)+(pttimeb.time)*1000-starttime; } else return MAX_ANIM_TIME+1;

object_management.h #ifndef ___OBJECT_MANAGEMENT___ #define ___OBJECT_MANAGEMENT___ #include /*generate normal to points for the current loaded object*/ void generateNormals(); /*load the object which extention is PLY*/ bool loadTXTObject(FILE *); /*save the current transformed object to a PLY format*/ bool saveTXTObject(FILE *); /*load the object which location is specified in the argument 'name'*/ bool loadObject(const char *name); /*save the current transformed object which location is specified in the argument 'name'*/ bool saveObject(const char *name); #endif

object_management.c #include #include #include #include #include #include #include

"object_management.h" "algebre.h" "GL\glui.h" "glui_functions.h" "defines.h"

/*-----------external variables---------------------------*/ … … … /*--------------------------------------------------------*/ //this function will generate the normals to points of the current object loaded void generateNormals() { printf("Generating point's normals..."); //Before generating normals to vertices, we tyo generate normals to faces //creating of a vector which will contain the 'numfaces' normals for each faces float *ptnormalfaces=(float*)malloc(numfaces*sizeof(float)*3); //initialasing of the mobil pointers unsigned int *ptf=ptfaces+numfaces*3; float *ptn=ptnormalfaces+numfaces*3; float *ptv2; //creating 3 points representing the 3 points of the current face pR3 p1,p2,p3; //creating 2 vectors defining the plan which contain the 3 previous created points vR3 v12, v13; //creating one nornal vR3 norm; //treatment of each faces unsigned int i=numfaces; while (i--) { //we take the 3 points of the current face ptv2=ptvertices+((*(--ptf))*3); p3.x=*ptv2; p3.y=*(++ptv2); p3.z=*(++ptv2); ptv2=ptvertices+((*(--ptf))*3); p2.x=*ptv2; p2.y=*(++ptv2); p2.z=*(++ptv2); ptv2=ptvertices+((*(--ptf))*3); p1.x=*ptv2; p1.y=*(++ptv2); p1.z=*(++ptv2); //we define the 2 vector defined the plan of the current face v12=getVR3(p1,p2); v13=getVR3(p1,p3); //we define the unit nornal of this face norm=getUnitNormal(v12,v13);

Jason MAHDJOUB

21

University of TEESSIDE

//save the current normal *(--ptn)=norm.z; *(--ptn)=norm.y; *(--ptn)=norm.x;

} //We can now generate the normals to each vertices of the current loaded object //Setting all values of the vector ptnormals in 0. The function memset use mainboard chipset and then It's the speediest solution to inialise a vector with the same value. memset(ptnormals,0,sizeof(float)*numvertices*3); //initialising the mobiles pointer float *ptnv=ptnormals,*ptnv2;//pointer to the vector of vertice's normals ptn=ptnormalfaces+numfaces*3;//pointer to the vector of face's normals ptf=ptfaces+numfaces*3; //pointer to the vector of faces unsigned int tmpf1,tmpf2,tmpf3; double angle1,angle2; double distab,distac,distbc; double a,b,c; unsigned int j=numfaces; while (j--) { //here we get the 3 points of the current face ptv2=ptvertices+(tmpf1=((*(--ptf))*3)); p3.x=*ptv2; p3.y=*(++ptv2); p3.z=*(++ptv2); ptv2=ptvertices+(tmpf2=((*(--ptf))*3)); p2.x=*ptv2; p2.y=*(++ptv2); p2.z=*(++ptv2); ptv2=ptvertices+(tmpf3=((*(--ptf))*3)); p1.x=*ptv2; p1.y=*(++ptv2); p1.z=*(++ptv2); /*For each point of the current faces ->p (it can be p1, p2 or p3) we caculate the angle in this point ->a we take the vertice's normal which position correspond to the vertice p in the vertice's vector ->n and we add to this vector whose value is equal to (0,0,0) at the beggening, the normal of the current face multiplied by the angle a When, all faces will be traversed, all vertice's normal should be calculated. */ distab=getDist(p1,p2); distac=getDist(p1,p3); distbc=getDist(p2,p3); //we work for the vertice's normal which corresponf to the point p3 ptnv2=ptnv+tmpf1+2;//we take the vector n angle1=acos(getDotProduct(getVR3(p3,p1),getVR3(p3,p2))/(distac*distbc)); //we caculate the angle a //we add the current face's normal mutiplied to the angle (*ptnv2)+=(angle1*(*(--ptn))); (*(--ptnv2))+=(angle1*(*(--ptn))); (*(--ptnv2))+=(angle1*(*(--ptn))); //we work for the vertice's normal which corresponf to the point p2 ptnv2=ptnv+tmpf2;//we take the vector n angle2= acos(getDotProduct( getVR3(p2,p1), getVR3(p2,p3)) / (distab * distbc)); //we caculate the angle a //we add the current face's normal mutiplied to the angle (*ptnv2)+=angle2*(*ptn); (*(++ptnv2))+=angle2*(*(++ptn)); (*(++ptnv2))+=angle2*(*(++ptn)); //we work for the vertice's normal which corresponf to the point p1 ptnv2=ptnv+tmpf3+2;//we take the vector n angle1=PI-angle1-angle2;//we caculate the angle a //we add the current face's normal mutiplied to the angle (*ptnv2)+=angle1*(*ptn); (*(--ptnv2))+=angle1*(*(--ptn)); (*(--ptnv2))+=angle1*(*(--ptn));

}

} //now, we got all the vertice's normal. we had to normalise them j=numvertices; ptnv+=numvertices*3; ptnv2=ptnv; while (j--) { c=*(--ptnv); b=*(--ptnv); a=*(--ptnv); angle1=sqrt(a*a+b*b+c*c); *(--ptnv2)=c/angle1; *(--ptnv2)=b/angle1; *(--ptnv2)=a/angle1; } //We don't need to face's normals, so we can delete it free(ptnormalfaces); puts("[OK]");

Jason MAHDJOUB

22

University of TEESSIDE

bool loadTXTObject(FILE *file) { //we get the number of vertices and the number of faces //the number of normals is equal to the number of vertices fscanf(file,"%u %u",&numvertices,&numfaces); //we allocate the correct number of coordinates for the vertices, normals et faces. There is 3 coordionate for each ptvertices=(float*)malloc(numvertices*sizeof(float)*3); ptnormals=(float*)malloc(numvertices*sizeof(float)*3); ptfaces=(unsigned int *)malloc(numfaces*sizeof(unsigned int)*3); //we scan now the vertices float *ptv=ptvertices; unsigned int numv=numvertices; default_pos_cam.x=0; while (numv--) { fscanf(file,"%f",ptv++); fscanf(file,"%f",ptv++); fscanf(file,"%f",ptv++); //we check the most far point from the center if ((default_pos_cam.y=ptv[-1]*ptv[-1]+ptv[-2]*ptv[-2]+ptv[-3]*ptv[-3]) > default_pos_cam.x) default_pos_cam.x=default_pos_cam.y; } //we scan now the faces char current[1024]; unsigned int *ptf=ptfaces; unsigned int numf=numfaces; while (numf--) { fscanf(file,"%s %u",current,++ptf); fscanf(file,"%u",--ptf); fscanf(file,"%u",(ptf+=2)++); } //the 3d object is now loaded, we can load the 2d file //we get the number of vertices fscanf(file,"%u",&num2dvertices); if (num2dvertices) { //we allocate the correct number of coodinates for 2D vertices pt2dvertices=(float*)malloc(num2dvertices*sizeof(float)*3); //we scan the vertices ptv=pt2dvertices; numv=num2dvertices; while (numv--) { fscanf(file,"%f",ptv++); fscanf(file,"%f",ptv++); *(ptv++)=0.0f; if ((default_pos_cam.y=ptv[-1]*ptv[-1]+ptv[-2]*ptv[-2])>default_pos_cam.x) default_pos_cam.x=default_pos_cam.y; } } //we define the default position of cameras. The aim is to have camera which is always well placed default_pos_cam.x=sqrtf(default_pos_cam.x*1.5); default_pos_cam.y=default_pos_cam.x; default_pos_cam.z=default_pos_cam.x; //the file is now loaded we can generate the normal to each vertice return true; } bool saveTXTObject(FILE *file) { //print of the number of vertices and faces fprintf(file,"%u\n%u\n",numvertices,numfaces); //print of the vertices unsigned int i=numvertices; float *ptv(ptvertices); float val[3]; while (i--) { multiply_matrix_pR3v(m_global_transformed,ptv,val); fprintf(file,"%f %f %f\n",val[0],val[1],val[2]); ptv+=3; } //print of the faces unsigned int *ptf(ptfaces); i=numfaces; while (i--) { fprintf(file,"3 %u ",*(++ptf)); fprintf(file,"%u ",*(--ptf)); fprintf(file,"%u\n",*((ptf+=2)++)); } //Now, we will save the 2D Object

Jason MAHDJOUB

23

University of TEESSIDE

//print of the number of vertices fprintf(file,"%u\n",num2dvertices); //print of the vertices if (num2dvertices) { i=num2dvertices; ptv=pt2dvertices; while (i--) { multiply_matrix_pR3v(m_global_transformed_2d,ptv,val); fprintf(file,"%f %f\n",*val,val[1]); ptv+=3; } } //the save is now complete return true; } bool loadObject(const char *name) { printf("\nOpening the file '%s'...",name); FILE *f=fopen(name,"r"); if (f) { puts("[OK]"); //we free the space allocated by the previous object. if (ptvertices) {free(ptvertices);ptvertices=NULL;} if (ptnormals) {free(ptnormals);ptnormals=NULL;} if (ptfaces) {free(ptfaces);ptfaces=NULL;} numfaces=0; numvertices=0; num2dvertices=0; printf("Reading TXT file..."); if (loadTXTObject(f)) { puts("[OK]"); generateNormals(); if (numfaces) printf("3D file loaded: \n\tNumber of vertices: %u\n\tNumber of normals: %u\n\tNumber of faces:%u\n",numvertices,numvertices,numfaces); if (num2dvertices) printf ("2D file loaded:\n\tNumber of vertices: %u\n",num2dvertices); else { if (listbox_dim->curr_text[0]=='2') { listbox_dim->set_int_val(1); glui_control(ALTER_NUM_DIMENSION); } } //Now, we will generate the OPEN GL's lists for all the sreens int i; for (i=4;i--;) { switch(i) { case 0:glutSetWindow(id_top_left_subwindow);break; case 1:glutSetWindow(id_top_right_subwindow);break; case 2:glutSetWindow(id_down_left_subwindow);break; case 3:glutSetWindow(id_down_right_subwindow);break; } unsigned int num=numfaces; unsigned int decal; unsigned int *ptf=ptfaces; glNewList(gl_num_list_3d,GL_COMPILE); { glBegin(GL_TRIANGLES); while (num--) { glNormal3fv(ptnormals+(decal=*(ptf++) * 3)); glVertex3fv(ptvertices+decal); glNormal3fv(ptnormals+(decal=(*ptf++) * 3)); glVertex3fv(ptvertices+decal); } glEnd();

glNormal3fv(ptnormals+(decal=*(ptf++) * 3)); glVertex3fv(ptvertices+decal);

} glEndList(); glNewList(gl_num_list_2d,GL_COMPILE); { num=num2dvertices; float *ptv=pt2dvertices; glBegin(GL_POLYGON); glNormal3f(0.0f,1.0f,0.0f); while (num--) { glVertex3fv(ptv);

Jason MAHDJOUB

24

University of TEESSIDE

} glEnd();

}

ptv+=3;

} glEndList();

//we reset position of the cameras glui_control(RESET); return true;

} else puts("[FAIL]"); puts(""); fclose(f);//close the file loaded

} else puts("[FAIL]\n"); return false;

} bool saveObject(const char *name) { printf("\nOpening the file '%s' to save ...",name); FILE *f=fopen(name,"w"); if (f) { printf("[OK]\nSaving TXT file ..."); if (saveTXTObject(f)) { puts("[OK]"); fclose(f); return true; } else { fclose(f); puts("[FAIL]"); } } else puts("[FAIL]"); return false; }

Jason MAHDJOUB

25

University of TEESSIDE

glut_functions.h #ifndef ___GLUT_FUNCTIONS___ #define ___GLUT_FUNCTIONS___ #include "GL\glut.h" /*glut functions prototypes for the main window*/ void display_main(); void reshape_main(int w, int h); /*---------------------------------------------*/ /*glut functions prototypes for the window containing the object not tranformed*/ /*the subwindows need to be centered. To do it, we need to know the glui window width and to wait the first screen of it. So we link at first time the funtions pre_display_left as a display function which will be used only once. when this function is runed, the glui window width can be now knewn and then the reshape of the left subwindow can be correctely made. At the end of this function, a link with the display_left function is made.*/ void pre_display_top_left(); void display_top_left(); void mouse_top_left(int button, int state, int x, int y); /*------------------------------------------------------------------------------*/ /*glut functions prototypes for the window containing the object tranformed*/ /*the subwindows need to be centered. To do it, we need to know the glui window width and to wait the first screen of it. So we link at first time the funtions pre_display_left as a display function which will be used only once. when this function is runed, the glui window width can be now knewn and then the reshape of the left subwindow can be correctely made. At the end of this function, a link with the display_left function is made.*/ void pre_display_top_right(); void display_top_right(); void mouse_top_right(int button, int state, int x, int y); /*------------------------------------------------------------------------------*/ /*glut functions prototypes for the window containing the object tranformed with a top view and an orthogonal projection*/ /*the subwindows need to be centered. To do it, we need to know the glui window width and to wait the first screen of it. So we link at first time the funtions pre_display_left as a display function which will be used only once. when this function is runed, the glui window width can be now knewn and then the reshape of the left subwindow can be correctely made. At the end of this function, a link with the display_left function is made.*/ void pre_display_down_left(); void display_down_left(); void mouse_down_left(int button, int state, int x, int y); void motion_ortho_down_left(int x, int y); void update_matrix_cam_down_left(); /*------------------------------------------------------------------------------*/ /*glut functions prototypes for the window containing the object tranformed with a front view and an orthogonal projection*/ /*the subwindows need to be centered. To do it, we need to know the glui window width and to wait the first screen of it. So we link at first time the funtions pre_display_left as a display function which will be used only once. when this function is runed, the glui window width can be now knewn and then the reshape of the left subwindow can be correctely made. At the end of this function, a link with the display_left function is made.*/ void pre_display_down_right(); void display_down_right(); void mouse_down_right(int button, int state, int x, int y); void motion_ortho_down_right(int x, int y); void update_matrix_cam_down_right(); /*------------------------------------------------------------------------------*/ /*common glut functions for the 4 sceens*/ void reshape_ortho_common(int w, int h); void reshape_perspective_common(int w, int h); void motion_perspective_common(int x, int y); /*----------------------------------*/ inline void drawGrid();//draw a grid on the XZ plane inline void drawRepere();//draw a 3d repere inline void drawString (const char *val);//draw text on screens whose projection is perpective inline void drawString_ortho (const char *val);//draw text on screens whose projection is orthogonal #endif

Jason MAHDJOUB

26

University of TEESSIDE

glut_functions.c #include #include #include #include #include

"glut_functions.h" "GL/glui.h" "algebre.h" "defines.h" "other_functions.h"

/*-----------external variables---------------------------*/ … … … /*--------------------------------------------------------*/ /*glut functions definitions for the main window*/ void display_main() { static unsigned long ul_tmp; if ((ul_tmp=getTimeElapsed())getWidth())/2,h/2); glutSetWindow(id_top_right_subwindow); glutPositionWindow((w-glui_window->getWidth())/2,0); glutReshapeWindow((w-glui_window->getWidth())/2,h/2); glutSetWindow(id_down_left_subwindow); glutPositionWindow(0,h/2); glutReshapeWindow((w-glui_window->getWidth())/2,h/2); glutSetWindow(id_down_right_subwindow); glutPositionWindow((w-glui_window->getWidth())/2,h/2); glutReshapeWindow((w-glui_window->getWidth())/2,h/2); } /*------------------------*/ /*glut functions definitions for the left window*/ void pre_display_top_left() { glutPositionWindow(0,0); glutReshapeWindow((WIDTH_MAIN_WINDOW-glui_window>getWidth())/2,HEIGHT_MAIN_WINDOW/2); glutDisplayFunc(display_top_left); glutPostRedisplay(); } void display_top_left() { glLoadIdentity(); /*loading camera matrix*/ glMultMatrixf(m_cam_top_left); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0,GL_POSITION,light_position); /*screens the grid and the repere*/ drawGrid(); drawRepere(); glColor3f(1.0f,1.0f,1.0f);

Jason MAHDJOUB

27

University of TEESSIDE

/*screens the 3d object*/ glCallList(*current_gl_num_list); drawString("3D view (original object)"); glutSwapBuffers(); } void mouse_top_left(int button, int state, int x, int y) { if (state==GLUT_DOWN) { if (button==GLUT_LEFT_BUTTON) mouse_down=1; if (button==GLUT_RIGHT_BUTTON) mouse_down=2; if (button==GLUT_MIDDLE_BUTTON) mouse_down=3; pos_cam_tmp=&pos_cam_top_left; ref_cam_tmp=&ref_cam_top_left; previous_translationx=x; previous_translationy=y; vUp_cam_tmp=&vUp_cam_top_left; m_cam_tmp=m_cam_top_left;

} else mouse_down=0;

} /*----------------------------------------------*/ /*glut functions definitions for the right window*/ void pre_display_top_right() { glutPositionWindow((WIDTH_MAIN_WINDOW-glui_window->getWidth())/2,0); glutReshapeWindow((WIDTH_MAIN_WINDOW-glui_window>getWidth())/2,HEIGHT_MAIN_WINDOW/2); glutDisplayFunc(display_top_right); glutPostRedisplay(); } void display_top_right() { glLoadIdentity(); /*loading camera matrix*/ glMultMatrixf(m_cam_top_right); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0,GL_POSITION,light_position);

drawGrid(); drawRepere(); glColor3f(1.0f,1.0f,1.0f); /*load the global transform matrix*/ glMultMatrixf(current_m_global_transformed); /*screens the 3d object*/ glCallList(*current_gl_num_list); drawString("3D view (transformed object)"); glutSwapBuffers(); } void mouse_top_right(int button, int state, int x, int y) { if (state==GLUT_DOWN) { if (button==GLUT_LEFT_BUTTON) mouse_down=1; if (button==GLUT_RIGHT_BUTTON) mouse_down=2; if (button==GLUT_MIDDLE_BUTTON) mouse_down=3; pos_cam_tmp=&pos_cam_top_right; ref_cam_tmp=&ref_cam_top_right; previous_translationx=x; previous_translationy=y; vUp_cam_tmp=&vUp_cam_top_right; m_cam_tmp=m_cam_top_right;

}

} else mouse_down=0;

/*-----------------------------------------------*/ /*glut functions definitions for the down left window*/ void pre_display_down_left() { glutPositionWindow(0,HEIGHT_MAIN_WINDOW/2); glutReshapeWindow((WIDTH_MAIN_WINDOW-glui_window>getWidth())/2,HEIGHT_MAIN_WINDOW/2); glutDisplayFunc(display_down_left); glutPostRedisplay(); } void display_down_left() {

Jason MAHDJOUB

28

University of TEESSIDE

glLoadIdentity(); /*loading camera matrix*/ glMultMatrixf(m_cam_down_left); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0,GL_POSITION,light_position); glDisable(GL_DEPTH_TEST); drawGrid(); drawRepere(); glEnable(GL_DEPTH_TEST); glColor3f(1,1,1); /*load the global transform matrix*/ glMultMatrixf(current_m_global_transformed); /*screens the 3d object*/ glCallList(*current_gl_num_list); drawString_ortho("Top view (transformed object)"); glutSwapBuffers(); } void mouse_down_left(int button, int state, int x, int y) { if (state==GLUT_DOWN) { if (button==GLUT_LEFT_BUTTON) mouse_down=1; if (button==GLUT_MIDDLE_BUTTON) mouse_down=3; previous_translationx=x; previous_translationy=y; } else mouse_down=0; } void motion_ortho_down_left(int x, int y) { if (mouse_down==1) { /*translation of the camera position*/ pos_cam_down_left.x=pos_cam_down_left.x+(2*float(previous_translationxx))/float(glutGet(GLUT_WINDOW_HEIGHT)); pos_cam_down_left.z=pos_cam_down_left.z+(2*float(previous_translationyy))/float(glutGet(GLUT_WINDOW_HEIGHT)); /*save the current mouse position for the next motion*/ previous_translationx=x; previous_translationy=y; /*update matrices*/ update_matrix_cam_down_left(); glutPostRedisplay(); } if (mouse_down==3) { /*zoom*/ pos_cam_down_left.y+=float(y-previous_translationy)/10.f; /*if the zoom is too near from the reference, the camera position is redifined*/ if (pos_cam_down_left.ygetWidth())/2,HEIGHT_MAIN_WINDOW/2); glutReshapeWindow((WIDTH_MAIN_WINDOW-glui_window>getWidth())/2,HEIGHT_MAIN_WINDOW/2); glutDisplayFunc(display_down_right); glutPostRedisplay();

} void display_down_right() { glLoadIdentity(); /*load the camera matrix*/ glMultMatrixf(m_cam_down_right); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0,GL_POSITION,light_position);

glDisable(GL_DEPTH_TEST); glPushMatrix(); glRotatef(90.0f,1.0f,0.0f,0.0f); drawGrid(); glPopMatrix(); drawRepere(); glEnable(GL_DEPTH_TEST); glColor3f(1,1,1); /*load the global transform matrix*/ glMultMatrixf(current_m_global_transformed); /*screens the 3d object*/ glCallList(*current_gl_num_list); drawString_ortho("Front view (transformed object)"); glutSwapBuffers(); } void mouse_down_right(int button, int state, int x, int y) { if (state==GLUT_DOWN) { if (button==GLUT_LEFT_BUTTON) mouse_down=1; if (button==GLUT_MIDDLE_BUTTON) mouse_down=3; previous_translationx=x; previous_translationy=y; } else mouse_down=0; } void motion_ortho_down_right(int x, int y) { /*see the previous description (because the same) in motion_ortho_down_left*/ if (mouse_down==1) { pos_cam_down_right.x=pos_cam_down_right.x+(2*float(previous_translationxx))/float(glutGet(GLUT_WINDOW_HEIGHT)); pos_cam_down_right.y=pos_cam_down_right.y+(2*float(yprevious_translationy))/float(glutGet(GLUT_WINDOW_HEIGHT)); previous_translationx=x; previous_translationy=y; update_matrix_cam_down_right(); glutPostRedisplay(); } if (mouse_down==3) { pos_cam_down_right.z+=float(y-previous_translationy)/10.f; if (pos_cam_down_right.zx=pos_cam_tmp->x+v_tmp.x*dx+vUp_cam_tmp->x*dy; pos_cam_tmp->y=pos_cam_tmp->y+v_tmp.y*dx+vUp_cam_tmp->y*dy; pos_cam_tmp->z=pos_cam_tmp->z+v_tmp.z*dx+vUp_cam_tmp->z*dy; /*translation of the camera's reference*/ ref_cam_tmp->x=ref_cam_tmp->x+v_tmp.x*dx+vUp_cam_tmp->x*dy; ref_cam_tmp->y=ref_cam_tmp->y+v_tmp.y*dx+vUp_cam_tmp->y*dy; ref_cam_tmp->z=ref_cam_tmp->z+v_tmp.z*dx+vUp_cam_tmp->z*dy; /*save the current position of the mouse for the next motion*/ previous_translationx=x; previous_translationy=y; /*update camera matrix */ getCameraMatrix(m_cam_tmp,*pos_cam_tmp,*ref_cam_tmp,*vUp_cam_tmp); glutPostRedisplay();

} if (mouse_down==2) { /*rotation of the camera*/ float m_rotate_tmp[16]; float m_rotate_tmp2[16];

Jason MAHDJOUB

31

University of TEESSIDE

vR3 vUp; vUp.x=0.0f; vUp.y=1.0f; vUp.z=0.0f; vR3 v_tmp;//normal of the camera's vectors up and vise v_tmp.x=ref_cam_tmp->x-pos_cam_tmp->x; v_tmp.y=ref_cam_tmp->y-pos_cam_tmp->y; v_tmp.z=ref_cam_tmp->z-pos_cam_tmp->z; v_tmp=getUnitNormal(v_tmp,*vUp_cam_tmp); /*creating rotation of around the y-axis*/ getMatrixRotationC(float(x - previous_translationx) * PI/600.0f, vUp, *ref_cam_tmp, m_rotate_tmp); /*creating rotation around the v_tmp normal*/ getMatrixRotationC(float(previous_translationyy)*PI/600.0f,v_tmp,*ref_cam_tmp,m_rotate_tmp2); /*multiplying the two rotations*/ multiply_matrix_matrix(m_rotate_tmp,m_rotate_tmp2,m_cam_tmp); /*appliying this matrix onto the camera's reference and onto the camera's up vector*/ *pos_cam_tmp=multiply_pR3_matrix(*pos_cam_tmp,m_cam_tmp); *vUp_cam_tmp=multiply_vR3_matrix(*vUp_cam_tmp,m_cam_tmp); /*save the current position of the mouse for the next motion*/ previous_translationx=x; previous_translationy=y; /*update the camera matrix*/ getCameraMatrix(m_cam_tmp,*pos_cam_tmp,*ref_cam_tmp,*vUp_cam_tmp); glutPostRedisplay();

} if (mouse_down==3) { /*zoom of the camera*/ float dy=float(previous_translationy-y)/10.0f;

vR3 v_tmp; v_tmp.x=ref_cam_tmp->x-pos_cam_tmp->x; v_tmp.y=ref_cam_tmp->y-pos_cam_tmp->y; v_tmp.z=ref_cam_tmp->z-pos_cam_tmp->z; /*setting a limit for the zoom*/ if (dy+0.5>sqrtf(v_tmp.x*v_tmp.x+v_tmp.y*v_tmp.y+v_tmp.z*v_tmp.z)) dy=sqrtf(v_tmp.x*v_tmp.x+v_tmp.y*v_tmp.y+v_tmp.z*v_tmp.z)-0.5f; normalize(v_tmp); /*moving the camera's postion for zoom*/ pos_cam_tmp->x=pos_cam_tmp->x+v_tmp.x*dy; pos_cam_tmp->y=pos_cam_tmp->y+v_tmp.y*dy; pos_cam_tmp->z=pos_cam_tmp->z+v_tmp.z*dy;

}

/*save the current position of the mouse for the next motion*/ previous_translationy=y; /*update the camera matrix*/ getCameraMatrix(m_cam_tmp,*pos_cam_tmp,*ref_cam_tmp,*vUp_cam_tmp); glutPostRedisplay();

} /*--------------------------------------------------*/ inline void drawGrid() { glDisable(GL_LIGHTING); glColor3f(0.3f,0.3f,0.3f); glBegin(GL_LINES); //drawing the grid float i; for (i=21.0f;i--;) { glVertex3f(-10.0f,0.0f,i-10.0f); glVertex3f(10.0f,0.0f,i-10.0f); } for (i=21.0f;i--;) { glVertex3f(i-10.0f,0.0f,10.0f); glVertex3f(i-10.0f,0.0f,-10.0f); } glEnd(); glEnable(GL_LIGHTING); } inline void drawRepere() { glDisable(GL_LIGHTING); glDepthFunc(GL_ALWAYS);/*enable to draw the repere over the grid (Z-Buffer isn't tested), but update the Z-buffer*/ glBegin(GL_LINES); glColor3f(1.0f,0.0f,0.0f); glVertex3f(0.0f,0.0f,0.0f); glVertex3f(default_pos_cam.x*1.5f,0.0f,0.0f); glColor3f(0.0f,1.0f,0.0f); glVertex3f(0.0f,0.0f,0.0f); glVertex3f(0.0f,default_pos_cam.y*1.5f,0.0f); glColor3f(0.0f,0.0f,1.0f); glVertex3f(0.0f,0.0f,0.0f);

Jason MAHDJOUB

32

University of TEESSIDE

glVertex3f(0.0f,0.0f,default_pos_cam.z*1.5f); glEnd(); glDepthFunc(GL_LESS);/*give to the Z-buffer his default value, that is to say his default utility*/ glEnable(GL_LIGHTING);

} inline void drawString (const char *val) { /*drawing a text onto a 3d screen*/ glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glPushMatrix(); glLoadIdentity(); glRasterPos3f(-0.5f * float(glutGet(GLUT_WINDOW_WIDTH)) / float(glutGet(GLUT_WINDOW_HEIGHT)), -0.5f, -0.9f); glColor3f(1.0f,1.0f,1.0f); unsigned int i=0,nb=strlen(val); for (i=0;iadd_item(0,"2D"); listbox_dim->add_item(1,"3D"); listbox_dim->set_int_val(1); rollout_file=glui_window->add_rollout("File",true); edittext_filename=glui_window->add_edittext_to_panel(rollout_file,"file name"); glui_window->add_button_to_panel(rollout_file,"load",LOAD_FILE,glui_control); glui_window->add_button_to_panel(rollout_file,"save",SAVE_FILE,glui_control); rollout_screen=glui_window->add_rollout("Screen management",true); glui_window->add_button_to_panel(rollout_screen,"Reset top left",RESET_TOP_LEFT,glui_control); glui_window->add_button_to_panel(rollout_screen,"Reset down left",RESET_DOWN_LEFT,glui_control); glui_window->add_column_to_panel(rollout_screen); glui_window->add_button_to_panel(rollout_screen,"Reset top right",RESET_TOP_RIGHT,glui_control); glui_window->add_button_to_panel(rollout_screen,"Reset down right",RESET_DOWN_RIGHT,glui_control); glui_window->add_button_to_panel(rollout_screen,"Reset all",RESET,glui_control); rollout_add_tr=glui_window->add_rollout("Add transformation",true); button_translation=glui_window>add_button_to_panel(rollout_add_tr,"Translation",ADD_TRANSLATION,glui_co ntrol); button_rotationx=glui_window->add_button_to_panel(rollout_add_tr,"Rotation X",ADD_ROTATIONX,glui_control); button_rotationy=glui_window->add_button_to_panel(rollout_add_tr,"Rotation Y",ADD_ROTATIONY,glui_control); button_rotationz=glui_window->add_button_to_panel(rollout_add_tr,"Rotation Z",ADD_ROTATIONZ,glui_control); button_scale=glui_window>add_button_to_panel(rollout_add_tr,"Scale",ADD_SCALE,glui_control); button_scale_overall=glui_window->add_button_to_panel(rollout_add_tr,"Scale Overall",ADD_SCALE_OVERALL,glui_control); glui_window->add_separator_to_panel(rollout_add_tr); button_del_trans=glui_window->add_button_to_panel(rollout_add_tr,"Del last transformation",DEL_LAST_TRANSFORM,glui_control); button_clear_trans=glui_window->add_button_to_panel(rollout_add_tr,"Clear transformtations",CLEAR_TRANSFORMS,glui_control); rollout_print=glui_window->add_rollout("Add transformation",true); button_print_proj=glui_window->add_button_to_panel(rollout_print,"Print projection matrices",PRINT_PROJECTION_MATRIX,glui_control); button_print_cam=glui_window->add_button_to_panel(rollout_print,"Print camera matrices",PRINT_CAM_MATRIX,glui_control); button_print_global=glui_window->add_button_to_panel(rollout_print,"Print global transform matrix",PRINT_GLOBAL_TRANSFORMATION_MATRIX,glui_control); }

/*-------------------------------*/

Jason MAHDJOUB

34

University of TEESSIDE

void glui_control(int val) { switch(val) { case ALTER_NUM_DIMENSION: if (listbox_dim->curr_text[0]=='3' && listbox_dim->curr_text[1]=='D') { /*we condider that we are in 3D mode, so we set the pointers up*/ current_pt_tr=&pt_tr; current_numTransformation=&numTransformation; current_m_global_transformed=m_global_transformed; current_gl_num_list=&gl_num_list_3d; } else { /*we condider that we are in 2D mode, so we set the pointers up*/ current_pt_tr=&pt_tr_2d; current_numTransformation=&numTransformation_2d; current_m_global_transformed=m_global_transformed_2d; current_gl_num_list=&gl_num_list_2d; } /*we update the global transform matrix to be coherent with the current mode*/ updateTransformMatrix(); /*we refresh all screens*/ glutSetWindow(id_top_left_subwindow); glutPostRedisplay(); glutSetWindow(id_top_right_subwindow); glutPostRedisplay(); glutSetWindow(id_down_left_subwindow); glutPostRedisplay(); glutSetWindow(id_down_right_subwindow); glutPostRedisplay(); /*we check buttons which need to be enabled or not*/ manage_widgets(); break; case LOAD_FILE: /*loading the file*/ loadObject(edittext_filename->get_text()); /*all transformation are cleared*/ clearTransformations(); /*refresh all the screens*/ glutSetWindow(id_top_left_subwindow); glutPostRedisplay(); glutSetWindow(id_top_right_subwindow); glutPostRedisplay(); glutSetWindow(id_down_left_subwindow); glutPostRedisplay(); glutSetWindow(id_down_right_subwindow); glutPostRedisplay(); /*we check buttons which need to be enabled or not*/ manage_widgets(); break; case SAVE_FILE: /*saving file*/ saveObject(edittext_filename->get_text()); break; case RESET: { /*reset position of all cameras*/ glui_control(RESET_TOP_LEFT); glui_control(RESET_TOP_RIGHT); glui_control(RESET_DOWN_LEFT); glui_control(RESET_DOWN_RIGHT); } break; case RESET_TOP_LEFT: { /*reset position of the top left camera*/ pos_cam_top_left.x=default_pos_cam.x; pos_cam_top_left.y=default_pos_cam.y; pos_cam_top_left.z=default_pos_cam.z; ref_cam_top_left.x=default_ref_cam.x; ref_cam_top_left.y=default_ref_cam.y; ref_cam_top_left.z=default_ref_cam.z; vUp_cam_top_left.x=default_vUp_cam.x; vUp_cam_top_left.y=default_vUp_cam.y; vUp_cam_top_left.z=default_vUp_cam.z; /*set the camera matrix up according the new value we have just set up*/ getCameraMatrix(m_cam_top_left,pos_cam_top_left,ref_cam_top_left,vUp_cam_ top_left); /*reset the top left screen*/ glutSetWindow(id_top_left_subwindow); glutPostRedisplay();

} break; case RESET_TOP_RIGHT: { /*reset position of the top right camera*/ pos_cam_top_right.x=default_pos_cam.x; pos_cam_top_right.y=default_pos_cam.y;

Jason MAHDJOUB

35

University of TEESSIDE

pos_cam_top_right.z=default_pos_cam.z; ref_cam_top_right.x=default_ref_cam.x; ref_cam_top_right.y=default_ref_cam.y; ref_cam_top_right.z=default_ref_cam.z; vUp_cam_top_right.x=default_vUp_cam.x; vUp_cam_top_right.y=default_vUp_cam.y; vUp_cam_top_right.z=default_vUp_cam.z; /*set the camera matrix up according the new value we have just set up*/ getCameraMatrix(m_cam_top_right,pos_cam_top_right,ref_cam_top_right,vUp _cam_top_right); /*reset the top right screen*/ glutSetWindow(id_top_right_subwindow); glutPostRedisplay();

} break; case RESET_DOWN_LEFT: { /*reset position of the down left camera*/ pos_cam_down_left.x=0.0f; pos_cam_down_left.y=default_pos_cam.y; pos_cam_down_left.z=0.0f; pR3 p_tmp_ref; p_tmp_ref.x=p_tmp_ref.y=p_tmp_ref.z=0.0f; vR3 v_tmp_vUp; v_tmp_vUp.x=v_tmp_vUp.y=0.0f; v_tmp_vUp.z=-1.0f; /*set the camera matrix up according the new value we have just set up*/ update_matrix_cam_down_left(); /*reset the down left creen*/ glutSetWindow(id_down_left_subwindow); glutPostRedisplay();

} break; case RESET_DOWN_RIGHT: { /*reset position of the down right camera*/ pos_cam_down_right.x=0.0f; pos_cam_down_right.y=0.0f; pos_cam_down_right.z=default_pos_cam.z; pR3 p_tmp_ref; p_tmp_ref.x=p_tmp_ref.y=p_tmp_ref.z=0.0f; vR3 v_tmp_vUp; v_tmp_vUp.x=v_tmp_vUp.z=0.0f; v_tmp_vUp.y=1.0f; /*set the camera matrix up according the new value we have just set up*/ update_matrix_cam_down_right();

}

/*reset the down left screen*/ glutSetWindow(id_down_right_subwindow); glutPostRedisplay();

break; case ADD_TRANSLATION: { /*add a new translation on the current object*/ current_glui_transform_window=ADD_TRANSLATION;/*it will be usefull later*/ if (glui_translate_window) {glutSetWindow(glui_translate_window-> glut_window_id); glutShowWindow();} else { /* it's the first time a translation is added, so the window of translation is created*/ glui_translate_window=getGLUI_Master().create_glui("Add a translation" ); glui_translate_window->add_statictext("Add a translation :"); translate_spinner_a=glui_translate_window->add_spinner( "X : ", GLUI_SPINNER_FLOAT); translate_spinner_b=glui_translate_window->add_spinner( "Y : ", GLUI_SPINNER_FLOAT); translate_spinner_c=glui_translate_window->add_spinner( "Z : ", GLUI_SPINNER_FLOAT); glui_translate_window-> add_button("Apply", FINISH_ADD_TRANSLATION, glui_control); glui_translate_window-> add_button("Cancel", FINISH_ADD_TRANSFORMATION, glui_control); if (listbox_dim->curr_text[0]=='2') translate_spinner_c->disable(); } /*we check buttons which need to be enabled or not*/ manage_widgets();

} break; case ADD_ROTATIONX: { /*add a new X rotation on the current object*/ current_glui_transform_window=ADD_ROTATIONX; if (glui_rotatex_window) {glutSetWindow(glui_rotatex_window-> glut_window_id); glutShowWindow();} else { /* it's the first time an x rotation is added, so the window of translation is created*/ glui_rotatex_window=getGLUI_Master().create_glui("Add a Rotation on X-axis" ); glui_rotatex_window->add_statictext("Add a Rotation on X-axis :");

Jason MAHDJOUB

36

University of TEESSIDE

rotationx_spinner=glui_rotatex_window->add_spinner( "Angle : ", GLUI_SPINNER_FLOAT); glui_rotatex_window-> add_button("Apply", FINISH_ADD_ROTATIONX, glui_control); glui_rotatex_window-> add_button("Cancel", FINISH_ADD_TRANSFORMATION, glui_control);

} /*we check buttons which need to be enabled or not*/ manage_widgets();

} break; case ADD_ROTATIONY: { /*add a new Y rotation on the current object*/ current_glui_transform_window=ADD_ROTATIONY; if (glui_rotatey_window) {glutSetWindow(glui_rotatey_window-> glut_window_id); glutShowWindow();} else { /* it's the first time an Y rotation is added, so the window of translation created*/ glui_rotatey_window=getGLUI_Master().create_glui("Add a Rotation on Y-axis" glui_rotatey_window->add_statictext("Add a Rotation on Y-axis :"); rotationy_spinner=glui_rotatey_window->add_spinner( "Angle : ", GLUI_SPINNER_FLOAT); glui_rotatey_window-> add_button("Apply", FINISH_ADD_ROTATIONY, glui_control); glui_rotatey_window-> add_button("Cancel", FINISH_ADD_TRANSFORMATION, glui_control); } /*we check buttons which need to be enabled or not*/ manage_widgets(); } break; case ADD_ROTATIONZ: { /*add a new Z rotation on the current object*/ current_glui_transform_window=ADD_ROTATIONZ; if (glui_rotatez_window) {glutSetWindow(glui_rotatez_window>glut_window_id);glutShowWindow();} else { /* it's the first time an Z rotation is added, so the window of translation created*/ glui_rotatez_window=getGLUI_Master().create_glui("Add a Rotation on Z-axis" glui_rotatez_window->add_statictext("Add a Rotation on Z-axis :"); rotationz_spinner=glui_rotatez_window->add_spinner( "Angle : ", GLUI_SPINNER_FLOAT); glui_rotatez_window-> add_button("Apply", FINISH_ADD_ROTATIONZ, glui_control); glui_rotatez_window-> add_button("Cancel", FINISH_ADD_TRANSFORMATION, glui_control); } /*we check buttons which need to be enabled or not*/ manage_widgets(); } break; case ADD_SCALE: { /*add a new scale on the current object*/ current_glui_transform_window=ADD_SCALE; if (glui_scale_window) {glutSetWindow(glui_scale_window->glut_window_id); glutShowWindow();} else { /* it's the first time a scale is added, so the window of translation is created*/ glui_scale_window=getGLUI_Master().create_glui("Add a scale" ); glui_scale_window->add_statictext("Add a scale :"); scale_spinner_a=glui_scale_window->add_spinner( "X : ", GLUI_SPINNER_FLOAT); scale_spinner_a->set_float_val(1.0f); scale_spinner_b=glui_scale_window->add_spinner( "Y : ", GLUI_SPINNER_FLOAT); scale_spinner_b->set_float_val(1.0f); scale_spinner_c=glui_scale_window->add_spinner( "Z : ", GLUI_SPINNER_FLOAT); scale_spinner_c->set_float_val(1.0f); glui_scale_window->add_button("Apply",FINISH_ADD_SCALE,glui_control); glui_scale_window->add_button("Cancel", FINISH_ADD_TRANSFORMATION, glui_control); if (listbox_dim->curr_text[0]=='2') scale_spinner_c->disable(); } /*we check buttons which need to be enabled or not*/ manage_widgets(); } break; case ADD_SCALE_OVERALL: { /*add a new overall scale on the current object*/ current_glui_transform_window=ADD_SCALE_OVERALL; if (glui_scaleoverall_window) {glutSetWindow(glui_scaleoverall_window>glut_window_id);glutShowWindow();} else {

Jason MAHDJOUB

37

is );

is );

University of TEESSIDE

/* it's the first time an overall scale is added, so the window of translation is created*/ glui_scaleoverall_window=getGLUI_Master().create_glui("Add a scale OVERALL" ); glui_scaleoverall_window->add_statictext("Add a scale OVERALL :"); scale_over_all_spinner=glui_scaleoverall_window->add_spinner( "value : ", GLUI_SPINNER_FLOAT); scale_over_all_spinner->set_float_val(1.0f); glui_scaleoverall_window-> add_button("Apply", FINISH_ADD_SCALE_OVERALL, glui_control); glui_scaleoverall_window-> add_button("Cancel", FINISH_ADD_TRANSFORMATION, glui_control);

} /*we check buttons which need to be screend or not*/ manage_widgets();

} break; case FINISH_ADD_TRANSLATION: { /*the translation have been applied on the window of transformation*/ Transformation tr; vR3 vec; /*we get values entred trow the glui interface*/ vec.x=translate_spinner_a->get_float_val(); vec.y=translate_spinner_b->get_float_val(); vec.z=translate_spinner_c->get_float_val(); /*we reset spinner for the next transformation*/ translate_spinner_a->set_float_val(0.0f); translate_spinner_b->set_float_val(0.0f); translate_spinner_c->set_float_val(0.0f); /*we create a translation transformation*/ createTranslation(tr,vec); /*we push this new transformation*/ pushTransformation(tr); /*we call to close the transformation window*/ glui_control(FINISH_ADD_TRANSFORMATION); } break; case FINISH_ADD_ROTATIONX: { /*the x rotation have been applied on the window of transformation*/ Transformation tr; /*we create a translation transformation*/ createX_Rotation(tr,rotationx_spinner->get_float_val()*PI/180); /*we reset spinner for the next transformation*/ rotationx_spinner->set_float_val(0.0f); /*we push this new transformation*/ pushTransformation(tr); /*we call to close the transformation window*/ glui_control(FINISH_ADD_TRANSFORMATION); } break; case FINISH_ADD_ROTATIONY: { /*the y ratation have been applied on the window of transformation*/ Transformation tr; /*we create a translation transformation*/ createY_Rotation(tr,rotationy_spinner->get_float_val()*PI/180); /*we reset spinner for the next transformation*/ rotationy_spinner->set_float_val(0.0f); /*we push this new transformation*/ pushTransformation(tr); /*we call to close the transformation window*/ glui_control(FINISH_ADD_TRANSFORMATION); } break; case FINISH_ADD_ROTATIONZ: { /*the z rotation have been applied on the window of transformation*/ Transformation tr; /*we create a translation transformation*/ createZ_Rotation(tr,rotationz_spinner->get_float_val()*PI/180); /*we reset spinner for the next transformation*/ rotationz_spinner->set_float_val(0.0f); /*we push this new transformation*/ pushTransformation(tr); /*we call to close the transformation window*/ glui_control(FINISH_ADD_TRANSFORMATION); } break; case FINISH_ADD_SCALE: { /*the scale have been applied on the window of transformation*/ Transformation tr; /*we create a translation transformation*/ createScale(tr,scale_spinner_a->get_float_val(),scale_spinner_b-> get_float_val(), scale_spinner_c->get_float_val()); /*we reset spinner for the next transformation*/ scale_spinner_a->set_float_val(1.0f); scale_spinner_b->set_float_val(1.0f); scale_spinner_c->set_float_val(1.0f); /*we push this new transformation*/ pushTransformation(tr); /*we call to close the transformation window*/ glui_control(FINISH_ADD_TRANSFORMATION); } break;

Jason MAHDJOUB

38

University of TEESSIDE

case FINISH_ADD_SCALE_OVERALL: { /*the overall scale have been applied on the window of transformation*/ Transformation tr; /*we create a translation transformation*/ createScaleOverall(tr,1.0f/scale_over_all_spinner->get_float_val()); /*we reset spinner for the next transformation*/ scale_over_all_spinner->set_float_val(1.0f); /*we push this new transformation*/ pushTransformation(tr); /*we call to close the transformation window*/ glui_control(FINISH_ADD_TRANSFORMATION); } break; case FINISH_ADD_TRANSFORMATION: { /*we hide the tranform window which has just been used*/ switch(current_glui_transform_window) { case ADD_TRANSLATION:glutSetWindow(glui_translate_window-> glut_window_id); glutHideWindow();break; case ADD_ROTATIONX:glutSetWindow(glui_rotatex_window-> glut_window_id); glutHideWindow();break; case ADD_ROTATIONY:glutSetWindow(glui_rotatey_window-> glut_window_id); glutHideWindow();break; case ADD_ROTATIONZ:glutSetWindow(glui_rotatez_window-> glut_window_id); glutHideWindow();break; case ADD_SCALE:glutSetWindow(glui_scale_window-> glut_window_id); glutHideWindow(); break; case ADD_SCALE_OVERALL:glutSetWindow(glui_scaleoverall_window-> glut_window_id); glutHideWindow();break; } /*we indicate to the main program that the transform adding is finished*/ current_glui_transform_window=0; /*we check buttons which need to be enabled or not*/ manage_widgets(); /*we start the chronometer for the animation of the transformation*/ startChronometer(); /*we refresh the main window...this main window will manage the animation and refresh all the concerned screens*/ glutSetWindow(id_main_window); glutPostRedisplay(); } break; case PRINT_PROJECTION_MATRIX: puts("Perspective projection matrix:"); printMatrix(m_proj_pers); puts("Orthogonal projection matrix:"); printMatrix(m_proj_ortho); break; case PRINT_CAM_MATRIX: puts("Top left camera matrix:"); printMatrix(m_cam_top_left); puts("Top right camera matrix:"); printMatrix(m_cam_top_right); puts("Down left camera matrix:"); printMatrix(m_cam_down_left); puts("Down right camera matrix:"); printMatrix(m_cam_down_right); break; case PRINT_GLOBAL_TRANSFORMATION_MATRIX: puts("Current global transform matrix:"); printMatrix(current_m_global_transformed); break; case CLEAR_TRANSFORMS: /*we clear all pushed transformations..the object will return to its original position*/ clearTransformations(); /*we check buttons which need to be enabled or not*/ manage_widgets(); /*refresh of all screens*/ glutSetWindow(id_top_right_subwindow); glutPostRedisplay(); glutSetWindow(id_down_left_subwindow); glutPostRedisplay(); glutSetWindow(id_down_right_subwindow); glutPostRedisplay(); break; case DEL_LAST_TRANSFORM: /*we delete the last transformation that has been added*/ popTransformation(); /*we check buttons which need to be enabled or not*/ manage_widgets(); /*refresh of all screens*/ glutSetWindow(id_top_right_subwindow); glutPostRedisplay(); glutSetWindow(id_down_left_subwindow); glutPostRedisplay(); glutSetWindow(id_down_right_subwindow); glutPostRedisplay(); break; }

Jason MAHDJOUB

39

University of TEESSIDE

} void manage_widgets() { if (current_glui_transform_window) { /*we consider that a transform window is opened and disable all the widgets*/ if (rollout_file->enabled) rollout_file->disable(); if (rollout_screen->enabled) rollout_screen->disable(); if (rollout_add_tr->enabled) rollout_add_tr->disable(); if (rollout_print->enabled) rollout_print->disable(); if (listbox_dim->curr_text[0]=='3') { /*we are in 3d mode, so z spinners had to be enabled*/

} else {

} else {

}

if (glui_translate_window) if (!translate_spinner_c->enabled) translate_spinner_c->enable(); if (glui_scale_window) if (!scale_spinner_c->enabled) scale_spinner_c->enable(); /*we are in 3d mode, so z spinners had to be desabled*/ if (glui_translate_window) if (translate_spinner_c->enabled) translate_spinner_c->disable(); if (glui_scale_window) if (scale_spinner_c->enabled) scale_spinner_c->disable();

/*we consider that no transform window is opened*/ if (!rollout_file->enabled) rollout_file->enable(); if (!rollout_screen->enabled) rollout_screen->enable(); if (!rollout_add_tr->enabled) rollout_add_tr->enable(); if (!rollout_print->enabled) rollout_print->enable();

if ((listbox_dim->curr_text[0]=='3' && numvertices) || (listbox_dim->curr_text[0]=='2' && num2dvertices)) { /*any object 2d or 3d is loaded*/ if (!button_translation->enabled)button_translation->enable(); if (!button_rotationz->enabled)button_rotationz->enable(); if (!button_scale->enabled)button_scale->enable(); if (!button_scale_overall->enabled)button_scale_overall->enable();

} else {

}

}

if (listbox_dim->curr_text[0]=='3') { /*in 3d mode, we need of all rotations*/ if (!button_rotationx->enabled)button_rotationx->enable(); if (!button_rotationy->enabled)button_rotationy->enable(); } else { /*in 2d mode, we just need the z rotation*/ if (button_rotationx->enabled)button_rotationx->disable(); if (button_rotationy->enabled)button_rotationy->disable(); } if (*current_numTransformation) { if (!button_del_trans->enabled) button_del_trans->enable(); if (!button_clear_trans->enabled) button_clear_trans->enable(); } else { /*no tranformation is saved, so we can't pop the previous transformation or clear current transformation*/ if (button_del_trans->enabled) button_del_trans->disable(); if (button_clear_trans->enabled) button_clear_trans->disable(); } /*no object is loaded*/ if (button_translation->enabled)button_translation->disable(); if (button_rotationy->enabled)button_rotationy->disable(); if (button_scale->enabled)button_scale->disable(); if (button_scale_overall->enabled)button_scale_overall->disable(); if (button_rotationx->enabled)button_rotationx->disable(); if (button_rotationz->enabled)button_rotationz->disable(); if (button_del_trans->enabled) button_del_trans->disable(); if (button_clear_trans->enabled) button_clear_trans->disable();

} if (listbox_dim->curr_text[0]=='3') { if (!button_print_proj->enabled)button_print_proj->enable(); if (!button_print_cam->enabled)button_print_cam->enable(); } else { if (button_print_proj->enabled)button_print_proj->disable(); if (button_print_cam->enabled)button_print_cam->disable(); }

Jason MAHDJOUB

40

University of TEESSIDE