// // Handle rendering of landscape // // Copyright (C) J. Belson 2001.12.06 // // $Author: jon $ : $Date: 2002/09/28 16:25:15 $ // #include #include "handler_land.h" #include "gradient.h" #include "hf_skydome.h" #include "handler_sky.h" #include "perlin.h" #include "point2d.h" #include "procedural.h" #include "renderer_flat_int.h" #include "texture.h" #include "triangle3d.h" handler_land::handler_land(int w, int h, const render_info& info) : handler_base(w, h, info) { my_settings.get_float(WAVE_HEIGHT, &wave_height); my_settings.get_float(WAVE_SCALE, &wave_scale); my_settings.get_float(WATER_REFLECTIVITY, &water_reflectivity); my_settings.get_float(WATER_LEVEL, &water_level); wave_scale += 0.5; px.set_seed(345); py.set_seed(765); pz.set_seed(23452); px.set_freq_scale(wave_scale/2); py.set_freq_scale(wave_scale/2); pz.set_freq_scale(wave_scale/2); num_tri = 0; call_count = 0; float i, j, k; my_settings.get_float3(LIGHT_VECTOR, &i, &j, &k); light = vector3d(i, j, k); hf_sky = new hfield(HF_SKYDOME); sky = new handler_sky(w, h, info); } handler_land::~handler_land() { delete hf_sky; delete sky; } // // Calculate height for specified point // float handler_land::get_height(float x, float y) { call_count++; return land->get_height(x, y); } //#define USE_CACHE #undef USE_CACHE // // Pass patch through render pipeline // void handler_land::process_patch(const point3d& p1, const point3d& p2, const point3d& p3, const point3d& p4) { #ifdef USE_CACHE // Cache patches so we can deal with them all at once cache.add_patch(p1, p2, p3, p4); if (!cache.is_full()) { return; } //printf("cache full\n"); #endif #ifdef USE_CACHE point3d* points = 0; triangle3d* triangle = 0; cache.get_triangles(triangle, points); int num_tri = cache.get_num(); //cache.dump(); #else point3d points[4]; points[0] = p1; points[1] = p2; points[2] = p3; points[3] = p4; #endif // Flatten at sea level // for (int i=0; i<4; i++) { for (int i=0; itrace_path(p, reflection); fcolour col; if (found) { // Found an intersection point, figure out the reflected colour // Calculate surface normal at reflected point normal = land->get_normal(p.x, p.z); if (textures) { col = proc::rough(p.x*800, p.z*800, normal); } else { //uint8 r, g, b; col = colour::get_colour_from_height(p.y /*, &r, &g, &b*/); //col = fcolour(r/255.0, g/255.0, b/255.0); } col = col*water_reflectivity; // + water_colour*0.25; triangle[tri].set_colour(col); triangle[tri].normal = normal; triangle[tri+1].set_colour(col); triangle[tri+1].normal = normal; } else { // Check for intersection with sky point3d p = triangle[tri].find_centre(points); point3d p2 = triangle[tri+1].find_centre(points); p = point3d((p.x + p2.x)/2.0, (p.y + p2.y)/2.0, (p.z + p2.z)/2.0); found = hf_sky->trace_path(p, reflection); if (found) { /////p = triangle[tri].find_centre(points); col = sky->get_colour(p); col = col*water_reflectivity; // + water_colour*0.25; triangle[tri].set_colour(col); triangle[tri+1].set_colour(col); //triangle[tri].set_colour(fcolour(1.0, 1.0, 1.0)); } else { triangle[tri].set_colour(water_colour); triangle[tri+1].set_colour(water_colour); } } } else { triangle[tri].set_colour(water_colour); triangle[tri+1].set_colour(water_colour); } } else { triangle[tri].calculate_normal(points); //triangle[1].calculate_normal(points); triangle[tri+1].normal = triangle[tri].normal; // Skip backfacing triangles... if (backface_cull) { point3d p = triangle[tri].find_centre(points); point3d vp = viewpoint; vector3d view = vp - p; // Vector from point to camera vector3d normal = triangle[tri].normal; // Normal at triangle if (check_backface(normal, view)) { triangle[tri].set_flag(eINVISIBLE); triangle[tri+1].set_flag(eINVISIBLE); /*break;*/ continue; } } fcolour col; point3d p = triangle[tri].find_centre(points); //find_centre(tri3d[i], pnt3d1); point3d p2 = triangle[tri+1].find_centre(points); p = point3d((p.x + p2.x)/2.0, (p.y + p2.y)/2.0, (p.z + p2.z)/2.0); if (textures) { col = proc::rough(p.x* 200 /*800*/, p.z*200 /*800*/, triangle[tri].normal); col.clamp(); } else { //uint8 r, g, b; col = colour::get_colour_from_height(p.y /*, &r, &g, &b*/); //col = fcolour(r/255.0, g/255.0, b/255.0); } triangle[tri].set_colour(col); triangle[tri+1].set_colour(col); } if (shadows) { // Trace straight line from triangle to light, checking for intersections with ground point3d p = triangle[tri].find_centre(points); point3d p2 = triangle[tri+1].find_centre(points); p = point3d((p.x + p2.x)/2.0, (p.y + p2.y)/2.0, (p.z + p2.z)/2.0); bool found = land->trace_path(p, -light); p.y += 0.2; if (found) { triangle[tri].set_flag(eSHADOW); triangle[tri+1].set_flag(eSHADOW); } else { triangle[tri].clear_flag(eSHADOW); triangle[tri+1].clear_flag(eSHADOW); } } triangle[tri+1].normal = triangle[tri].normal; } //puts("processed triangles"); #if 0 vector3d& v1 = triangle[0].normal; vector3d& v2 = triangle[1].normal; if (v1.i != v2.i && v1.j != v2.j && v1.k != v2.k) { //std::cout << "NORMALS NOT SAME" << std::endl; } #endif // Translate/rotate transform(points, num_tri*4 /*4*/); // Do perspective transform... // point2d pnt2d[4]; point2d* pnt2d = new point2d[num_tri*4]; perspective(points, pnt2d, num_tri*4 /*4*/); transform_normals(triangle, num_tri /*2*/); // Render the strip... vector3d dummy[4]; rinfo.rend->setup( triangle, pnt2d, dummy, num_tri /*2*/, rinfo.fbuffer, rinfo.bytes_per_row, scene_width, scene_height, rinfo.zb); rinfo.rend->do_render(); num_tri+=2; delete [] pnt2d; cache.clear(); #if 0 // Aaarrggghhhh!!!!!! if (/*(num_tri%100) == 0 &&*/ rinfo.prog) { rinfo.prog->update_status(); if (rinfo.prog->cancelled()) { set_cancelled(); } } #endif } // // Decide is a triangle is a part of the sea // bool handler_land::check_sea_level(triangle3d& tri, const point3d* pnt3d) { bool sea = true; for (int i=0; i<3; i++) { if (pnt3d[tri.point[i]].y > water_level+0.01) { sea = false; break; } } return sea; } // // Apply water ripples to points // void handler_land::make_waves(point3d* pnt3d, int num_points) { for (int idx=0; idxset_message("Rendering land..."); // Transform the light.. //cout << "light is " << light << endl; light = camera*light; //cout << "transformed light is " << light2 << endl; rinfo.rend->set_light(light); float h1 = get_height(-TERRAIN_WIDTH/2, -TERRAIN_WIDTH/2 + TERRAIN_WIDTH); float h2 = get_height(-TERRAIN_WIDTH/2 + TERRAIN_WIDTH, -TERRAIN_WIDTH/2 + TERRAIN_WIDTH); float h3 = get_height(-TERRAIN_WIDTH/2 + TERRAIN_WIDTH, -TERRAIN_WIDTH/2); float h4 = get_height(-TERRAIN_WIDTH/2, -TERRAIN_WIDTH/2); subdivide(-TERRAIN_WIDTH/2, -TERRAIN_WIDTH/2, TERRAIN_WIDTH, h1, h2, h3, h4); printf("call_count = %d\n", call_count); printf("num_tri = %d\n", num_tri); } void handler_land::set_heightfield(hfield* hf) { land = hf; }