(no commit message)
[atyndall/cits2231.git] / helper.c
1 /**
2  * Helper Function File
3  * Contains all of the project's helper functions
4  * @author Ashley Tyndall (20915779), Jenna de la Harpe (20367932)
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <dirent.h>
10 #include <string.h>
11 #include <math.h>
12 #include <GL/gl.h>
13 #include <GL/glut.h>
14 #include <time.h>
15
16 #include "bitmap.h"
17 #include "types.h"
18 #include "globals.h"
19 #include "helper.h"
20
21 /**
22  * Prints out error message when file cannot be read
23  * @param fileName Name of file that could not be read
24  */
25 void fileErr(char* fileName) {
26     printf("Error reading file: %s\n", fileName);
27     printf("If not in the CSSE labs, you will need to include the directory containing\n");
28     printf("the models on the command line, or put it in the same folder as the exectutable.");
29     exit(EXIT_FAILURE);
30 }
31
32 /**
33  * Reads .bmp texture files and converts them to a texture object
34  * @param fileName .bmp texture file
35  * @return texture object
36  */
37 texture* loadTexture(char *fileName) {
38     texture* t = malloc(sizeof (texture));
39     BITMAPINFO *info;
40
41     t->rgbData = LoadDIBitmap(fileName, &info);
42     t->height=info->bmiHeader.biHeight;
43     t->width=info->bmiHeader.biWidth;
44
45     return t;
46 }
47
48 /**
49  * Reads .x files and converts them to a mesh object
50  * @param fileName .x mesh file
51  * @return mesh object
52  */
53 mesh* loadMesh(char* fileName) {
54     mesh* m = malloc(sizeof (mesh));
55     FILE* fp = fopen(fileName, "r");
56     char line[256] = "";
57     int lineBuffSize = 256;
58
59     if(fp == NULL) fileErr(fileName);
60
61     while(strcmp(line,"Mesh {\r\n") != 0 && strcmp(line,"Mesh {\n") != 0 )
62         fgets(line, lineBuffSize, fp);
63
64     fscanf(fp, "%d;\n", &(m->nVertices));
65     m->vertices = malloc(m->nVertices * sizeof(vertex));
66     for(int i=0; i < m->nVertices; i++)
67         fscanf(fp, "%f; %f; %f;%*[,;]\n", &(m->vertices[i][0]), &(m->vertices[i][1]), &(m->vertices[i][2]) );
68
69     fscanf(fp, "%d;\n", &(m->nTriangles));
70     m->triangles = malloc(m->nTriangles * sizeof(triangle));
71     for(int i=0; i < m->nTriangles; i++)
72         fscanf(fp, "%*d; %d, %d, %d;%*[;,]", m->triangles[i], m->triangles[i]+1, m->triangles[i]+2);
73
74     while(strcmp(line,"  MeshNormals {\r\n") != 0 && strcmp(line,"  MeshNormals {\n") != 0)
75         fgets(line, lineBuffSize, fp);
76
77     fgets(line, lineBuffSize, fp);
78     m->normals = malloc(m->nVertices * sizeof(normal));
79     for(int i=0; i < m->nVertices; i++)
80         fscanf(fp, "%f; %f; %f;%*[;,]\n",
81                &(m->normals[i][0]), &(m->normals[i][1]), &(m->normals[i][2]));
82
83     while(strcmp(line,"MeshTextureCoords {\r\n") != 0 && strcmp(line,"MeshTextureCoords {\n") != 0)
84         fgets(line, lineBuffSize, fp);
85
86     fgets(line, lineBuffSize, fp);
87     m->texCoords = malloc(m->nVertices * sizeof(texCoord));
88     for(int i=0; i < m->nVertices; i++)
89         fscanf(fp, "%f;%f;%*[,;]\n", &(m->texCoords[i][0]), &(m->texCoords[i][1]) );
90     fclose(fp);
91
92     return m;
93 }
94
95 // [You may want to add to this function.]
96 /**
97  * Loads mesh[i] if it isn't already loaded.
98  * You must call getMesh(i) at least once before using mesh[i].
99  *
100  * @param i Mesh ID
101  */
102 void getMesh(int i) { // getMesh(i) loads mesh[i] if it isn't already loaded.
103     char fileName[220];
104     if(i>=NMESH || i<0) {
105         printf("Error in getMesh - wrong model number");
106         exit(1);
107     }
108     if(meshes[i] != NULL)
109         return;
110     sprintf(fileName, "%s/model%d.x", dataDir, i+1);
111     meshes[i] = loadMesh(fileName);
112 }
113
114 /**
115  * Loads texture i if it isn't already loaded
116  *
117  * After calling getTexture(i), you can make texture i the current texture using
118  *      glBindTexture(GL_TEXTURE_2D, i);
119  * Use i=0 to return to the default plain texture.
120  *
121  * You can then scale the texture via:
122  *      glMatrixMode(GL_TEXTURE);
123  * See the textbook, section 8.8.3.
124  *
125  * You must call getTexture(i) at least once before using texture i.
126  * @param i Texture ID
127  */
128 void getTexture(int i) {
129     char fileName[220];
130     if(i<1 || i>NTEXTURE) {
131         printf("Error in getTexture - wrong texture number");
132         exit(1);
133     }
134     if(textures[i-1] != NULL)
135         return;
136     sprintf(fileName, "%s/texture%d.bmp", dataDir, i);
137
138     textures[i-1] = loadTexture(fileName);
139
140     glBindTexture(GL_TEXTURE_2D, i);
141
142     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textures[i-1]->width, textures[i-1]->height,
143                  0, GL_RGB, GL_UNSIGNED_BYTE, textures[i-1]->rgbData);
144     gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, textures[i-1]->width, textures[i-1]->height, GL_RGB,
145                       GL_UNSIGNED_BYTE, textures[i-1]->rgbData);
146     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
147     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
148     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
149     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
150
151     glBindTexture(GL_TEXTURE_2D, 0);  // Back to default texture
152 }
153
154 /**
155  * Rounds up numbers, from http://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number
156  * @param numToRound Number to round
157  * @param multiple Multiple to round up to
158  * @return Rounded number
159  */
160 int roundUp(int numToRound, int multiple) {
161   if(multiple == 0) {
162     return numToRound;
163   }
164
165   int remainder = numToRound % multiple;
166   if (remainder == 0)
167     return numToRound;
168   return numToRound + multiple - remainder;
169 }
170
171 /**
172  * Makes a submenu from an array of items, splitting the list into subsubmenus
173  * of only 10 items.
174  * @param menuEntries Array of menu items
175  * @param menuEntriesSize Size of menuEntries
176  * @param callback Callback function for this array of menu items
177  * @return Reference to menu created
178  */
179 int makeSubmenuFromArray( const char *menuEntries[], unsigned int menuEntriesSize, void *callback ) {
180   if ( menuEntriesSize == 0 ) return -1;
181
182   int menuNumber = roundUp(menuEntriesSize, 10) / 10;
183   int submenuObjects[menuNumber-1];
184
185   for( int i = 0; i < menuNumber; i++ ) {
186     submenuObjects[i] = glutCreateMenu(callback);
187     int startNum = i*11 - (i-1);
188     for ( int j = startNum - 1; j < (startNum+9); j++ ) {
189       if ( j == menuEntriesSize ) break; // Detect if we've reached the end of the array
190       glutAddMenuEntry( menuEntries[j], j + 1 );
191     }
192   }
193
194   int mainMenu = glutCreateMenu(callback);
195   for ( int i = 0; i < menuNumber; i++ ) {
196     char name[10]; // buffer to hold name
197     int startNum = i*11 - (i-1);
198     int endNum = startNum + 9;
199     if ( i == menuNumber - 1 ) { // We're on the last one
200       endNum = startNum + (menuEntriesSize - startNum); // Work out final number
201     }
202     sprintf(name, "%d-%d", startNum, endNum);
203     glutAddSubMenu( name, submenuObjects[i] );
204   }
205
206   return mainMenu;
207 }
208
209 /**
210  * Draw a floor by looping over the floorSize and squareSize variables
211  */
212 void drawFloor() {
213         glBegin(GL_QUADS);
214     for ( int x = -floorSize; x < floorSize; x++ ) {
215       for ( int z = -floorSize; z < floorSize; z++ ) {
216         glColor3f( 1.0, 1.0, 1.0 );
217         glVertex3f( (x+1)*squareSize, 0.0, (z+1)*squareSize );
218         glVertex3f( (x+1)*squareSize, 0.0,     z*squareSize );
219         glVertex3f(     x*squareSize, 0.0,     z*squareSize );
220         glVertex3f(     x*squareSize, 0.0, (z+1)*squareSize );
221       }
222     }
223         glEnd();
224 }
225
226 /**
227  * Draw x, z axis on floor
228  */
229 void drawAxisLines() {
230   // **NOTE: Function does not currently draw arrow-heads
231
232   glDisable(GL_TEXTURE_2D);
233   glDisable(GL_LIGHTING);
234   glEnable(GL_BLEND);
235   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
236   glEnable(GL_LINE_SMOOTH);
237   glColor3f( 0.0, 0.0, 0.0 );
238
239   float arrowLength = 1.0;
240
241   glBegin(GL_LINES);
242     // x arrow
243     glVertex3i(  lineLength, 0.0, 0.0 );
244     glVertex3i( -lineLength, 0.0, 0.0 );
245     
246     // x arrowheads
247     glVertex3i(  lineLength, 0.0, 0.0 );
248     glVertex3i(  lineLength - arrowLength, 0.0,  1.0 );
249
250     glVertex3i(  lineLength, 0.0, 0.0 );
251     glVertex3i(  lineLength - arrowLength, 0.0, -1.0 );
252
253     // z arrow
254     glVertex3i(  0.0, 0.0,  lineLength );
255     glVertex3i(  0.0, 0.0, -lineLength );
256
257     // z arrowheads
258     glVertex3i(  0.0, 0.0,  lineLength );
259     glVertex3i(  1.0, 0.0,  lineLength - arrowLength );
260
261     glVertex3i(  0.0, 0.0,  lineLength );
262     glVertex3i( -1.0, 0.0,  lineLength - arrowLength );
263   glEnd();
264
265   glDisable(GL_BLEND);
266   glEnable(GL_LIGHTING);
267   glEnable(GL_TEXTURE_2D);
268 }

UCC git Repository :: git.ucc.asn.au