// // This source code is property of the Computer Graphics and Visualization // chair of the TU Dresden. Do not distribute in modified or unmodified form! // Copyright (C) 2016 CGV TU Dresden - All Rights Reserved // #include "terrain.h" // Load images and initialize variables terrain::terrain() { initialized = false; heightmap = 0; angle = 0; // The display list is not valid dl_valid = false; dl_handle = 0; // Try to load the heightmap if (!load_heightmap("../../data/tex_height.bmp")) return; // Try to load the texture if (!load_texture("../../data/tex_topo.bmp", &texture_handle)) return; initialized = true; // Basic initial settings set_show_solid(true); set_show_wireframe(false); set_show_levels(false); } // Unload images and textures terrain::~terrain() { // Delete the texture glDeleteTextures(1, &texture_handle); // Free the memory for the height map BMP_Free(heightmap); // Delete the display list if neccessary if (glIsList(dl_handle)) glDeleteLists(dl_handle, 1); } // Render the actual scene void terrain::render() { // Enable depth testing glEnable(GL_DEPTH_TEST); // Enable automatic normalization of normals glEnable(GL_NORMALIZE); // Clear the screen glClearColor(1,1,1,0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Nothing to do if we are not properly initialized if (!initialized) return; // Setup perspective and modelview matrix setup_projection(); // Setup light setup_light(); // Render the solid terrain with lighting and texture mapping if (show_solid) render_solid_terrain(); // Render the outline of the terrain if (show_wireframe) render_wireframe_terrain(); // Eventually render level lines if (show_levels) render_level_lines(); } // Render the terrain as solid void terrain::render_solid_terrain() { // Enable lighting glEnable(GL_LIGHTING); // This is a trick which is neccessary in order to draw lines // later on. Otherwise there would be artifacts due to a z-fight. glPolygonOffset(1, 1); glEnable(GL_POLYGON_OFFSET_FILL); /******** Task 2.2.4. Activate 2D texture mapping and bind the texture that is identified by the handle "texture_handle". Do not remove any of the code in this method. Aufgabe 2.2.4. Aktivieren Sie 2D-Texturierung und binden Sie die Textur, die ueber das Handle "texture_handle" identifiziert ist. Entfernen Sie keinen Code in dieser Methode. ************/ // Set the material color to white glColor3d(1, 1, 1); // Render the terrain render_terrain(); // Disable texture mapping glDisable(GL_TEXTURE_2D); // Disable support for depth buffer offsets glDisable(GL_POLYGON_OFFSET_FILL); // Disable lighting glDisable(GL_LIGHTING); } // Render the terrain as wireframe void terrain::render_wireframe_terrain() { // Set the line width to be 1 pixel glLineWidth(1.0); // Set the draw mode to draw outlines of polygons glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Set the color to black glColor3d(0, 0, 0); // Render the terrain render_terrain(); // Set the draw mode to fill polygons glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } // Render the terrain void terrain::render_terrain() { // Store width and height for faster access int map_width = get_heightmap_width(); int map_height = get_heightmap_height(); // Move and scale the coordinate system so that we can work with // whole units. That means that a vertex at height map position (x, y) // with a height of h can be placed as glVertex3d(x, h, y). The // terrain extents in the XZ-layer while the height is on the Y-axis. glPushMatrix(); glTranslated(-1, 0, -1); glScaled(2.0/static_cast(map_width), 1.0/256.0, 2.0/static_cast(map_height)); /******** Task 2.2.1. Complete the code below to create a regular grid which expands along the X-Z-layer. Create the grid by specifying triangle strips for each line. The coordinate system is already scaled and translated to use the values of the variables "x" and "y" defined below directly as coordinates. The initial height of the grid shall be 0. Aufgabe 2.2.1. Vervollstaendigen Sie den nachfolgenden Quelltext um die Erstellung eines regelmaessigen Gitters das sich ueber die X-Z-Ebene erstreckt. Erstellen Sie dieses Gitter, indem Sie zeilenweise Dreiecksstreifen definieren. Das Koordinatensystem ist bereits skaliert und verschoben, so dass Sie die Werte der Variablen "x" und "y", die unten definiert werden direkt als Koordinaten einsetzen koennen. Das Gitter soll zunaechst eine Hoehe von 0 besitzen. Task 2.2.2. Now elevate the height of the vertices to create the grid terrain that corresponds to the height map. Use "get_heightmap_value(x, y)". Aufgabe 2.2.2. Heben Sie jetzt die Vertices an um ein Drahtgitterterrain zu erstellen, das zur Hoehenkarte korrespondiert. Nutzen Sie die Methode "get_heightmap_value(x, y)". Task 2.2.3. Make sure to call "set_normal" for every vertex and continue this task in "set_normal". Aufgabe 2.2.3. Stellen Sie sicher, dass Sie "set_normal" für jeden Vertex aufrufen und fahren Sie in "set_normal" mit der Aufgabe fort. Task 2.2.4. Activate texture mapping and bind the texture in the method "render_solid_terrain". Provide 2D texture coordinates per vertex in this method using "glTexCoord2d". Aufgabe 2.2.4. Aktivieren Sie Texturmapping und binden Sie eine Textur in der Methode "render_solid_terrain". Spezifizieren Sie in dieser Methode pro Vertex eine Texturkoordinate mittels der Methode "glTexCoord2d". *********/ // Go through all rows (-1) for (int y = 0; y(get_heightmap_width()), 1.0/256.0, 2.0/static_cast(get_heightmap_height())); // Connect with lines glBegin(GL_LINES); // Render lines which were created in "create_level_lines" and stored into // the list "level_lines" for (int i=0; i<(int)level_lines.size(); i+=2) { glVertex3d(level_lines[i ].x(), level_lines[i ].y(), level_lines[i ].z()); glVertex3d(level_lines[i+1].x(), level_lines[i+1].y(), level_lines[i+1].z()); } glEnd(); // Set the width back to 1.0 glLineWidth(1.0); glPopMatrix(); } // Create height lines for the level "level" void terrain::create_level_line(int level) { /******** Additional Task: Find iso lines with the "Marching Squares" algorithm for the height value "level". Store the start and end points of the found lines in the list "level_lines". Zusatzaufgabe: Finden Sie Hoehenlinien mittels des "Marching Squares"-Algorithmus fuer den Hoehenwert "level". Legen Sie die Start- und Endpunkte der gefundenen Linien in der Liste "level_lines" ab. *************/ } // Set the light parameters void terrain::setup_light() { // Enable lighting and colored materials glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); // Enable light source 0 glEnable(GL_LIGHT0); // Set the modelview matrix to be the identity to avoid // having the light position moved with the terrain. glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // Set light parameters float position[4]={1.0f,1.0f,1.0f,1.0f}; float ambient_color[4]={0.0f,0.0f,0.0f,1.0f}; float diffuse_color[4]={1.0f,1.0f,1.0f,1.0f}; float specular_color[4]={1.0f,1.0f,1.0f,1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_color); glLightfv(GL_LIGHT0, GL_SPECULAR, specular_color); glLightf(GL_LIGHT0,GL_SPOT_EXPONENT, 10.0f); glPopMatrix(); glDisable(GL_LIGHTING); } // Set the projection and the view void terrain::setup_projection() { // For projection choose a perspective matrix with an aperture angle of // 45deg, an aspect ratio that corresponds to the width and height of the // window, z_near at 0.01 and z_far at 10.0 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, glutGet(GLUT_WINDOW_WIDTH) / static_cast(glutGet(GLUT_WINDOW_HEIGHT)), 0.01, 10.0); // For the modelview matrix choose a view from the position (2.5, 2.5, 0) to // the position (0, 0, 0) where the up-direction is (0, 1, 0). // Also rotate with the specified angle around the Y-axis glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(2.5,2.5,0, 0,0,0, 0,1,0); glRotated(angle, 0,1,0); } // Advance one frame void terrain::advance_frame() { // Increase angle and perform a modulo 360 angle = (angle+1)%360; } // (De)activate solid rendering void terrain::set_show_solid(bool state) { show_solid = state; // The current display list is outdated now dl_valid = false; } // (De)activate wireframe rendering void terrain::set_show_wireframe(bool state) { show_wireframe = state; // The current display list is outdated now dl_valid = false; } // (De)activate height level line rendering void terrain::set_show_levels(bool state) { show_levels = state; // If level lines shall be displayed then // recreate them in equidistant ranges if (show_levels) { level_lines.clear(); for (int i=20; i<=255; i+=20) create_level_line(i); } // The current display list is outdated now dl_valid = false; } // Load the height map from the file "filename" bool terrain::load_heightmap(const char *filename) { // Load the heightmap by reading a bmp file heightmap = BMP_ReadFile(filename); // Return false and show an error message if the file // could not be loaded if (BMP_GetError() != BMP_OK) { std::cout<=get_heightmap_width()) x = 2*get_heightmap_width()-x-1; if (y>=get_heightmap_height()) y = 2*get_heightmap_height()-y-1; // Read the pixel and return the red component BMP_GetPixelRGB(heightmap, x, y, &r, &g, &b); return r; } // Set debug text void terrain::set_text(std::stringstream &stream) { if (!initialized) { stream<<"Cannot show terrain - not all files were loaded!"; return; } stream<<"Showing terrain"; if (!show_solid && !show_wireframe && !show_levels) { stream<<" (all features disabled)"; return; } stream<<" ("; if (show_solid) stream<<"as solid geometry"; if (show_solid && show_wireframe) stream<<", "; if (show_wireframe) stream<<"as wireframe"; if (show_wireframe && show_levels) stream<<", "; if (show_levels) stream<<"with level lines"; stream<<")"; }