3 * Contains all of the project's helper functions
4 * @author Ashley Tyndall (20915779), Jenna de la Harpe (20367932)
22 * Prints out error message when file cannot be read
23 * @param fileName Name of file that could not be read
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.");
33 * Reads .bmp texture files and converts them to a texture object
34 * @param fileName .bmp texture file
35 * @return texture object
37 texture* loadTexture(char *fileName) {
38 texture* t = malloc(sizeof (texture));
41 t->rgbData = LoadDIBitmap(fileName, &info);
42 t->height=info->bmiHeader.biHeight;
43 t->width=info->bmiHeader.biWidth;
49 * Reads .x files and converts them to a mesh object
50 * @param fileName .x mesh file
53 mesh* loadMesh(char* fileName) {
54 mesh* m = malloc(sizeof (mesh));
55 FILE* fp = fopen(fileName, "r");
57 int lineBuffSize = 256;
59 if(fp == NULL) fileErr(fileName);
61 while(strcmp(line,"Mesh {\r\n") != 0 && strcmp(line,"Mesh {\n") != 0 )
62 fgets(line, lineBuffSize, fp);
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]) );
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);
74 while(strcmp(line," MeshNormals {\r\n") != 0 && strcmp(line," MeshNormals {\n") != 0)
75 fgets(line, lineBuffSize, fp);
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]));
83 while(strcmp(line,"MeshTextureCoords {\r\n") != 0 && strcmp(line,"MeshTextureCoords {\n") != 0)
84 fgets(line, lineBuffSize, fp);
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]) );
95 // [You may want to add to this function.]
97 * Loads mesh[i] if it isn't already loaded.
98 * You must call getMesh(i) at least once before using mesh[i].
102 void getMesh(int i) { // getMesh(i) loads mesh[i] if it isn't already loaded.
104 if(i>=NMESH || i<0) {
105 printf("Error in getMesh - wrong model number");
108 if(meshes[i] != NULL)
110 sprintf(fileName, "%s/model%d.x", dataDir, i+1);
111 meshes[i] = loadMesh(fileName);
115 * Loads texture i if it isn't already loaded
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.
121 * You can then scale the texture via:
122 * glMatrixMode(GL_TEXTURE);
123 * See the textbook, section 8.8.3.
125 * You must call getTexture(i) at least once before using texture i.
126 * @param i Texture ID
128 void getTexture(int i) {
130 if(i<1 || i>NTEXTURE) {
131 printf("Error in getTexture - wrong texture number");
134 if(textures[i-1] != NULL)
136 sprintf(fileName, "%s/texture%d.bmp", dataDir, i);
138 textures[i-1] = loadTexture(fileName);
140 glBindTexture(GL_TEXTURE_2D, i);
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);
151 glBindTexture(GL_TEXTURE_2D, 0); // Back to default texture
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
160 int roundUp(int numToRound, int multiple) {
165 int remainder = numToRound % multiple;
168 return numToRound + multiple - remainder;
172 * Makes a submenu from an array of items, splitting the list into subsubmenus
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
179 int makeSubmenuFromArray( const char *menuEntries[], unsigned int menuEntriesSize, void *callback ) {
180 if ( menuEntriesSize == 0 ) return -1;
182 int menuNumber = roundUp(menuEntriesSize, 10) / 10;
183 int submenuObjects[menuNumber-1];
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 );
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
202 sprintf(name, "%d-%d", startNum, endNum);
203 glutAddSubMenu( name, submenuObjects[i] );
210 * Draw a floor by looping over the floorSize and squareSize variables
215 glBindTexture(GL_TEXTURE_2D, 2);
216 for ( int x = -floorSize; x < floorSize; x++ ) {
217 for ( int z = -floorSize; z < floorSize; z++ ) {
218 glColor3f( 1.0, 1.0, 1.0 );
219 glVertex3f( (x+1)*squareSize, 0.0, (z+1)*squareSize );
220 glVertex3f( (x+1)*squareSize, 0.0, z*squareSize );
221 glVertex3f( x*squareSize, 0.0, z*squareSize );
222 glVertex3f( x*squareSize, 0.0, (z+1)*squareSize );
229 * Draw x, z axis on floor
231 void drawAxisLines() {
232 // **NOTE: Function does not currently draw arrow-heads
234 glDisable(GL_TEXTURE_2D);
235 glDisable(GL_LIGHTING);
237 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
238 glEnable(GL_LINE_SMOOTH);
239 glColor3f( 0.0, 0.0, 0.0 );
241 float arrowLength = 1.0;
245 glVertex3i( lineLength, 0.0, 0.0 );
246 glVertex3i( -lineLength, 0.0, 0.0 );
249 glVertex3i( lineLength, 0.0, 0.0 );
250 glVertex3i( lineLength - arrowLength, 0.0, 1.0 );
252 glVertex3i( lineLength, 0.0, 0.0 );
253 glVertex3i( lineLength - arrowLength, 0.0, -1.0 );
256 glVertex3i( 0.0, 0.0, lineLength );
257 glVertex3i( 0.0, 0.0, -lineLength );
260 glVertex3i( 0.0, 0.0, lineLength );
261 glVertex3i( 1.0, 0.0, lineLength - arrowLength );
263 glVertex3i( 0.0, 0.0, lineLength );
264 glVertex3i( -1.0, 0.0, lineLength - arrowLength );
268 glEnable(GL_LIGHTING);
269 glEnable(GL_TEXTURE_2D);