//////////////////////////////////////////////////////////// // terrain.cpp // // Terrain class for EDrive, a multiplatform driving simulator. // // Copyright 2004 by Evan Alexander Weaver // // Despite the copyright, this is free software. See edrive.cpp for details. // // Date last modified: 31 May 2004 #include #include "error.h" #include "edmath.h" #include "graphics.h" #include "terrain.h" //////////////////////////////////////////////////////////////////////// // terrain class // // Comprised of several things (none of which should have vertical surfaces) // over which cars can drive. // Initially, the terrain is empty // terrain::terrain() { tricnt = piececnt = 0; } terrain::~terrain() { destroy(); } // Get rid of the pieces comprising the terrain // void terrain::destroy() { for (int i = 0; i < piececnt; i++) piece[i].destroy(); piececnt = 0; tricnt = 0; } // Load terrain data from file // bool terrain::create(graphics &gr, const char *file) { FILE *fp; char texfile[200]; int i, j, n; bool rc = false; vector nv; float u[3], v[3], r = 1, g = 1, b = 1; char c = 'm'; destroy(); // in case it had previously been loaded if (fp = fopen(file, "r")) { while (5 == fscanf(fp, "%d%f%f%f %[^\n]\n", &n, &r, &g, &b, texfile)) { // found the start of a piece, so create that piece // if (rc = piece[piececnt].create(gr, mkcolor(r, g, b), TRIANGLELIST, texfile, n * 3)) { // load in the triangle data, storing a copy in the member // "tri" as well as passing it along to the piece // for (i = tricnt; i < n + tricnt; i++) { for (j = 0; j < 3; j++) { fscanf(fp, "(%f,%f,%f) [%f,%f]\n", &tri[i][j].x, &tri[i][j].y, &tri[i][j].z, &u[j], &v[j]); tri[i][j].z = Z(tri[i][j].z); } // compute the normal for the triangle (note: eventually // this might be part of the input data) // nv = right(tri[i][1]-tri[i][0], tri[i][2]-tri[i][0]); normalize(nv); for (j = 0; j < 3; j++) piece[piececnt].add(tri[i][j].x, tri[i][j].y, tri[i][j].z, nv.x, nv.y, nv.z, u[j], v[j], j%3 == 2); } tricnt += n; piececnt++; } } fclose(fp); } return rc; } // Return the height of the point on the terrain where the X coordinate is "x" // and the Z coordinate is "z". This is done by searching all the triangles // of the terrain until a match is found, then using a little algebra to // compute the height. // float terrain::height(float x, float z) { bool stilllooking = true; float rc = 0; int i; for (i = 0; stilllooking && i < tricnt; i++) { if (inxztriangle(x, z, tri[i][0], tri[i][1], tri[i][2])) { // found the triangle it is in, so compute the height // (y) by substituting x and z into the equation for // the triangle's plane. // stilllooking = false; vector n = cross(tri[i][1]-tri[i][0], tri[i][2]-tri[i][0]); float d = dot(tri[i][0], n); rc = (d - n.x * x - n.z * z)/n.y; } } return rc; } // Draw the terrain on "g". // void terrain::draw(graphics &g) { for (int i = 0; i < piececnt; i++) piece[i].draw(g); }