MapgenV6Params::MapgenV6Params() { np_terrain_base = NoiseParams(-4, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6, 2.0); np_terrain_higher = NoiseParams(20, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6, 2.0); np_steepness = NoiseParams(0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7, 2.0); np_height_select = NoiseParams(0, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69, 2.0); np_mud = NoiseParams(4, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55, 2.0); np_beach = NoiseParams(0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50, 2.0); np_biome = NoiseParams(0, 1.0, v3f(500.0, 500.0, 500.0), 9130, 3, 0.50, 2.0); np_cave = NoiseParams(6, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50, 2.0); np_humidity = NoiseParams(0.5, 0.5, v3f(500.0, 500.0, 500.0), 72384, 3, 0.50, 2.0); np_trees = NoiseParams(0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66, 2.0); np_apple_trees = NoiseParams(0, 1.0, v3f(100.0, 100.0, 100.0), 342902, 3, 0.45, 2.0); }
void LocalPlayer::applyControl(float dtime, ClientEnvironment *env) { // Clear stuff swimming_vertical = false; setPitch(control.pitch); setYaw(control.yaw); // Nullify speed and don't run positioning code if the player is attached if(isAttached) { setSpeed(v3f(0,0,0)); return; } v3f move_direction = v3f(0,0,1); move_direction.rotateXZBy(getYaw()); v3f speedH = v3f(0,0,0); // Horizontal (X, Z) v3f speedV = v3f(0,0,0); // Vertical (Y) bool fly_allowed = m_gamedef->checkLocalPrivilege("fly"); bool fast_allowed = m_gamedef->checkLocalPrivilege("fast"); free_move = fly_allowed && g_settings->getBool("free_move"); bool fast_move = fast_allowed && g_settings->getBool("fast_move"); // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends"); bool continuous_forward = g_settings->getBool("continuous_forward"); bool fast_pressed = false; // Whether superspeed mode is used or not superspeed = false; if(g_settings->getBool("always_fly_fast") && free_move && fast_move) superspeed = true; // Old descend control if(g_settings->getBool("aux1_descends")) { // If free movement and fast movement, always move fast if(free_move && fast_move) superspeed = true; // Auxiliary button 1 (E) if(control.aux1) { if(free_move) { // In free movement mode, aux1 descends if(fast_move) speedV.Y = -movement_speed_fast; else speedV.Y = -movement_speed_walk; } else if(in_liquid || in_liquid_stable) { speedV.Y = -movement_speed_walk; swimming_vertical = true; } else if(is_climbing) { speedV.Y = -movement_speed_climb; } else { // If not free movement but fast is allowed, aux1 is // "Turbo button" if(fast_allowed) superspeed = true; } } } // New minecraft-like descend control else { // Auxiliary button 1 (E) if(control.aux1) { if(!is_climbing) { // aux1 is "Turbo button" if(fast_allowed) superspeed = true; } if(fast_allowed) fast_pressed = true; } if(control.sneak) { if(free_move) { // In free movement mode, sneak descends if(fast_move && (control.aux1 || g_settings->getBool("always_fly_fast"))) speedV.Y = -movement_speed_fast; else speedV.Y = -movement_speed_walk; } else if(in_liquid || in_liquid_stable) { if(fast_climb) speedV.Y = -movement_speed_fast; else speedV.Y = -movement_speed_walk; swimming_vertical = true; } else if(is_climbing) { if(fast_climb) speedV.Y = -movement_speed_fast; else speedV.Y = -movement_speed_climb; } } } if(continuous_forward) speedH += move_direction; if(control.up) { if(continuous_forward) superspeed = true; else speedH += move_direction; } if(control.down) { speedH -= move_direction; } if(control.left) { speedH += move_direction.crossProduct(v3f(0,1,0)); } if(control.right) { speedH += move_direction.crossProduct(v3f(0,-1,0)); } if(control.jump) { if(free_move) { if(g_settings->getBool("aux1_descends") || g_settings->getBool("always_fly_fast")) { if(fast_move) speedV.Y = movement_speed_fast; else speedV.Y = movement_speed_walk; } else { if(fast_move && control.aux1) speedV.Y = movement_speed_fast; else speedV.Y = movement_speed_walk; } } else if(m_can_jump) { /* NOTE: The d value in move() affects jump height by raising the height at which the jump speed is kept at its starting value */ v3f speedJ = getSpeed(); if(speedJ.Y >= -0.5 * BS) { speedJ.Y = movement_speed_jump * physics_override_jump; setSpeed(speedJ); MtEvent *e = new SimpleTriggerEvent("PlayerJump"); m_gamedef->event()->put(e); } } else if(in_liquid) { if(fast_climb) speedV.Y = movement_speed_fast; else speedV.Y = movement_speed_walk; swimming_vertical = true; } else if(is_climbing) { if(fast_climb) speedV.Y = movement_speed_fast; else speedV.Y = movement_speed_climb; } } // The speed of the player (Y is ignored) if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb) || fast_pressed) speedH = speedH.normalize() * movement_speed_fast; else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable) speedH = speedH.normalize() * movement_speed_crouch; else speedH = speedH.normalize() * movement_speed_walk; // Acceleration increase f32 incH = 0; // Horizontal (X, Z) f32 incV = 0; // Vertical (Y) if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump)) { // Jumping and falling if(superspeed || (fast_move && control.aux1)) incH = movement_acceleration_fast * BS * dtime; else incH = movement_acceleration_air * BS * dtime; incV = 0; // No vertical acceleration in air // better air control when falling fast float speed = m_speed.getLength(); if (!superspeed && speed > movement_speed_fast && (control.down || control.up || control.left || control.right)) { v3f rotate = move_direction * (speed / (BS * 120)); // 80 - good wingsuit if(control.up) rotate = rotate.crossProduct(v3f(0,1,0)); if(control.down) rotate = rotate.crossProduct(v3f(0,-1,0)); if(control.left) rotate *=-1; m_speed.rotateYZBy(rotate.X); m_speed.rotateXZBy(rotate.Y); m_speed.rotateXYBy(rotate.Z); m_speed = m_speed.normalize() * speed * (1-speed*0.00001); // 0.998 if (m_speed.Y) return; } } else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb)) incH = incV = movement_acceleration_fast * BS * dtime; else incH = incV = movement_acceleration_default * BS * dtime; // Accelerate to target speed with maximum increment INodeDefManager *nodemgr = m_gamedef->ndef(); Map *map = &env->getMap(); v3s16 p = floatToInt(getPosition() - v3f(0,BS/2,0), BS); float slippery = 0; try { slippery = itemgroup_get(nodemgr->get(map->getNode(p)).groups, "slippery"); } catch (...) {} accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed, slippery); accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed); }
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, std::list<CollisionInfo> *collision_info) { Map *map = &env->getMap(); INodeDefManager *nodemgr = m_gamedef->ndef(); v3f position = getPosition(); v3f old_speed = m_speed; // Copy parent position if local player is attached if(isAttached) { setPosition(overridePosition); m_sneak_node_exists = false; return; } // Skip collision detection if noclip mode is used bool fly_allowed = m_gamedef->checkLocalPrivilege("fly"); bool noclip = m_gamedef->checkLocalPrivilege("noclip") && g_settings->getBool("noclip"); bool free_move = noclip && fly_allowed && g_settings->getBool("free_move"); if(free_move) { position += m_speed * dtime; setPosition(position); m_sneak_node_exists = false; return; } /* Collision detection */ /* Check if player is in liquid (the oscillating value) */ try{ // If in liquid, the threshold of coming out is at higher y if(in_liquid) { v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS); in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity; } // If not in liquid, the threshold of going in is at lower y else { v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS); in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity; } } catch(InvalidPositionException &e) { in_liquid = false; } /* Check if player is in liquid (the stable value) */ try{ v3s16 pp = floatToInt(position + v3f(0,0,0), BS); in_liquid_stable = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); } catch(InvalidPositionException &e) { in_liquid_stable = false; } /* Check if player is climbing */ try { v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS); v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS); is_climbing = ((nodemgr->get(map->getNode(pp).getContent()).climbable || nodemgr->get(map->getNode(pp2).getContent()).climbable) && !free_move); } catch(InvalidPositionException &e) { is_climbing = false; } /* Collision uncertainty radius Make it a bit larger than the maximum distance of movement */ //f32 d = pos_max_d * 1.1; // A fairly large value in here makes moving smoother f32 d = 0.15*BS; // This should always apply, otherwise there are glitches assert(d > pos_max_d); // Maximum distance over border for sneaking f32 sneak_max = BS*0.4; /* If sneaking, keep in range from the last walked node and don't fall off from it */ if(control.sneak && m_sneak_node_exists && !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid && physics_override_sneak) { f32 maxd = 0.5*BS + sneak_max; v3f lwn_f = intToFloat(m_sneak_node, BS); position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd); position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd); if(!is_climbing) { f32 min_y = lwn_f.Y + 0.5*BS; if(position.Y < min_y) { position.Y = min_y; if(m_speed.Y < 0) m_speed.Y = 0; } } } float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2); v3f accel_f = v3f(0,0,0); collisionMoveResult result = collisionMoveSimple(env, m_gamedef, pos_max_d, m_collisionbox, player_stepheight, dtime, position, m_speed, accel_f); /* If the player's feet touch the topside of any node, this is set to true. Player is allowed to jump when this is true. */ bool touching_ground_was = touching_ground; touching_ground = result.touching_ground; //bool standing_on_unloaded = result.standing_on_unloaded; /* Check the nodes under the player to see from which node the player is sneaking from, if any. If the node from under the player has been removed, the player falls. */ v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS); if(m_sneak_node_exists && nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" && m_old_node_below_type != "air") { // Old node appears to have been removed; that is, // it wasn't air before but now it is m_need_to_get_new_sneak_node = false; m_sneak_node_exists = false; } else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air") { // We are on something, so make sure to recalculate the sneak // node. m_need_to_get_new_sneak_node = true; } if(m_need_to_get_new_sneak_node && physics_override_sneak) { v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS); v2f player_p2df(position.X, position.Z); f32 min_distance_f = 100000.0*BS; // If already seeking from some node, compare to it. /*if(m_sneak_node_exists) { v3f sneaknode_pf = intToFloat(m_sneak_node, BS); v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z); f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df); f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y); // Ignore if player is not on the same level (likely dropped) if(d_vert_f < 0.15*BS) min_distance_f = d_horiz_f; }*/ v3s16 new_sneak_node = m_sneak_node; for(s16 x=-1; x<=1; x++) for(s16 z=-1; z<=1; z++) { v3s16 p = pos_i_bottom + v3s16(x,0,z); v3f pf = intToFloat(p, BS); v2f node_p2df(pf.X, pf.Z); f32 distance_f = player_p2df.getDistanceFrom(node_p2df); f32 max_axis_distance_f = MYMAX( fabs(player_p2df.X-node_p2df.X), fabs(player_p2df.Y-node_p2df.Y)); if(distance_f > min_distance_f || max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS) continue; try{ // The node to be sneaked on has to be walkable if(nodemgr->get(map->getNode(p)).walkable == false) continue; // And the node above it has to be nonwalkable if(nodemgr->get(map->getNode(p+v3s16(0,1,0))).walkable == true) { continue; } if (!physics_override_sneak_glitch) { if (nodemgr->get(map->getNode(p+v3s16(0,2,0))).walkable) continue; } } catch(InvalidPositionException &e) { continue; } min_distance_f = distance_f; new_sneak_node = p; } bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9); m_sneak_node = new_sneak_node; m_sneak_node_exists = sneak_node_found; /* If sneaking, the player's collision box can be in air, so this has to be set explicitly */ if(sneak_node_found && control.sneak) touching_ground = true; } /* Set new position */ setPosition(position); /* Report collisions */ bool bouncy_jump = false; // Dont report if flying if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) { for(size_t i=0; i<result.collisions.size(); i++){ const CollisionInfo &info = result.collisions[i]; collision_info->push_back(info); if(info.new_speed.Y - info.old_speed.Y > 0.1*BS && info.bouncy) bouncy_jump = true; } } if(bouncy_jump && control.jump){ m_speed.Y += movement_speed_jump*BS; touching_ground = false; MtEvent *e = new SimpleTriggerEvent("PlayerJump"); m_gamedef->event()->put(e); } if(!touching_ground_was && touching_ground){ MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround"); m_gamedef->event()->put(e); // Set camera impact value to be used for view bobbing camera_impact = getSpeed().Y * -1; } { camera_barely_in_ceiling = false; v3s16 camera_np = floatToInt(getEyePosition(), BS); MapNode n = map->getNodeNoEx(camera_np); if(n.getContent() != CONTENT_IGNORE){ if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){ camera_barely_in_ceiling = true; } } } /* Update the node last under the player */ m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS); m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name; /* Check properties of the node on which the player is standing */ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos())); // Determine if jumping is possible m_can_jump = touching_ground && !in_liquid; if(itemgroup_get(f.groups, "disable_jump")) m_can_jump = false; }
//! constructor Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, ITextureSource *tsrc): scene::ISceneNode(parent, mgr, id), m_visible(true), m_fallback_bg_color(255,255,255,255), m_first_update(true), m_brightness(0.5), m_cloud_brightness(0.5), m_bgcolor_bright_f(1,1,1,1), m_skycolor_bright_f(1,1,1,1), m_cloudcolor_bright_f(1,1,1,1) { setAutomaticCulling(scene::EAC_OFF); Box.MaxEdge.set(0,0,0); Box.MinEdge.set(0,0,0); // create material video::SMaterial mat; mat.Lighting = false; mat.ZBuffer = video::ECFN_NEVER; mat.ZWriteEnable = false; mat.AntiAliasing=0; mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; mat.BackfaceCulling = false; m_materials[0] = mat; m_materials[1] = mat; //m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; m_materials[2] = mat; m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png")); m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; //m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; m_sun_texture = tsrc->isKnownSourceImage("sun.png") ? tsrc->getTextureForMesh("sun.png") : NULL; m_moon_texture = tsrc->isKnownSourceImage("moon.png") ? tsrc->getTextureForMesh("moon.png") : NULL; m_sun_tonemap = tsrc->isKnownSourceImage("sun_tonemap.png") ? tsrc->getTexture("sun_tonemap.png") : NULL; m_moon_tonemap = tsrc->isKnownSourceImage("moon_tonemap.png") ? tsrc->getTexture("moon_tonemap.png") : NULL; if (m_sun_texture){ m_materials[3] = mat; m_materials[3].setTexture(0, m_sun_texture); m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; if (m_sun_tonemap) m_materials[3].Lighting = true; } if (m_moon_texture){ m_materials[4] = mat; m_materials[4].setTexture(0, m_moon_texture); m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; if (m_moon_tonemap) m_materials[4].Lighting = true; } for(u32 i=0; i<SKY_STAR_COUNT; i++){ m_stars[i] = v3f( myrand_range(-10000,10000), myrand_range(-10000,10000), myrand_range(-10000,10000) ); m_stars[i].normalize(); } m_directional_colored_fog = g_settings->getBool("directional_colored_fog"); sun_moon_light = mgr->addLightSceneNode(this, core::vector3df(0,MAP_GENERATION_LIMIT*BS*2,0), video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), MAP_GENERATION_LIMIT*BS*5); }
//#include "serverobject.h" #include "content_sao.h" #include "nodedef.h" #include "content_mapnode.h" // For content_mapnode_get_new_name #include "voxelalgorithms.h" #include "profiler.h" #include "settings.h" // For g_settings #include "main.h" // For g_profiler #include "emerge.h" #include "dungeongen.h" #include "treegen.h" #include "mapgen_v6.h" /////////////////// Mapgen V6 perlin noise default values NoiseParams nparams_v6_def_terrain_base = {-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6}; NoiseParams nparams_v6_def_terrain_higher = {20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6}; NoiseParams nparams_v6_def_steepness = {0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7}; NoiseParams nparams_v6_def_height_select = {0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69}; NoiseParams nparams_v6_def_mud = {AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55}; NoiseParams nparams_v6_def_beach = {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50}; NoiseParams nparams_v6_def_biome = {0.0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50}; NoiseParams nparams_v6_def_cave = {6.0, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50}; NoiseParams nparams_v6_def_humidity =
void ClientLauncher::speed_tests() { // volatile to avoid some potential compiler optimisations volatile static s16 temp16; volatile static f32 tempf; static v3f tempv3f1; static v3f tempv3f2; static std::string tempstring; static std::string tempstring2; tempv3f1 = v3f(); tempv3f2 = v3f(); tempstring = std::string(); tempstring2 = std::string(); { infostream << "The following test should take around 20ms." << std::endl; TimeTaker timer("Testing std::string speed"); const u32 jj = 10000; for (u32 j = 0; j < jj; j++) { tempstring = ""; tempstring2 = ""; const u32 ii = 10; for (u32 i = 0; i < ii; i++) { tempstring2 += "asd"; } for (u32 i = 0; i < ii+1; i++) { tempstring += "asd"; if (tempstring == tempstring2) break; } } } infostream << "All of the following tests should take around 100ms each." << std::endl; { TimeTaker timer("Testing floating-point conversion speed"); tempf = 0.001; for (u32 i = 0; i < 4000000; i++) { temp16 += tempf; tempf += 0.001; } } { TimeTaker timer("Testing floating-point vector speed"); tempv3f1 = v3f(1, 2, 3); tempv3f2 = v3f(4, 5, 6); for (u32 i = 0; i < 10000000; i++) { tempf += tempv3f1.dotProduct(tempv3f2); tempv3f2 += v3f(7, 8, 9); } } { TimeTaker timer("Testing std::map speed"); std::map<v2s16, f32> map1; tempf = -324; const s16 ii = 300; for (s16 y = 0; y < ii; y++) { for (s16 x = 0; x < ii; x++) { map1[v2s16(x, y)] = tempf; tempf += 1; } } for (s16 y = ii - 1; y >= 0; y--) { for (s16 x = 0; x < ii; x++) { tempf = map1[v2s16(x, y)]; } } } { infostream << "Around 5000/ms should do well here." << std::endl; TimeTaker timer("Testing mutex speed"); JMutex m; u32 n = 0; u32 i = 0; do { n += 10000; for (; i < n; i++) { m.Lock(); m.Unlock(); } } // Do at least 10ms while(timer.getTimerTime() < 10); u32 dtime = timer.stop(); u32 per_ms = n / dtime; infostream << "Done. " << dtime << "ms, " << per_ms << "/ms" << std::endl; } }
int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor, int oldvalue, bool *sunlight_seen_result) { const bool debugprint = false; INodeDefManager *ndef = m_gamedef->ndef(); static v3f z_directions[50] = { v3f(-100, 0, 0) }; static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = { -1000, }; if(z_directions[0].X < -99){ for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){ z_directions[i] = v3f( 0.01 * myrand_range(-100, 100), 1.0, 0.01 * myrand_range(-100, 100) ); z_offsets[i] = 0.01 * myrand_range(0,100); } } if(debugprint) std::cerr<<"In goes "<<PP(m_camera_direction)<<", out comes "; int sunlight_seen_count = 0; float sunlight_min_d = max_d*0.8; if(sunlight_min_d > 35*BS) sunlight_min_d = 35*BS; core::array<int> values; for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){ v3f z_dir = z_directions[i]; z_dir.normalize(); core::CMatrix4<f32> a; a.buildRotateFromTo(v3f(0,1,0), z_dir); v3f dir = m_camera_direction; a.rotateVect(dir); int br = 0; float step = BS*1.5; if(max_d > 35*BS) step = max_d / 35 * 1.5; float off = step * z_offsets[i]; bool sunlight_seen_now = false; bool ok = getVisibleBrightness(this, m_camera_position, dir, step, 1.0, max_d*0.6+off, max_d, ndef, daylight_factor, sunlight_min_d, &br, &sunlight_seen_now); if(sunlight_seen_now) sunlight_seen_count++; if(!ok) continue; values.push_back(br); // Don't try too much if being in the sun is clear if(sunlight_seen_count >= 20) break; } int brightness_sum = 0; int brightness_count = 0; values.sort(); u32 num_values_to_use = values.size(); if(num_values_to_use >= 10) num_values_to_use -= num_values_to_use/2; else if(num_values_to_use >= 7) num_values_to_use -= num_values_to_use/3; u32 first_value_i = (values.size() - num_values_to_use) / 2; if(debugprint){ for(u32 i=0; i < first_value_i; i++) std::cerr<<values[i]<<" "; std::cerr<<"["; } for(u32 i=first_value_i; i < first_value_i+num_values_to_use; i++){ if(debugprint) std::cerr<<values[i]<<" "; brightness_sum += values[i]; brightness_count++; } if(debugprint){ std::cerr<<"]"; for(u32 i=first_value_i+num_values_to_use; i < values.size(); i++) std::cerr<<values[i]<<" "; } int ret = 0; if(brightness_count == 0){ MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS)); if(ndef->get(n).param_type == CPT_LIGHT){ ret = decode_light(n.getLightBlend(daylight_factor, ndef)); } else { ret = oldvalue; //ret = blend_light(255, 0, daylight_factor); } } else { /*float pre = (float)brightness_sum / (float)brightness_count; float tmp = pre; const float d = 0.2; pre *= 1.0 + d*2; pre -= tmp * d; int preint = pre; ret = MYMAX(0, MYMIN(255, preint));*/ ret = brightness_sum / brightness_count; } if(debugprint) std::cerr<<"Result: "<<ret<<" sunlight_seen_count=" <<sunlight_seen_count<<std::endl; *sunlight_seen_result = (sunlight_seen_count > 0); return ret; }
int RemoteClient::GetNextBlocks ( ServerEnvironment *env, EmergeManager * emerge, float dtime, double m_uptime, std::vector<PrioritySortedBlockTransfer> &dest) { DSTACK(FUNCTION_NAME); auto lock = lock_unique_rec(); if (!lock->owns_lock()) return 0; // Increment timers m_nothing_to_send_pause_timer -= dtime; m_nearest_unsent_reset_timer += dtime; m_time_from_building += dtime; if (m_nearest_unsent_reset) { m_nearest_unsent_reset = 0; m_nearest_unsent_reset_timer = 999; m_nothing_to_send_pause_timer = 0; m_time_from_building = 999; } if(m_nothing_to_send_pause_timer >= 0) return 0; Player *player = env->getPlayer(peer_id); // This can happen sometimes; clients and players are not in perfect sync. if(player == NULL) return 0; v3f playerpos = player->getPosition(); v3f playerspeed = player->getSpeed(); if(playerspeed.getLength() > 1000.0*BS) //cheater or bug, ignore him return 0; v3f playerspeeddir(0,0,0); if(playerspeed.getLength() > 1.0*BS) playerspeeddir = playerspeed / playerspeed.getLength(); // Predict to next block v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS; v3s16 center_nodepos = floatToInt(playerpos_predicted, BS); v3s16 center = getNodeBlockPos(center_nodepos); // Camera position and direction v3f camera_pos = player->getEyePosition(); v3f camera_dir = v3f(0,0,1); camera_dir.rotateYZBy(player->getPitch()); camera_dir.rotateXZBy(player->getYaw()); //infostream<<"camera_dir=("<<camera_dir<<")"<< " camera_pos="<<camera_pos<<std::endl; /* Get the starting value of the block finder radius. */ if(m_last_center != center) { m_last_center = center; m_nearest_unsent_reset_timer = 999; } if (m_last_direction.getDistanceFrom(camera_dir)>0.4) { // 1 = 90deg m_last_direction = camera_dir; m_nearest_unsent_reset_timer = 999; } /*infostream<<"m_nearest_unsent_reset_timer=" <<m_nearest_unsent_reset_timer<<std::endl;*/ // Reset periodically to workaround for some bugs or stuff if(m_nearest_unsent_reset_timer > 120.0) { m_nearest_unsent_reset_timer = 0; m_nearest_unsent_d = 0; m_nearest_unsent_reset = 0; //infostream<<"Resetting m_nearest_unsent_d for "<<peer_id<<std::endl; } //s16 last_nearest_unsent_d = m_nearest_unsent_d; s16 d_start = m_nearest_unsent_d; //infostream<<"d_start="<<d_start<<std::endl; static const u16 max_simul_sends_setting = g_settings->getU16 ("max_simultaneous_block_sends_per_client"); static const u16 max_simul_sends_usually = max_simul_sends_setting; /* Check the time from last addNode/removeNode. Decrease send rate if player is building stuff. */ static const auto full_block_send_enable_min_time_from_building = g_settings->getFloat("full_block_send_enable_min_time_from_building"); if(m_time_from_building < full_block_send_enable_min_time_from_building) { /* max_simul_sends_usually = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; */ if(d_start<=1) d_start=2; m_nearest_unsent_reset_timer = 999; //magical number more than ^ other number 120 - need to reset d on next iteration } /* Number of blocks sending + number of blocks selected for sending */ u32 num_blocks_selected = 0; u32 num_blocks_sending = 0; /* next time d will be continued from the d from which the nearest unsent block was found this time. This is because not necessarily any of the blocks found this time are actually sent. */ s32 new_nearest_unsent_d = -1; static const auto max_block_send_distance = g_settings->getS16("max_block_send_distance"); s16 full_d_max = max_block_send_distance; if (wanted_range) { s16 wanted_blocks = wanted_range / MAP_BLOCKSIZE + 1; if (wanted_blocks < full_d_max) full_d_max = wanted_blocks; } s16 d_max = full_d_max; static const s16 d_max_gen = g_settings->getS16("max_block_generate_distance"); // Don't loop very much at a time s16 max_d_increment_at_time = 10; if(d_max > d_start + max_d_increment_at_time) d_max = d_start + max_d_increment_at_time; /*if(d_max_gen > d_start+2) d_max_gen = d_start+2;*/ //infostream<<"Starting from "<<d_start<<std::endl; s32 nearest_emerged_d = -1; s32 nearest_emergefull_d = -1; s32 nearest_sent_d = -1; //bool queue_is_full = false; f32 speed_in_blocks = (playerspeed/(MAP_BLOCKSIZE*BS)).getLength(); int blocks_occlusion_culled = 0; static const bool server_occlusion = g_settings->getBool("server_occlusion"); bool occlusion_culling_enabled = server_occlusion; auto cam_pos_nodes = floatToInt(playerpos, BS); auto nodemgr = env->getGameDef()->getNodeDefManager(); MapNode n; { #if !ENABLE_THREADS auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec(); #endif n = env->getMap().getNodeTry(cam_pos_nodes); } if(n && nodemgr->get(n).solidness == 2) occlusion_culling_enabled = false; unordered_map_v3POS<bool> occlude_cache; s16 d; for(d = d_start; d <= d_max; d++) { /*errorstream<<"checking d="<<d<<" for " <<server->getPlayerName(peer_id)<<std::endl;*/ //infostream<<"RemoteClient::SendBlocks(): d="<<d<<" d_start="<<d_start<<" d_max="<<d_max<<" d_max_gen="<<d_max_gen<<std::endl; std::vector<v3POS> list; if (d > 2 && d == d_start && m_nearest_unsent_reset_timer != 999) { // oops, again magic number from up ^ list.push_back(v3POS(0,0,0)); } bool can_skip = d > 1; // Fast fall/move optimize. speed_in_blocks now limited to 6.4 if (speed_in_blocks>0.8 && d <= 2) { can_skip = false; if (d == 0) { for(s16 addn = 0; addn < (speed_in_blocks+1)*2; ++addn) list.push_back(floatToInt(playerspeeddir*addn, 1)); } else if (d == 1) { for(s16 addn = 0; addn < (speed_in_blocks+1)*1.5; ++addn) { list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 0, 0, 1)); // back list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0, 0)); // left list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1, 0, 0)); // right list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 0, 0, -1)); // front } } else if (d == 2) { for(s16 addn = 0; addn < (speed_in_blocks+1)*1.5; ++addn) { list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0, 1)); // back left list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1, 0, 1)); // left right list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0, -1)); // right left list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1, 0, -1)); // front right } } } else { /* Get the border/face dot coordinates of a "d-radiused" box */ list = FacePositionCache::getFacePositions(d); } for(auto li=list.begin(); li!=list.end(); ++li) { v3POS p = *li + center; /* Send throttling - Don't allow too many simultaneous transfers - EXCEPT when the blocks are very close Also, don't send blocks that are already flying. */ // Start with the usual maximum u16 max_simul_dynamic = max_simul_sends_usually; // If block is very close, allow full maximum if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D) max_simul_dynamic = max_simul_sends_setting; // Don't select too many blocks for sending if (num_blocks_selected + num_blocks_sending >= max_simul_dynamic) { //queue_is_full = true; goto queue_full_break; } /* Do not go over-limit */ if (blockpos_over_limit(p)) continue; // If this is true, inexistent block will be made from scratch bool generate = d <= d_max_gen; { /*// Limit the generating area vertically to 2/3 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3) generate = false;*/ /* maybe good idea (if not use block culling) but brokes far (25+) area generate by flooding emergequeue with no generate blocks // Limit the send area vertically to 1/2 if(can_skip && abs(p.Y - center.Y) > full_d_max / 2) generate = false; */ } //infostream<<"d="<<d<<std::endl; /* Don't generate or send if not in sight FIXME This only works if the client uses a small enough FOV setting. The default of 72 degrees is fine. */ float camera_fov = ((fov+5)*M_PI/180) * 4./3.; if(can_skip && isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false) { continue; } /* Don't send already sent blocks */ unsigned int block_sent = 0; { auto lock = m_blocks_sent.lock_shared_rec(); block_sent = m_blocks_sent.find(p) != m_blocks_sent.end() ? m_blocks_sent.get(p) : 0; } if(block_sent > 0 && (/* (block_overflow && d>1) || */ block_sent + (d <= 2 ? 1 : d*d*d) > m_uptime)) { continue; } /* Check if map has this block */ MapBlock *block; { #if !ENABLE_THREADS auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec(); #endif block = env->getMap().getBlockNoCreateNoEx(p); } bool surely_not_found_on_disk = false; bool block_is_invalid = false; if(block != NULL) { if (d > 3 && block->content_only == CONTENT_AIR) { continue; } if (block_sent > 0 && block_sent >= block->m_changed_timestamp) { continue; } if (occlusion_culling_enabled) { ScopeProfiler sp(g_profiler, "SMap: Occusion calls"); //Occlusion culling auto cpn = p*MAP_BLOCKSIZE; // No occlusion culling when free_move is on and camera is // inside ground cpn += v3POS(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2); float step = 1; float stepfac = 1.3; float startoff = 5; float endoff = -MAP_BLOCKSIZE; v3POS spn = cam_pos_nodes + v3POS(0,0,0); s16 bs2 = MAP_BLOCKSIZE/2 + 1; u32 needed_count = 1; #if !ENABLE_THREADS auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec(); #endif //VERY BAD COPYPASTE FROM clientmap.cpp! if( d >= 1 && occlusion_culling_enabled && isOccluded(&env->getMap(), spn, cpn + v3POS(0,0,0), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,-bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,-bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,-bs2,bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) && isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,-bs2,-bs2), step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) ) { //infostream<<" occlusion player="<<cam_pos_nodes<<" d="<<d<<" block="<<cpn<<" total="<<blocks_occlusion_culled<<"/"<<num_blocks_selected<<std::endl; g_profiler->add("SMap: Occlusion skip", 1); blocks_occlusion_culled++; continue; } } // Reset usage timer, this block will be of use in the future. block->resetUsageTimer(); if (block->getLightingExpired()) { //env->getServerMap().lighting_modified_blocks.set(p, nullptr); env->getServerMap().lighting_modified_add(p, d); } if (block->lighting_broken > 0 && (block_sent || d > 0)) continue; // Block is valid if lighting is up-to-date and data exists if(block->isValid() == false) { block_is_invalid = true; } if(block->isGenerated() == false) { continue; } /* If block is not close, don't send it unless it is near ground level. Block is near ground level if night-time mesh differs from day-time mesh. */ /* if(d >= 4) { if(block->getDayNightDiff() == false) continue; } */ } /* If block has been marked to not exist on disk (dummy) and generating new ones is not wanted, skip block. */ if(generate == false && surely_not_found_on_disk == true) { // get next one. continue; } /* Add inexistent block to emerge queue. */ if(block == NULL || surely_not_found_on_disk || block_is_invalid) { //infostream<<"start gen d="<<d<<" p="<<p<<" notfound="<<surely_not_found_on_disk<<" invalid="<< block_is_invalid<<" block="<<block<<" generate="<<generate<<std::endl; if (emerge->enqueueBlockEmerge(peer_id, p, generate)) { if (nearest_emerged_d == -1) nearest_emerged_d = d; } else { if (nearest_emergefull_d == -1) nearest_emergefull_d = d; goto queue_full_break; } // get next one. continue; } if(nearest_sent_d == -1) nearest_sent_d = d; /* Add block to send queue */ PrioritySortedBlockTransfer q((float)d, p, peer_id); dest.push_back(q); num_blocks_selected += 1; } } queue_full_break: //infostream<<"Stopped at "<<d<<" d_start="<<d_start<< " d_max="<<d_max<<" nearest_emerged_d="<<nearest_emerged_d<<" nearest_emergefull_d="<<nearest_emergefull_d<< " new_nearest_unsent_d="<<new_nearest_unsent_d<< " sel="<<num_blocks_selected<< "+"<<num_blocks_sending << " culled=" << blocks_occlusion_culled <<" cEN="<<occlusion_culling_enabled<<std::endl; num_blocks_selected += num_blocks_sending; if(!num_blocks_selected && d_start <= d) { //new_nearest_unsent_d = 0; m_nothing_to_send_pause_timer = 1.0; } // If nothing was found for sending and nothing was queued for // emerging, continue next time browsing from here if(nearest_emerged_d != -1){ new_nearest_unsent_d = nearest_emerged_d; } else if(nearest_emergefull_d != -1){ new_nearest_unsent_d = nearest_emergefull_d; } else { if(d > full_d_max){ new_nearest_unsent_d = 0; m_nothing_to_send_pause_timer = 1.0; } else { if(nearest_sent_d != -1) new_nearest_unsent_d = nearest_sent_d; else new_nearest_unsent_d = d; } } if(new_nearest_unsent_d != -1) m_nearest_unsent_d = new_nearest_unsent_d; return num_blocks_selected - num_blocks_sending; }
void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, v2u32 screensize, f32 tool_reload_ratio, int current_camera_mode, ClientEnvironment &c_env) { // Get player position // Smooth the movement when walking up stairs v3f old_player_position = m_playernode->getPosition(); v3f player_position = player->getPosition(); if (player->isAttached && player->parent) player_position = player->parent->getPosition(); //if(player->touching_ground && player_position.Y > old_player_position.Y) if(player->touching_ground && player_position.Y > old_player_position.Y) { f32 oldy = old_player_position.Y; f32 newy = player_position.Y; f32 t = exp(-23*frametime); player_position.Y = oldy * t + newy * (1-t); } // Set player node transformation m_playernode->setPosition(player_position); m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0)); m_playernode->updateAbsolutePosition(); // Get camera tilt timer (hurt animation) float cameratilt = fabs(fabs(player->hurt_tilt_timer-0.75)-0.75); // Fall bobbing animation float fall_bobbing = 0; if(player->camera_impact >= 1 && current_camera_mode < CAMERA_MODE_THIRD) { if(m_view_bobbing_fall == -1) // Effect took place and has finished player->camera_impact = m_view_bobbing_fall = 0; else if(m_view_bobbing_fall == 0) // Initialize effect m_view_bobbing_fall = 1; // Convert 0 -> 1 to 0 -> 1 -> 0 fall_bobbing = m_view_bobbing_fall < 0.5 ? m_view_bobbing_fall * 2 : -(m_view_bobbing_fall - 0.5) * 2 + 1; // Smoothen and invert the above fall_bobbing = sin(fall_bobbing * 0.5 * M_PI) * -1; // Amplify according to the intensity of the impact fall_bobbing *= (1 - rangelim(50 / player->camera_impact, 0, 1)) * 5; fall_bobbing *= g_settings->getFloat("fall_bobbing_amount"); } // Calculate players eye offset for different camera modes v3f PlayerEyeOffset = player->getEyeOffset(); if (current_camera_mode == CAMERA_MODE_FIRST) PlayerEyeOffset += player->eye_offset_first; else PlayerEyeOffset += player->eye_offset_third; // Set head node transformation m_headnode->setPosition(PlayerEyeOffset+v3f(0,cameratilt*-player->hurt_tilt_strength+fall_bobbing,0)); m_headnode->setRotation(v3f(player->getPitch(), 0, cameratilt*player->hurt_tilt_strength)); m_headnode->updateAbsolutePosition(); // Compute relative camera position and target v3f rel_cam_pos = v3f(0,0,0); v3f rel_cam_target = v3f(0,0,1); v3f rel_cam_up = v3f(0,1,0); if (m_view_bobbing_anim != 0 && current_camera_mode < CAMERA_MODE_THIRD) { f32 bobfrac = my_modf(m_view_bobbing_anim * 2); f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0; #if 1 f32 bobknob = 1.2; f32 bobtmp = sin(pow(bobfrac, bobknob) * M_PI); //f32 bobtmp2 = cos(pow(bobfrac, bobknob) * M_PI); v3f bobvec = v3f( 0.3 * bobdir * sin(bobfrac * M_PI), -0.28 * bobtmp * bobtmp, 0.); //rel_cam_pos += 0.2 * bobvec; //rel_cam_target += 0.03 * bobvec; //rel_cam_up.rotateXYBy(0.02 * bobdir * bobtmp * M_PI); float f = 1.0; f *= g_settings->getFloat("view_bobbing_amount"); rel_cam_pos += bobvec * f; //rel_cam_target += 0.995 * bobvec * f; rel_cam_target += bobvec * f; rel_cam_target.Z -= 0.005 * bobvec.Z * f; //rel_cam_target.X -= 0.005 * bobvec.X * f; //rel_cam_target.Y -= 0.005 * bobvec.Y * f; rel_cam_up.rotateXYBy(-0.03 * bobdir * bobtmp * M_PI * f); #else f32 angle_deg = 1 * bobdir * sin(bobfrac * M_PI); f32 angle_rad = angle_deg * M_PI / 180; f32 r = 0.05; v3f off = v3f( r * sin(angle_rad), r * (cos(angle_rad) - 1), 0); rel_cam_pos += off; //rel_cam_target += off; rel_cam_up.rotateXYBy(angle_deg); #endif } // Compute absolute camera position and target m_headnode->getAbsoluteTransformation().transformVect(m_camera_position, rel_cam_pos); m_headnode->getAbsoluteTransformation().rotateVect(m_camera_direction, rel_cam_target - rel_cam_pos); v3f abs_cam_up; m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up); // Seperate camera position for calculation v3f my_cp = m_camera_position; // Reposition the camera for third person view if (current_camera_mode > CAMERA_MODE_FIRST) { if (current_camera_mode == CAMERA_MODE_THIRD_FRONT) m_camera_direction *= -1; my_cp.Y += 2; // Calculate new position bool abort = false; for (int i = BS; i <= BS*2; i++) { my_cp.X = m_camera_position.X + m_camera_direction.X*-i; my_cp.Z = m_camera_position.Z + m_camera_direction.Z*-i; if (i > 12) my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i); // Prevent camera positioned inside nodes INodeDefManager *nodemgr = m_gamedef->ndef(); MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS)); const ContentFeatures& features = nodemgr->get(n); if(features.walkable) { my_cp.X += m_camera_direction.X*-1*-BS/2; my_cp.Z += m_camera_direction.Z*-1*-BS/2; my_cp.Y += m_camera_direction.Y*-1*-BS/2; abort = true; break; } } // If node blocks camera position don't move y to heigh if (abort && my_cp.Y > player_position.Y+BS*2) my_cp.Y = player_position.Y+BS*2; } // Update offset if too far away from the center of the map m_camera_offset.X += CAMERA_OFFSET_STEP* (((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP); m_camera_offset.Y += CAMERA_OFFSET_STEP* (((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP); m_camera_offset.Z += CAMERA_OFFSET_STEP* (((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP); // Set camera node transformation m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS)); m_cameranode->setUpVector(abs_cam_up); // *100.0 helps in large map coordinates m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction); // update the camera position in front-view mode to render blocks behind player if (current_camera_mode == CAMERA_MODE_THIRD_FRONT) m_camera_position = my_cp; // Get FOV setting f32 fov_degrees = g_settings->getFloat("fov"); fov_degrees = MYMAX(fov_degrees, 10.0); fov_degrees = MYMIN(fov_degrees, 170.0); // FOV and aspect ratio m_aspect = (f32)screensize.X / (f32) screensize.Y; m_fov_y = fov_degrees * M_PI / 180.0; // Increase vertical FOV on lower aspect ratios (<16:10) m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect))); m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y)); m_cameranode->setAspectRatio(m_aspect); m_cameranode->setFOV(m_fov_y); // Position the wielded item //v3f wield_position = v3f(45, -35, 65); v3f wield_position = v3f(55, -35, 65); //v3f wield_rotation = v3f(-100, 120, -100); v3f wield_rotation = v3f(-100, 120, -100); if(m_wield_change_timer < 0) wield_position.Y -= 40 + m_wield_change_timer*320; else wield_position.Y -= 40 - m_wield_change_timer*320; if(m_digging_anim < 0.05 || m_digging_anim > 0.5){ f32 frac = 1.0; if(m_digging_anim > 0.5) frac = 2.0 * (m_digging_anim - 0.5); // This value starts from 1 and settles to 0 f32 ratiothing = pow((1.0f - tool_reload_ratio), 0.5f); //f32 ratiothing2 = pow(ratiothing, 0.5f); f32 ratiothing2 = (easeCurve(ratiothing*0.5))*2.0; wield_position.Y -= frac * 25.0 * pow(ratiothing2, 1.7f); //wield_position.Z += frac * 5.0 * ratiothing2; wield_position.X -= frac * 35.0 * pow(ratiothing2, 1.1f); wield_rotation.Y += frac * 70.0 * pow(ratiothing2, 1.4f); //wield_rotation.X -= frac * 15.0 * pow(ratiothing2, 1.4f); //wield_rotation.Z += frac * 15.0 * pow(ratiothing2, 1.0f); } if (m_digging_button != -1) { f32 digfrac = m_digging_anim; wield_position.X -= 50 * sin(pow(digfrac, 0.8f) * M_PI); wield_position.Y += 24 * sin(digfrac * 1.8 * M_PI); wield_position.Z += 25 * 0.5; // Euler angles are PURE EVIL, so why not use quaternions? core::quaternion quat_begin(wield_rotation * core::DEGTORAD); core::quaternion quat_end(v3f(80, 30, 100) * core::DEGTORAD); core::quaternion quat_slerp; quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * M_PI)); quat_slerp.toEuler(wield_rotation); wield_rotation *= core::RADTODEG; } else { f32 bobfrac = my_modf(m_view_bobbing_anim); wield_position.X -= sin(bobfrac*M_PI*2.0) * 3.0; wield_position.Y += sin(my_modf(bobfrac*2.0)*M_PI) * 3.0; } m_wieldnode->setPosition(wield_position); m_wieldnode->setRotation(wield_rotation); m_wieldlight = player->light; // Render distance feedback loop updateViewingRange(frametime, busytime); // If the player seems to be walking on solid ground, // view bobbing is enabled and free_move is off, // start (or continue) the view bobbing animation. v3f speed = player->getSpeed(); if ((hypot(speed.X, speed.Z) > BS) && (player->touching_ground) && (g_settings->getBool("view_bobbing") == true) && (g_settings->getBool("free_move") == false || !m_gamedef->checkLocalPrivilege("fly"))) { // Start animation m_view_bobbing_state = 1; m_view_bobbing_speed = MYMIN(speed.getLength(), 40); } else if (m_view_bobbing_state == 1) { // Stop animation m_view_bobbing_state = 2; m_view_bobbing_speed = 60; } }
// add_particle({pos=, velocity=, acceleration=, expirationtime=, // size=, collisiondetection=, collision_removal=, object_collision=, // vertical=, texture=, player=}) // pos/velocity/acceleration = {x=num, y=num, z=num} // expirationtime = num (seconds) // size = num // collisiondetection = bool // collision_removal = bool // object_collision = bool // vertical = bool // texture = e.g."default_wood.png" // animation = TileAnimation definition // glow = num int ModApiParticles::l_add_particle(lua_State *L) { MAP_LOCK_REQUIRED; // Get parameters v3f pos, vel, acc; float expirationtime, size; expirationtime = size = 1; bool collisiondetection, vertical, collision_removal, object_collision; collisiondetection = vertical = collision_removal = object_collision = false; struct TileAnimationParams animation; animation.type = TAT_NONE; std::string texture; std::string playername; u8 glow = 0; if (lua_gettop(L) > 1) // deprecated { log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition"); pos = check_v3f(L, 1); vel = check_v3f(L, 2); acc = check_v3f(L, 3); expirationtime = luaL_checknumber(L, 4); size = luaL_checknumber(L, 5); collisiondetection = readParam<bool>(L, 6); texture = luaL_checkstring(L, 7); if (lua_gettop(L) == 8) // only spawn for a single player playername = luaL_checkstring(L, 8); } else if (lua_istable(L, 1)) { lua_getfield(L, 1, "pos"); pos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(); lua_pop(L, 1); lua_getfield(L, 1, "vel"); if (lua_istable(L, -1)) { vel = check_v3f(L, -1); log_deprecated(L, "The use of vel is deprecated. " "Use velocity instead"); } lua_pop(L, 1); lua_getfield(L, 1, "velocity"); vel = lua_istable(L, -1) ? check_v3f(L, -1) : vel; lua_pop(L, 1); lua_getfield(L, 1, "acc"); if (lua_istable(L, -1)) { acc = check_v3f(L, -1); log_deprecated(L, "The use of acc is deprecated. " "Use acceleration instead"); } lua_pop(L, 1); lua_getfield(L, 1, "acceleration"); acc = lua_istable(L, -1) ? check_v3f(L, -1) : acc; lua_pop(L, 1); expirationtime = getfloatfield_default(L, 1, "expirationtime", 1); size = getfloatfield_default(L, 1, "size", 1); collisiondetection = getboolfield_default(L, 1, "collisiondetection", collisiondetection); collision_removal = getboolfield_default(L, 1, "collision_removal", collision_removal); object_collision = getboolfield_default(L, 1, "object_collision", object_collision); vertical = getboolfield_default(L, 1, "vertical", vertical); lua_getfield(L, 1, "animation"); animation = read_animation_definition(L, -1); lua_pop(L, 1); texture = getstringfield_default(L, 1, "texture", ""); playername = getstringfield_default(L, 1, "playername", ""); glow = getintfield_default(L, 1, "glow", 0); } getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size, collisiondetection, collision_removal, object_collision, vertical, texture, animation, glow); return 1; }
// hud_add(self, form) int ObjectRef::l_hud_add(lua_State *L) { NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); if (player == NULL) return 0; HudElement *elem = new HudElement; elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", es_HudElementType, HUD_ELEM_TEXT); lua_getfield(L, 2, "position"); elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "scale"); elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "size"); elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32(); lua_pop(L, 1); elem->name = getstringfield_default(L, 2, "name", ""); elem->text = getstringfield_default(L, 2, "text", ""); elem->number = getintfield_default(L, 2, "number", 0); elem->item = getintfield_default(L, 2, "item", 0); elem->dir = getintfield_default(L, 2, "direction", 0); // Deprecated, only for compatibility's sake if (elem->dir == 0) elem->dir = getintfield_default(L, 2, "dir", 0); lua_getfield(L, 2, "alignment"); elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "offset"); elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); lua_pop(L, 1); lua_getfield(L, 2, "world_pos"); elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f(); lua_pop(L, 1); /* check for known deprecated element usage */ if ((elem->type == HUD_ELEM_STATBAR) && (elem->size == v2s32())) { log_deprecated(L,"Deprecated usage of statbar without size!"); } u32 id = getServer(L)->hudAdd(player, elem); if (id == U32_MAX) { delete elem; return 0; } lua_pushnumber(L, id); return 1; }
static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3, v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest) { FastFace face; // Position is at the center of the cube. v3f pos = p * BS; float x0 = 0.0; float y0 = 0.0; float w = 1.0; float h = 1.0; v3f vertex_pos[4]; v3s16 vertex_dirs[4]; getNodeVertexDirs(dir, vertex_dirs); v3s16 t; u16 t1; switch (tile.rotation) { case 0: break; case 1: //R90 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[3]; vertex_dirs[3] = vertex_dirs[2]; vertex_dirs[2] = vertex_dirs[1]; vertex_dirs[1] = t; t1=li0; li0=li3; li3=li2; li2=li1; li1=t1; break; case 2: //R180 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[2]; vertex_dirs[2] = t; t = vertex_dirs[1]; vertex_dirs[1] = vertex_dirs[3]; vertex_dirs[3] = t; t1 = li0; li0 = li2; li2 = t1; t1 = li1; li1 = li3; li3 = t1; break; case 3: //R270 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[1]; vertex_dirs[1] = vertex_dirs[2]; vertex_dirs[2] = vertex_dirs[3]; vertex_dirs[3] = t; t1 = li0; li0 = li1; li1 = li2; li2 = li3; li3 = t1; break; case 4: //FXR90 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[3]; vertex_dirs[3] = vertex_dirs[2]; vertex_dirs[2] = vertex_dirs[1]; vertex_dirs[1] = t; t1 = li0; li0 = li3; li3 = li2; li2 = li1; li1 = t1; y0 += h; h *= -1; break; case 5: //FXR270 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[1]; vertex_dirs[1] = vertex_dirs[2]; vertex_dirs[2] = vertex_dirs[3]; vertex_dirs[3] = t; t1 = li0; li0 = li1; li1 = li2; li2 = li3; li3 = t1; y0 += h; h *= -1; break; case 6: //FYR90 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[3]; vertex_dirs[3] = vertex_dirs[2]; vertex_dirs[2] = vertex_dirs[1]; vertex_dirs[1] = t; t1 = li0; li0 = li3; li3 = li2; li2 = li1; li1 = t1; x0 += w; w *= -1; break; case 7: //FYR270 t = vertex_dirs[0]; vertex_dirs[0] = vertex_dirs[1]; vertex_dirs[1] = vertex_dirs[2]; vertex_dirs[2] = vertex_dirs[3]; vertex_dirs[3] = t; t1 = li0; li0 = li1; li1 = li2; li2 = li3; li3 = t1; x0 += w; w *= -1; break; case 8: //FX y0 += h; h *= -1; break; case 9: //FY x0 += w; w *= -1; break; default: break; } for(u16 i=0; i<4; i++) { vertex_pos[i] = v3f( BS/2*vertex_dirs[i].X, BS/2*vertex_dirs[i].Y, BS/2*vertex_dirs[i].Z ); } for(u16 i=0; i<4; i++) { vertex_pos[i].X *= scale.X; vertex_pos[i].Y *= scale.Y; vertex_pos[i].Z *= scale.Z; vertex_pos[i] += pos; } f32 abs_scale = 1.0; if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X; else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y; else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z; v3f normal(dir.X, dir.Y, dir.Z); u8 alpha = tile.alpha; face.vertices[0] = video::S3DVertex(vertex_pos[0], normal, MapBlock_LightColor(alpha, li0, light_source), core::vector2d<f32>(x0+w*abs_scale, y0+h)); face.vertices[1] = video::S3DVertex(vertex_pos[1], normal, MapBlock_LightColor(alpha, li1, light_source), core::vector2d<f32>(x0, y0+h)); face.vertices[2] = video::S3DVertex(vertex_pos[2], normal, MapBlock_LightColor(alpha, li2, light_source), core::vector2d<f32>(x0, y0)); face.vertices[3] = video::S3DVertex(vertex_pos[3], normal, MapBlock_LightColor(alpha, li3, light_source), core::vector2d<f32>(x0+w*abs_scale, y0)); face.tile = tile; dest.push_back(face); }
MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): clearHardwareBuffer(false), step(data->step), timestamp(data->timestamp), m_mesh(new scene::SMesh()), m_gamedef(data->m_gamedef), m_animation_force_timer(0), // force initial animation m_last_crack(-1), m_crack_materials(), m_highlighted_materials(), m_last_daynight_ratio((u32) -1), m_daynight_diffs(), m_usage_timer(0) { m_enable_shaders = g_settings->getBool("enable_shaders"); m_enable_highlighting = g_settings->getBool("enable_node_highlighting"); // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated) // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated) //TimeTaker timer1("MapBlockMesh()"); data->fill_data(); std::vector<FastFace> fastfaces_new; /* We are including the faces of the trailing edges of the block. This means that when something changes, the caller must also update the meshes of the blocks at the leading edges. NOTE: This is the slowest part of this method. */ { // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated) //TimeTaker timer2("updateAllFastFaceRows()"); updateAllFastFaceRows(data, fastfaces_new, step); } // End of slow part //if (data->debug) infostream<<" step="<<step<<" fastfaces_new.size="<<fastfaces_new.size()<<std::endl; /* Convert FastFaces to MeshCollector */ MeshCollector collector; { // avg 0ms (100ms spikes when loading textures the first time) // (NOTE: probably outdated) //TimeTaker timer2("MeshCollector building"); for(u32 i=0; i<fastfaces_new.size(); i++) { FastFace &f = fastfaces_new[i]; const u16 indices[] = {0,1,2,2,3,0}; const u16 indices_alternate[] = {0,1,3,2,3,1}; if(f.tile.texture == NULL) continue; const u16 *indices_p = indices; /* Revert triangles for nicer looking gradient if vertices 1 and 3 have same color or 0 and 2 have different color. getRed() is the day color. */ if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed() || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed()) indices_p = indices_alternate; collector.append(f.tile, f.vertices, 4, indices_p, 6); } } /* Add special graphics: - torches - flowing water - fences - whatever */ if(step <= 1) mapblock_mesh_generate_special(data, collector); m_highlight_mesh_color = data->m_highlight_mesh_color; /* Convert MeshCollector to SMesh */ ITextureSource *tsrc = m_gamedef->tsrc(); IShaderSource *shdrsrc = m_gamedef->getShaderSource(); for(u32 i = 0; i < collector.prebuffers.size(); i++) { PreMeshBuffer &p = collector.prebuffers[i]; if (step <= data->draw_control.farmesh || !data->draw_control.farmesh) { // Generate animation data // - Cracks if(p.tile.material_flags & MATERIAL_FLAG_CRACK) { // Find the texture name plus ^[crack:N: std::ostringstream os(std::ios::binary); os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack"; if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY) os<<"o"; // use ^[cracko os<<":"<<(u32)p.tile.animation_frame_count<<":"; m_crack_materials.insert(std::make_pair(i, os.str())); // Replace tile texture with the cracked one p.tile.texture = tsrc->getTexture( os.str()+"0", &p.tile.texture_id); } // - Texture animation if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) { // Add to MapBlockMesh in order to animate these tiles m_animation_tiles[i] = p.tile; m_animation_frames[i] = 0; if(g_settings->getBool("desynchronize_mapblock_texture_animation")){ // Get starting position from noise m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d( data->m_blockpos.X, data->m_blockpos.Y, data->m_blockpos.Z, 0)); } else { // Play all synchronized m_animation_frame_offsets[i] = 0; } // Replace tile texture with the first animation frame FrameSpec animation_frame = p.tile.frames.find(0)->second; p.tile.texture = animation_frame.texture; } } if(m_enable_highlighting && p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) m_highlighted_materials.push_back(i); for(u32 j = 0; j < p.vertices.size(); j++) { // Note applyFacesShading second parameter is precalculated sqrt // value for speed improvement // Skip it for lightsources and top faces. video::SColor &vc = p.vertices[j].Color; if (!vc.getBlue()) { if (p.vertices[j].Normal.Y < -0.5) { applyFacesShading (vc, 0.447213); } else if (p.vertices[j].Normal.X > 0.5) { applyFacesShading (vc, 0.670820); } else if (p.vertices[j].Normal.X < -0.5) { applyFacesShading (vc, 0.670820); } else if (p.vertices[j].Normal.Z > 0.5) { applyFacesShading (vc, 0.836660); } else if (p.vertices[j].Normal.Z < -0.5) { applyFacesShading (vc, 0.836660); } } if(!m_enable_shaders) { // - Classic lighting (shaders handle this by themselves) // Set initial real color and store for later updates u8 day = vc.getRed(); u8 night = vc.getGreen(); finalColorBlend(vc, day, night, 1000); if(day != night) m_daynight_diffs[i][j] = std::make_pair(day, night); } } // Create material video::SMaterial material; material.setFlag(video::EMF_LIGHTING, false); material.setFlag(video::EMF_BACK_FACE_CULLING, true); material.setFlag(video::EMF_BILINEAR_FILTER, false); material.setFlag(video::EMF_FOG_ENABLE, true); //material.setFlag(video::EMF_WIREFRAME, true); material.setTexture(0, p.tile.texture); if (p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) { material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; } else { if (m_enable_shaders) { material.MaterialType = shdrsrc->getShaderInfo(p.tile.shader_id).material; p.tile.applyMaterialOptionsWithShaders(material); if (p.tile.normal_texture) { material.setTexture(1, p.tile.normal_texture); material.setTexture(2, tsrc->getTexture("enable_img.png")); } else { material.setTexture(2, tsrc->getTexture("disable_img.png")); } } else { p.tile.applyMaterialOptions(material); } } // Create meshbuffer // This is a "Standard MeshBuffer", // it's a typedeffed CMeshBuffer<video::S3DVertex> scene::SMeshBuffer *buf = new scene::SMeshBuffer(); // Set material buf->Material = material; // Add to mesh m_mesh->addMeshBuffer(buf); // Mesh grabbed it buf->drop(); buf->append(&p.vertices[0], p.vertices.size(), &p.indices[0], p.indices.size()); } m_camera_offset = camera_offset; /* Do some stuff to the mesh */ v3f t = v3f(0,0,0); if (step>1) { scaleMesh(m_mesh, v3f(step,step,step)); // TODO: remove this wrong numbers, find formula good test: fly above ocean if (step == 2) t = v3f(BS/2, BS/2, BS/2); if (step == 4) t = v3f(BS*1.666, -BS/3.0, BS*1.666); if (step == 8) t = v3f(BS*2.666, -BS*2.4, BS*2.666); if (step == 16) t = v3f(BS*6.4, -BS*6.4, BS*6.4); } translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS) + t); if(m_mesh) { #if 0 // Usually 1-700 faces and 1-7 materials infostream<<"Updated MapBlock mesh p="<<data->m_blockpos<<" has "<<fastfaces_new.size()<<" faces " <<"and uses "<<m_mesh->getMeshBufferCount() <<" materials "<<" step="<<step<<" range="<<data->range<< " mesh="<<m_mesh<<std::endl; #endif } //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl; // Check if animation is required for this mesh m_has_animation = !m_crack_materials.empty() || !m_daynight_diffs.empty() || !m_animation_tiles.empty() || !m_highlighted_materials.empty(); }
void MapgenV6::makeChunk(BlockMakeData *data) { // Pre-conditions assert(data->vmanip); assert(data->nodedef); assert(data->blockpos_requested.X >= data->blockpos_min.X && data->blockpos_requested.Y >= data->blockpos_min.Y && data->blockpos_requested.Z >= data->blockpos_min.Z); assert(data->blockpos_requested.X <= data->blockpos_max.X && data->blockpos_requested.Y <= data->blockpos_max.Y && data->blockpos_requested.Z <= data->blockpos_max.Z); this->generating = true; this->vm = data->vmanip; this->ndef = data->nodedef; // Hack: use minimum block coords for old code that assumes a single block v3s16 blockpos_min = data->blockpos_min; v3s16 blockpos_max = data->blockpos_max; // Area of central chunk node_min = blockpos_min * MAP_BLOCKSIZE; node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1); // Full allocated area full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE; full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1); central_area_size = node_max - node_min + v3s16(1, 1, 1); assert(central_area_size.X == central_area_size.Z); int volume_blocks = (blockpos_max.X - blockpos_min.X + 1) * (blockpos_max.Y - blockpos_min.Y + 1) * (blockpos_max.Z - blockpos_max.Z + 1); volume_nodes = volume_blocks * MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; // Create a block-specific seed blockseed = get_blockseed(data->seed, full_node_min); // Make some noise calculateNoise(); // Maximum height of the stone surface and obstacles. // This is used to guide the cave generation s16 stone_surface_max_y; // Generate general ground level to full area stone_surface_max_y = generateGround(); // Create initial heightmap to limit caves updateHeightmap(node_min, node_max); const s16 max_spread_amount = MAP_BLOCKSIZE; // Limit dirt flow area by 1 because mud is flown into neighbors. s16 mudflow_minpos = -max_spread_amount + 1; s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2; // Loop this part, it will make stuff look older and newer nicely const u32 age_loops = 2; for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop // Make caves (this code is relatively horrible) if (flags & MG_CAVES) generateCaves(stone_surface_max_y); // Add mud to the central chunk addMud(); // Flow mud away from steep edges if (spflags & MGV6_MUDFLOW) flowMud(mudflow_minpos, mudflow_maxpos); } // Update heightmap after mudflow updateHeightmap(node_min, node_max); // Add dungeons if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) { DungeonParams dp; dp.seed = seed; dp.c_water = c_water_source; dp.c_river_water = c_water_source; dp.only_in_ground = true; dp.corridor_len_min = 1; dp.corridor_len_max = 13; dp.rooms_min = 2; dp.rooms_max = 16; dp.y_min = -MAX_MAP_GENERATION_LIMIT; dp.y_max = MAX_MAP_GENERATION_LIMIT; dp.np_density = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0); dp.np_alt_wall = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0); if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) { dp.c_wall = c_desert_stone; dp.c_alt_wall = CONTENT_IGNORE; dp.c_stair = c_stair_desert_stone; dp.diagonal_dirs = true; dp.holesize = v3s16(2, 3, 2); dp.room_size_min = v3s16(6, 9, 6); dp.room_size_max = v3s16(10, 11, 10); dp.room_size_large_min = v3s16(10, 13, 10); dp.room_size_large_max = v3s16(18, 21, 18); dp.notifytype = GENNOTIFY_TEMPLE; } else { dp.c_wall = c_cobble; dp.c_alt_wall = c_mossycobble; dp.c_stair = c_stair_cobble; dp.diagonal_dirs = false; dp.holesize = v3s16(1, 2, 1); dp.room_size_min = v3s16(4, 4, 4); dp.room_size_max = v3s16(8, 6, 8); dp.room_size_large_min = v3s16(8, 8, 8); dp.room_size_large_max = v3s16(16, 16, 16); dp.notifytype = GENNOTIFY_DUNGEON; } DungeonGen dgen(ndef, &gennotify, &dp); dgen.generate(vm, blockseed, full_node_min, full_node_max); } // Add top and bottom side of water to transforming_liquid queue updateLiquid(&data->transforming_liquid, full_node_min, full_node_max); // Add surface nodes growGrass(); // Generate some trees, and add grass, if a jungle if (spflags & MGV6_TREES) placeTreesAndJungleGrass(); // Generate the registered decorations if (flags & MG_DECORATIONS) m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max); // Generate the registered ores m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max); // Calculate lighting if (flags & MG_LIGHT) calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE, node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE, full_node_min, full_node_max); this->generating = false; }
bool generate_image(std::string part_of_name, video::IImage *& baseimg, IrrlichtDevice *device, SourceImageCache *sourcecache) { video::IVideoDriver* driver = device->getVideoDriver(); assert(driver); // Stuff starting with [ are special commands if(part_of_name.size() == 0 || part_of_name[0] != '[') { video::IImage *image = sourcecache->getOrLoad(part_of_name, device); if(image == NULL) { if(part_of_name != ""){ errorstream<<"generate_image(): Could not load image \"" <<part_of_name<<"\""<<" while building texture"<<std::endl; errorstream<<"generate_image(): Creating a dummy" <<" image for \""<<part_of_name<<"\""<<std::endl; } // Just create a dummy image //core::dimension2d<u32> dim(2,2); core::dimension2d<u32> dim(1,1); image = driver->createImage(video::ECF_A8R8G8B8, dim); assert(image); /*image->setPixel(0,0, video::SColor(255,255,0,0)); image->setPixel(1,0, video::SColor(255,0,255,0)); image->setPixel(0,1, video::SColor(255,0,0,255)); image->setPixel(1,1, video::SColor(255,255,0,255));*/ image->setPixel(0,0, video::SColor(255,myrand()%256, myrand()%256,myrand()%256)); /*image->setPixel(1,0, video::SColor(255,myrand()%256, myrand()%256,myrand()%256)); image->setPixel(0,1, video::SColor(255,myrand()%256, myrand()%256,myrand()%256)); image->setPixel(1,1, video::SColor(255,myrand()%256, myrand()%256,myrand()%256));*/ } // If base image is NULL, load as base. if(baseimg == NULL) { //infostream<<"Setting "<<part_of_name<<" as base"<<std::endl; /* Copy it this way to get an alpha channel. Otherwise images with alpha cannot be blitted on images that don't have alpha in the original file. */ core::dimension2d<u32> dim = image->getDimension(); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); image->copyTo(baseimg); image->drop(); } // Else blit on base. else { //infostream<<"Blitting "<<part_of_name<<" on base"<<std::endl; // Size of the copied area core::dimension2d<u32> dim = image->getDimension(); //core::dimension2d<u32> dim(16,16); // Position to copy the blitted to in the base image core::position2d<s32> pos_to(0,0); // Position to copy the blitted from in the blitted image core::position2d<s32> pos_from(0,0); // Blit image->copyToWithAlpha(baseimg, pos_to, core::rect<s32>(pos_from, dim), video::SColor(255,255,255,255), NULL); // Drop image image->drop(); } } else { // A special texture modification /*infostream<<"generate_image(): generating special " <<"modification \""<<part_of_name<<"\"" <<std::endl;*/ /* This is the simplest of all; it just adds stuff to the name so that a separate texture is created. It is used to make textures for stuff that doesn't want to implement getting the texture from a bigger texture atlas. */ if(part_of_name == "[forcesingle") { // If base image is NULL, create a random color if(baseimg == NULL) { core::dimension2d<u32> dim(1,1); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); assert(baseimg); baseimg->setPixel(0,0, video::SColor(255,myrand()%256, myrand()%256,myrand()%256)); } } /* [crackN Adds a cracking texture */ else if(part_of_name.substr(0,6) == "[crack") { if(baseimg == NULL) { errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } // Crack image number and overlay option s32 progression = 0; bool use_overlay = false; if(part_of_name.substr(6,1) == "o") { progression = stoi(part_of_name.substr(7)); use_overlay = true; } else { progression = stoi(part_of_name.substr(6)); use_overlay = false; } // Size of the base image core::dimension2d<u32> dim_base = baseimg->getDimension(); /* Load crack image. It is an image with a number of cracking stages horizontally tiled. */ video::IImage *img_crack = sourcecache->getOrLoad( "crack_anylength.png", device); if(img_crack && progression >= 0) { // Dimension of original image core::dimension2d<u32> dim_crack = img_crack->getDimension(); // Count of crack stages s32 crack_count = dim_crack.Height / dim_crack.Width; // Limit progression if(progression > crack_count-1) progression = crack_count-1; // Dimension of a single crack stage core::dimension2d<u32> dim_crack_cropped( dim_crack.Width, dim_crack.Width ); // Create cropped and scaled crack images video::IImage *img_crack_cropped = driver->createImage( video::ECF_A8R8G8B8, dim_crack_cropped); video::IImage *img_crack_scaled = driver->createImage( video::ECF_A8R8G8B8, dim_base); if(img_crack_cropped && img_crack_scaled) { // Crop crack image v2s32 pos_crack(0, progression*dim_crack.Width); img_crack->copyTo(img_crack_cropped, v2s32(0,0), core::rect<s32>(pos_crack, dim_crack_cropped)); // Scale crack image by copying img_crack_cropped->copyToScaling(img_crack_scaled); // Copy or overlay crack image if(use_overlay) { overlay(baseimg, img_crack_scaled); } else { /*img_crack_scaled->copyToWithAlpha( baseimg, v2s32(0,0), core::rect<s32>(v2s32(0,0), dim_base), video::SColor(255,255,255,255));*/ blit_with_alpha(img_crack_scaled, baseimg, v2s32(0,0), v2s32(0,0), dim_base); } } if(img_crack_scaled) img_crack_scaled->drop(); if(img_crack_cropped) img_crack_cropped->drop(); img_crack->drop(); } } /* [combine:WxH:X,Y=filename:X,Y=filename2 Creates a bigger texture from an amount of smaller ones */ else if(part_of_name.substr(0,8) == "[combine") { Strfnd sf(part_of_name); sf.next(":"); u32 w0 = stoi(sf.next("x")); u32 h0 = stoi(sf.next(":")); infostream<<"combined w="<<w0<<" h="<<h0<<std::endl; core::dimension2d<u32> dim(w0,h0); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); while(sf.atend() == false) { u32 x = stoi(sf.next(",")); u32 y = stoi(sf.next("=")); std::string filename = sf.next(":"); infostream<<"Adding \""<<filename <<"\" to combined ("<<x<<","<<y<<")" <<std::endl; video::IImage *img = sourcecache->getOrLoad(filename, device); if(img) { core::dimension2d<u32> dim = img->getDimension(); infostream<<"Size "<<dim.Width <<"x"<<dim.Height<<std::endl; core::position2d<s32> pos_base(x, y); video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, dim); img->copyTo(img2); img->drop(); img2->copyToWithAlpha(baseimg, pos_base, core::rect<s32>(v2s32(0,0), dim), video::SColor(255,255,255,255), NULL); img2->drop(); } else { infostream<<"img==NULL"<<std::endl; } } } /* "[brighten" */ else if(part_of_name.substr(0,9) == "[brighten") { if(baseimg == NULL) { errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } brighten(baseimg); } /* "[noalpha" Make image completely opaque. Used for the leaves texture when in old leaves mode, so that the transparent parts don't look completely black when simple alpha channel is used for rendering. */ else if(part_of_name.substr(0,8) == "[noalpha") { if(baseimg == NULL) { errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } core::dimension2d<u32> dim = baseimg->getDimension(); // Set alpha to full for(u32 y=0; y<dim.Height; y++) for(u32 x=0; x<dim.Width; x++) { video::SColor c = baseimg->getPixel(x,y); c.setAlpha(255); baseimg->setPixel(x,y,c); } } /* "[makealpha:R,G,B" Convert one color to transparent. */ else if(part_of_name.substr(0,11) == "[makealpha:") { if(baseimg == NULL) { errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } Strfnd sf(part_of_name.substr(11)); u32 r1 = stoi(sf.next(",")); u32 g1 = stoi(sf.next(",")); u32 b1 = stoi(sf.next("")); std::string filename = sf.next(""); core::dimension2d<u32> dim = baseimg->getDimension(); /*video::IImage *oldbaseimg = baseimg; baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); oldbaseimg->copyTo(baseimg); oldbaseimg->drop();*/ // Set alpha to full for(u32 y=0; y<dim.Height; y++) for(u32 x=0; x<dim.Width; x++) { video::SColor c = baseimg->getPixel(x,y); u32 r = c.getRed(); u32 g = c.getGreen(); u32 b = c.getBlue(); if(!(r == r1 && g == g1 && b == b1)) continue; c.setAlpha(0); baseimg->setPixel(x,y,c); } } /* "[transformN" Rotates and/or flips the image. N can be a number (between 0 and 7) or a transform name. Rotations are counter-clockwise. 0 I identity 1 R90 rotate by 90 degrees 2 R180 rotate by 180 degrees 3 R270 rotate by 270 degrees 4 FX flip X 5 FXR90 flip X then rotate by 90 degrees 6 FY flip Y 7 FYR90 flip Y then rotate by 90 degrees Note: Transform names can be concatenated to produce their product (applies the first then the second). The resulting transform will be equivalent to one of the eight existing ones, though (see: dihedral group). */ else if(part_of_name.substr(0,10) == "[transform") { if(baseimg == NULL) { errorstream<<"generate_image(): baseimg==NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } u32 transform = parseImageTransform(part_of_name.substr(10)); core::dimension2d<u32> dim = imageTransformDimension( transform, baseimg->getDimension()); video::IImage *image = driver->createImage( baseimg->getColorFormat(), dim); assert(image); imageTransform(transform, baseimg, image); baseimg->drop(); baseimg = image; } /* [inventorycube{topimage{leftimage{rightimage In every subimage, replace ^ with &. Create an "inventory cube". NOTE: This should be used only on its own. Example (a grass block (not actually used in game): "[inventorycube{grass.png{mud.png&grass_side.png{mud.png&grass_side.png" */ else if(part_of_name.substr(0,14) == "[inventorycube") { if(baseimg != NULL) { errorstream<<"generate_image(): baseimg!=NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } str_replace_char(part_of_name, '&', '^'); Strfnd sf(part_of_name); sf.next("{"); std::string imagename_top = sf.next("{"); std::string imagename_left = sf.next("{"); std::string imagename_right = sf.next("{"); // Generate images for the faces of the cube video::IImage *img_top = generate_image_from_scratch( imagename_top, device, sourcecache); video::IImage *img_left = generate_image_from_scratch( imagename_left, device, sourcecache); video::IImage *img_right = generate_image_from_scratch( imagename_right, device, sourcecache); assert(img_top && img_left && img_right); // Create textures from images video::ITexture *texture_top = driver->addTexture( (imagename_top + "__temp__").c_str(), img_top); video::ITexture *texture_left = driver->addTexture( (imagename_left + "__temp__").c_str(), img_left); video::ITexture *texture_right = driver->addTexture( (imagename_right + "__temp__").c_str(), img_right); assert(texture_top && texture_left && texture_right); // Drop images img_top->drop(); img_left->drop(); img_right->drop(); /* Draw a cube mesh into a render target texture */ scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1)); setMeshColor(cube, video::SColor(255, 255, 255, 255)); cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top); cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top); cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right); cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right); cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left); cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left); core::dimension2d<u32> dim(64,64); std::string rtt_texture_name = part_of_name + "_RTT"; v3f camera_position(0, 1.0, -1.5); camera_position.rotateXZBy(45); v3f camera_lookat(0, 0, 0); core::CMatrix4<f32> camera_projection_matrix; // Set orthogonal projection camera_projection_matrix.buildProjectionMatrixOrthoLH( 1.65, 1.65, 0, 100); video::SColorf ambient_light(0.2,0.2,0.2); v3f light_position(10, 100, -50); video::SColorf light_color(0.5,0.5,0.5); f32 light_radius = 1000; video::ITexture *rtt = generateTextureFromMesh( cube, device, dim, rtt_texture_name, camera_position, camera_lookat, camera_projection_matrix, ambient_light, light_position, light_color, light_radius); // Drop mesh cube->drop(); // Free textures of images driver->removeTexture(texture_top); driver->removeTexture(texture_left); driver->removeTexture(texture_right); if(rtt == NULL) { baseimg = generate_image_from_scratch( imagename_top, device, sourcecache); return true; } // Create image of render target video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim); assert(image); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); if(image) { image->copyTo(baseimg); image->drop(); } } /* [lowpart:percent:filename Adds the lower part of a texture */ else if(part_of_name.substr(0,9) == "[lowpart:") { Strfnd sf(part_of_name); sf.next(":"); u32 percent = stoi(sf.next(":")); std::string filename = sf.next(":"); //infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl; if(baseimg == NULL) baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16)); video::IImage *img = sourcecache->getOrLoad(filename, device); if(img) { core::dimension2d<u32> dim = img->getDimension(); core::position2d<s32> pos_base(0, 0); video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, dim); img->copyTo(img2); img->drop(); core::position2d<s32> clippos(0, 0); clippos.Y = dim.Height * (100-percent) / 100; core::dimension2d<u32> clipdim = dim; clipdim.Height = clipdim.Height * percent / 100 + 1; core::rect<s32> cliprect(clippos, clipdim); img2->copyToWithAlpha(baseimg, pos_base, core::rect<s32>(v2s32(0,0), dim), video::SColor(255,255,255,255), &cliprect); img2->drop(); } } /* [verticalframe:N:I Crops a frame of a vertical animation. N = frame count, I = frame index */ else if(part_of_name.substr(0,15) == "[verticalframe:") { Strfnd sf(part_of_name); sf.next(":"); u32 frame_count = stoi(sf.next(":")); u32 frame_index = stoi(sf.next(":")); if(baseimg == NULL){ errorstream<<"generate_image(): baseimg!=NULL " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } v2u32 frame_size = baseimg->getDimension(); frame_size.Y /= frame_count; video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, frame_size); if(!img){ errorstream<<"generate_image(): Could not create image " <<"for part_of_name=\""<<part_of_name <<"\", cancelling."<<std::endl; return false; } // Fill target image with transparency img->fill(video::SColor(0,0,0,0)); core::dimension2d<u32> dim = frame_size; core::position2d<s32> pos_dst(0, 0); core::position2d<s32> pos_src(0, frame_index * frame_size.Y); baseimg->copyToWithAlpha(img, pos_dst, core::rect<s32>(pos_src, dim), video::SColor(255,255,255,255), NULL); // Replace baseimg baseimg->drop(); baseimg = img; } else { errorstream<<"generate_image(): Invalid " " modification: \""<<part_of_name<<"\""<<std::endl; } } return true; }
void RemoteClient::GetNextBlocks( ServerEnvironment *env, EmergeManager * emerge, float dtime, std::vector<PrioritySortedBlockTransfer> &dest) { DSTACK(__FUNCTION_NAME); // Increment timers m_nothing_to_send_pause_timer -= dtime; m_nearest_unsent_reset_timer += dtime; if(m_nothing_to_send_pause_timer >= 0) return; Player *player = env->getPlayer(peer_id); // This can happen sometimes; clients and players are not in perfect sync. if(player == NULL) return; // Won't send anything if already sending if(m_blocks_sending.size() >= g_settings->getU16 ("max_simultaneous_block_sends_per_client")) { //infostream<<"Not sending any blocks, Queue full."<<std::endl; return; } v3f playerpos = player->getPosition(); v3f playerspeed = player->getSpeed(); v3f playerspeeddir(0,0,0); if(playerspeed.getLength() > 1.0*BS) playerspeeddir = playerspeed / playerspeed.getLength(); // Predict to next block v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS; v3s16 center_nodepos = floatToInt(playerpos_predicted, BS); v3s16 center = getNodeBlockPos(center_nodepos); // Camera position and direction v3f camera_pos = player->getEyePosition(); v3f camera_dir = v3f(0,0,1); camera_dir.rotateYZBy(player->getPitch()); camera_dir.rotateXZBy(player->getYaw()); /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<"," <<camera_dir.Z<<")"<<std::endl;*/ /* Get the starting value of the block finder radius. */ if(m_last_center != center) { m_nearest_unsent_d = 0; m_last_center = center; } /*infostream<<"m_nearest_unsent_reset_timer=" <<m_nearest_unsent_reset_timer<<std::endl;*/ // Reset periodically to workaround for some bugs or stuff if(m_nearest_unsent_reset_timer > 20.0) { m_nearest_unsent_reset_timer = 0; m_nearest_unsent_d = 0; //infostream<<"Resetting m_nearest_unsent_d for " // <<server->getPlayerName(peer_id)<<std::endl; } //s16 last_nearest_unsent_d = m_nearest_unsent_d; s16 d_start = m_nearest_unsent_d; //infostream<<"d_start="<<d_start<<std::endl; u16 max_simul_sends_setting = g_settings->getU16 ("max_simultaneous_block_sends_per_client"); u16 max_simul_sends_usually = max_simul_sends_setting; /* Check the time from last addNode/removeNode. Decrease send rate if player is building stuff. */ m_time_from_building += dtime; if(m_time_from_building < g_settings->getFloat( "full_block_send_enable_min_time_from_building")) { max_simul_sends_usually = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; } /* Number of blocks sending + number of blocks selected for sending */ u32 num_blocks_selected = m_blocks_sending.size(); /* next time d will be continued from the d from which the nearest unsent block was found this time. This is because not necessarily any of the blocks found this time are actually sent. */ s32 new_nearest_unsent_d = -1; const s16 full_d_max = g_settings->getS16("max_block_send_distance"); s16 d_max = full_d_max; s16 d_max_gen = g_settings->getS16("max_block_generate_distance"); // Don't loop very much at a time s16 max_d_increment_at_time = 2; if(d_max > d_start + max_d_increment_at_time) d_max = d_start + max_d_increment_at_time; s32 nearest_emerged_d = -1; s32 nearest_emergefull_d = -1; s32 nearest_sent_d = -1; bool queue_is_full = false; s16 d; for(d = d_start; d <= d_max; d++) { /* Get the border/face dot coordinates of a "d-radiused" box */ std::list<v3s16> list; getFacePositions(list, d); std::list<v3s16>::iterator li; for(li=list.begin(); li!=list.end(); ++li) { v3s16 p = *li + center; /* Send throttling - Don't allow too many simultaneous transfers - EXCEPT when the blocks are very close Also, don't send blocks that are already flying. */ // Start with the usual maximum u16 max_simul_dynamic = max_simul_sends_usually; // If block is very close, allow full maximum if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D) max_simul_dynamic = max_simul_sends_setting; // Don't select too many blocks for sending if(num_blocks_selected >= max_simul_dynamic) { queue_is_full = true; goto queue_full_break; } // Don't send blocks that are currently being transferred if(m_blocks_sending.find(p) != m_blocks_sending.end()) continue; /* Do not go over-limit */ if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) continue; // If this is true, inexistent block will be made from scratch bool generate = d <= d_max_gen; { /*// Limit the generating area vertically to 2/3 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3) generate = false;*/ // Limit the send area vertically to 1/2 if(abs(p.Y - center.Y) > full_d_max / 2) continue; } /* Don't generate or send if not in sight FIXME This only works if the client uses a small enough FOV setting. The default of 72 degrees is fine. */ float camera_fov = (72.0*M_PI/180) * 4./3.; if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false) { continue; } /* Don't send already sent blocks */ { if(m_blocks_sent.find(p) != m_blocks_sent.end()) { continue; } } /* Check if map has this block */ MapBlock *block = env->getMap().getBlockNoCreateNoEx(p); bool surely_not_found_on_disk = false; bool block_is_invalid = false; if(block != NULL) { // Reset usage timer, this block will be of use in the future. block->resetUsageTimer(); // Block is dummy if data doesn't exist. // It means it has been not found from disk and not generated if(block->isDummy()) { surely_not_found_on_disk = true; } // Block is valid if lighting is up-to-date and data exists if(block->isValid() == false) { block_is_invalid = true; } if(block->isGenerated() == false) block_is_invalid = true; /* If block is not close, don't send it unless it is near ground level. Block is near ground level if night-time mesh differs from day-time mesh. */ if(d >= 4) { if(block->getDayNightDiff() == false) continue; } } /* If block has been marked to not exist on disk (dummy) and generating new ones is not wanted, skip block. */ if(generate == false && surely_not_found_on_disk == true) { // get next one. continue; } /* Add inexistent block to emerge queue. */ if(block == NULL || surely_not_found_on_disk || block_is_invalid) { if (emerge->enqueueBlockEmerge(peer_id, p, generate)) { if (nearest_emerged_d == -1) nearest_emerged_d = d; } else { if (nearest_emergefull_d == -1) nearest_emergefull_d = d; goto queue_full_break; } // get next one. continue; } if(nearest_sent_d == -1) nearest_sent_d = d; /* Add block to send queue */ PrioritySortedBlockTransfer q((float)d, p, peer_id); dest.push_back(q); num_blocks_selected += 1; } } queue_full_break: // If nothing was found for sending and nothing was queued for // emerging, continue next time browsing from here if(nearest_emerged_d != -1){ new_nearest_unsent_d = nearest_emerged_d; } else if(nearest_emergefull_d != -1){ new_nearest_unsent_d = nearest_emergefull_d; } else { if(d > g_settings->getS16("max_block_send_distance")){ new_nearest_unsent_d = 0; m_nothing_to_send_pause_timer = 2.0; } else { if(nearest_sent_d != -1) new_nearest_unsent_d = nearest_sent_d; else new_nearest_unsent_d = d; } } if(new_nearest_unsent_d != -1) m_nearest_unsent_d = new_nearest_unsent_d; }
collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, f32 pos_max_d, const aabb3f &box_0, f32 stepheight, f32 dtime, v3f &pos_f, v3f &speed_f, v3f &accel_f,ActiveObject* self, bool collideWithObjects) { static bool time_notification_done = false; Map *map = &env->getMap(); //TimeTaker tt("collisionMoveSimple"); ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG); collisionMoveResult result; /* Calculate new velocity */ if (dtime > 0.5) { if (!time_notification_done) { time_notification_done = true; infostream << "collisionMoveSimple: maximum step interval exceeded," " lost movement details!"<<std::endl; } dtime = 0.5; } else { time_notification_done = false; } speed_f += accel_f * dtime; // If there is no speed, there are no collisions if(speed_f.getLength() == 0) return result; // Limit speed for avoiding hangs speed_f.Y=rangelim(speed_f.Y,-5000,5000); speed_f.X=rangelim(speed_f.X,-5000,5000); speed_f.Z=rangelim(speed_f.Z,-5000,5000); /* Collect node boxes in movement range */ std::vector<aabb3f> cboxes; std::vector<bool> is_unloaded; std::vector<bool> is_step_up; std::vector<bool> is_object; std::vector<int> bouncy_values; std::vector<v3s16> node_positions; { //TimeTaker tt2("collisionMoveSimple collect boxes"); ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG); v3s16 oldpos_i = floatToInt(pos_f, BS); v3s16 newpos_i = floatToInt(pos_f + speed_f * dtime, BS); s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1; s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1; s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1; s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1; s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1; s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1; bool any_position_valid = false; for(s16 x = min_x; x <= max_x; x++) for(s16 y = min_y; y <= max_y; y++) for(s16 z = min_z; z <= max_z; z++) { v3s16 p(x,y,z); bool is_position_valid; MapNode n = map->getNodeNoEx(p, &is_position_valid); if (is_position_valid) { // Object collides into walkable nodes any_position_valid = true; const ContentFeatures &f = gamedef->getNodeDefManager()->get(n); if(f.walkable == false) continue; int n_bouncy_value = itemgroup_get(f.groups, "bouncy"); std::vector<aabb3f> nodeboxes = n.getCollisionBoxes(gamedef->ndef()); for(std::vector<aabb3f>::iterator i = nodeboxes.begin(); i != nodeboxes.end(); ++i) { aabb3f box = *i; box.MinEdge += v3f(x, y, z)*BS; box.MaxEdge += v3f(x, y, z)*BS; cboxes.push_back(box); is_unloaded.push_back(false); is_step_up.push_back(false); bouncy_values.push_back(n_bouncy_value); node_positions.push_back(p); is_object.push_back(false); } } else { // Collide with unloaded nodes aabb3f box = getNodeBox(p, BS); cboxes.push_back(box); is_unloaded.push_back(true); is_step_up.push_back(false); bouncy_values.push_back(0); node_positions.push_back(p); is_object.push_back(false); } } // Do not move if world has not loaded yet, since custom node boxes // are not available for collision detection. if (!any_position_valid) return result; } // tt2 if(collideWithObjects) { ScopeProfiler sp(g_profiler, "collisionMoveSimple objects avg", SPT_AVG); //TimeTaker tt3("collisionMoveSimple collect object boxes"); /* add object boxes to cboxes */ std::vector<ActiveObject*> objects; #ifndef SERVER ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env); if (c_env != 0) { f32 distance = speed_f.getLength(); std::vector<DistanceSortedActiveObject> clientobjects; c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects); for (size_t i=0; i < clientobjects.size(); i++) { if ((self == 0) || (self != clientobjects[i].obj)) { objects.push_back((ActiveObject*)clientobjects[i].obj); } } } else #endif { ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env); if (s_env != 0) { f32 distance = speed_f.getLength(); std::vector<u16> s_objects; s_env->getObjectsInsideRadius(s_objects, pos_f, distance * 1.5); for (std::vector<u16>::iterator iter = s_objects.begin(); iter != s_objects.end(); ++iter) { ServerActiveObject *current = s_env->getActiveObject(*iter); if ((self == 0) || (self != current)) { objects.push_back((ActiveObject*)current); } } } } for (std::vector<ActiveObject*>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) { ActiveObject *object = *iter; if (object != NULL) { aabb3f object_collisionbox; if (object->getCollisionBox(&object_collisionbox) && object->collideWithObjects()) { cboxes.push_back(object_collisionbox); is_unloaded.push_back(false); is_step_up.push_back(false); bouncy_values.push_back(0); node_positions.push_back(v3s16(0,0,0)); is_object.push_back(true); } } } } //tt3 assert(cboxes.size() == is_unloaded.size()); // post-condition assert(cboxes.size() == is_step_up.size()); // post-condition assert(cboxes.size() == bouncy_values.size()); // post-condition assert(cboxes.size() == node_positions.size()); // post-condition assert(cboxes.size() == is_object.size()); // post-condition /* Collision detection */ /* Collision uncertainty radius Make it a bit larger than the maximum distance of movement */ f32 d = pos_max_d * 1.1; // A fairly large value in here makes moving smoother //f32 d = 0.15*BS; // This should always apply, otherwise there are glitches assert(d > pos_max_d); // invariant int loopcount = 0; while(dtime > BS * 1e-10) { //TimeTaker tt3("collisionMoveSimple dtime loop"); ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG); // Avoid infinite loop loopcount++; if (loopcount >= 100) { warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl; dtime = 0; break; } aabb3f movingbox = box_0; movingbox.MinEdge += pos_f; movingbox.MaxEdge += pos_f; int nearest_collided = -1; f32 nearest_dtime = dtime; u32 nearest_boxindex = -1; /* Go through every nodebox, find nearest collision */ for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) { // Ignore if already stepped up this nodebox. if(is_step_up[boxindex]) continue; // Find nearest collision of the two boxes (raytracing-like) f32 dtime_tmp; int collided = axisAlignedCollision( cboxes[boxindex], movingbox, speed_f, d, dtime_tmp); if (collided == -1 || dtime_tmp >= nearest_dtime) continue; nearest_dtime = dtime_tmp; nearest_collided = collided; nearest_boxindex = boxindex; } if (nearest_collided == -1) { // No collision with any collision box. pos_f += speed_f * dtime; dtime = 0; // Set to 0 to avoid "infinite" loop due to small FP numbers } else { // Otherwise, a collision occurred. const aabb3f& cbox = cboxes[nearest_boxindex]; // Check for stairs. bool step_up = (nearest_collided != 1) && // must not be Y direction (movingbox.MinEdge.Y < cbox.MaxEdge.Y) && (movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) && (!wouldCollideWithCeiling(cboxes, movingbox, cbox.MaxEdge.Y - movingbox.MinEdge.Y, d)); // Get bounce multiplier bool bouncy = (bouncy_values[nearest_boxindex] >= 1); float bounce = -(float)bouncy_values[nearest_boxindex] / 100.0; // Move to the point of collision and reduce dtime by nearest_dtime if (nearest_dtime < 0) { // Handle negative nearest_dtime (can be caused by the d allowance) if (!step_up) { if (nearest_collided == 0) pos_f.X += speed_f.X * nearest_dtime; if (nearest_collided == 1) pos_f.Y += speed_f.Y * nearest_dtime; if (nearest_collided == 2) pos_f.Z += speed_f.Z * nearest_dtime; } } else { pos_f += speed_f * nearest_dtime; dtime -= nearest_dtime; } bool is_collision = true; if (is_unloaded[nearest_boxindex]) is_collision = false; CollisionInfo info; if (is_object[nearest_boxindex]) info.type = COLLISION_OBJECT; else info.type = COLLISION_NODE; info.node_p = node_positions[nearest_boxindex]; info.bouncy = bouncy; info.old_speed = speed_f; // Set the speed component that caused the collision to zero if (step_up) { // Special case: Handle stairs is_step_up[nearest_boxindex] = true; is_collision = false; } else if(nearest_collided == 0) { // X if (fabs(speed_f.X) > BS * 3) speed_f.X *= bounce; else speed_f.X = 0; result.collides = true; result.collides_xz = true; } else if(nearest_collided == 1) { // Y if(fabs(speed_f.Y) > BS * 3) speed_f.Y *= bounce; else speed_f.Y = 0; result.collides = true; } else if(nearest_collided == 2) { // Z if (fabs(speed_f.Z) > BS * 3) speed_f.Z *= bounce; else speed_f.Z = 0; result.collides = true; result.collides_xz = true; } info.new_speed = speed_f; if (info.new_speed.getDistanceFrom(info.old_speed) < 0.1 * BS) is_collision = false; if (is_collision) { result.collisions.push_back(info); } } } /* Final touches: Check if standing on ground, step up stairs. */ aabb3f box = box_0; box.MinEdge += pos_f; box.MaxEdge += pos_f; for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) { const aabb3f& cbox = cboxes[boxindex]; /* See if the object is touching ground. Object touches ground if object's minimum Y is near node's maximum Y and object's X-Z-area overlaps with the node's X-Z-area. Use 0.15*BS so that it is easier to get on a node. */ if (cbox.MaxEdge.X - d > box.MinEdge.X && cbox.MinEdge.X + d < box.MaxEdge.X && cbox.MaxEdge.Z - d > box.MinEdge.Z && cbox.MinEdge.Z + d < box.MaxEdge.Z) { if (is_step_up[boxindex]) { pos_f.Y += (cbox.MaxEdge.Y - box.MinEdge.Y); box = box_0; box.MinEdge += pos_f; box.MaxEdge += pos_f; } if (fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.15 * BS) { result.touching_ground = true; if (is_object[boxindex]) result.standing_on_object = true; if (is_unloaded[boxindex]) result.standing_on_unloaded = true; } } } return result; }
void CNodeDefManager::updateTextures(IGameDef *gamedef, void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress), void *progress_callback_args) { infostream << "CNodeDefManager::updateTextures(): Updating " "textures in node definitions" << std::endl; bool server = !progress_callback; ITextureSource *tsrc = !gamedef ? nullptr : gamedef->tsrc(); IShaderSource *shdsrc = !gamedef ? nullptr : gamedef->getShaderSource(); scene::ISceneManager* smgr = !gamedef ? nullptr : gamedef->getSceneManager(); scene::IMeshManipulator* meshmanip = !smgr ? nullptr : smgr->getMeshManipulator(); bool new_style_water = g_settings->getBool("new_style_water"); bool connected_glass = g_settings->getBool("connected_glass"); bool opaque_water = g_settings->getBool("opaque_water"); bool enable_shaders = g_settings->getBool("enable_shaders"); bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping"); bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion"); bool enable_mesh_cache = g_settings->getBool("enable_mesh_cache"); bool enable_minimap = g_settings->getBool("enable_minimap"); std::string leaves_style = g_settings->get("leaves_style"); bool use_normal_texture = enable_shaders && (enable_bumpmapping || enable_parallax_occlusion); u32 size = m_content_features.size(); for (u32 i = 0; i < size; i++) { ContentFeatures *f = &m_content_features[i]; #ifndef SERVER // minimap pixel color - the average color of a texture if (tsrc) if (enable_minimap && f->tiledef[0].name != "") f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name); #endif // Figure out the actual tiles to use TileDef tiledef[6]; for (u32 j = 0; j < 6; j++) { tiledef[j] = f->tiledef[j]; if (tiledef[j].name == "") tiledef[j].name = "unknown_node.png"; } bool is_liquid = false; bool is_water_surface = false; u8 material_type = (f->alpha == 255) ? TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; switch (f->drawtype) { default: case NDT_NORMAL: f->solidness = 2; break; case NDT_AIRLIKE: f->solidness = 0; break; case NDT_LIQUID: assert(f->liquid_type == LIQUID_SOURCE); if (opaque_water) f->alpha = 255; if (new_style_water){ f->solidness = 0; } else { f->solidness = 1; f->backface_culling = false; } is_liquid = true; break; case NDT_FLOWINGLIQUID: assert(f->liquid_type == LIQUID_FLOWING); f->solidness = 0; if (opaque_water) f->alpha = 255; is_liquid = true; break; case NDT_GLASSLIKE: f->solidness = 0; f->visual_solidness = 1; break; case NDT_GLASSLIKE_FRAMED: f->solidness = 0; f->visual_solidness = 1; break; case NDT_GLASSLIKE_FRAMED_OPTIONAL: f->solidness = 0; f->visual_solidness = 1; if (!server) f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE; break; case NDT_ALLFACES: f->solidness = 0; f->visual_solidness = 1; break; case NDT_ALLFACES_OPTIONAL: if (leaves_style == "fancy") { if (!server) f->drawtype = NDT_ALLFACES; f->solidness = 0; f->visual_solidness = 1; } else if (leaves_style == "simple") { for (u32 j = 0; j < 6; j++) { if (f->tiledef_special[j].name != "") tiledef[j].name = f->tiledef_special[j].name; } if (!server) f->drawtype = NDT_GLASSLIKE; f->solidness = 0; f->visual_solidness = 1; } else { if (!server) f->drawtype = NDT_NORMAL; f->solidness = 2; for (u32 i = 0; i < 6; i++) tiledef[i].name += std::string("^[noalpha"); } if (f->waving == 1) material_type = TILE_MATERIAL_WAVING_LEAVES; break; case NDT_PLANTLIKE: f->solidness = 0; f->backface_culling = false; if (f->waving == 1) material_type = TILE_MATERIAL_WAVING_PLANTS; break; case NDT_FIRELIKE: f->backface_culling = false; f->solidness = 0; break; case NDT_MESH: f->solidness = 0; f->backface_culling = false; break; case NDT_TORCHLIKE: case NDT_SIGNLIKE: case NDT_FENCELIKE: case NDT_RAILLIKE: case NDT_NODEBOX: f->solidness = 0; break; } #ifndef SERVER if (is_liquid) { material_type = (f->alpha == 255) ? TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT; if (f->name == "default:water_source") is_water_surface = true; } u32 tile_shader[6]; if (shdsrc) { for (u16 j = 0; j < 6; j++) { tile_shader[j] = shdsrc->getShader("nodes_shader", material_type, f->drawtype); } if (is_water_surface) { tile_shader[0] = shdsrc->getShader("water_surface_shader", material_type, f->drawtype); } } if (tsrc) { // Tiles (fill in f->tiles[]) for (u16 j = 0; j < 6; j++) { fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j], use_normal_texture, f->backface_culling, f->alpha, material_type); } // Special tiles (fill in f->special_tiles[]) for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) { fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j], tile_shader[j], use_normal_texture, f->tiledef_special[j].backface_culling, f->alpha, material_type); } if ((f->drawtype == NDT_MESH) && (f->mesh != "")) { // Meshnode drawtype // Read the mesh and apply scale f->mesh_ptr[0] = gamedef->getMesh(f->mesh); if (f->mesh_ptr[0]){ v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale; scaleMesh(f->mesh_ptr[0], scale); recalculateBoundingBox(f->mesh_ptr[0]); meshmanip->recalculateNormals(f->mesh_ptr[0], true, false); } } else if ((f->drawtype == NDT_NODEBOX) && ((f->node_box.type == NODEBOX_REGULAR) || (f->node_box.type == NODEBOX_FIXED)) && (!f->node_box.fixed.empty())) { //Convert regular nodebox nodes to meshnodes //Change the drawtype and apply scale if (!server) f->drawtype = NDT_MESH; f->mesh_ptr[0] = convertNodeboxNodeToMesh(f); v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale; scaleMesh(f->mesh_ptr[0], scale); recalculateBoundingBox(f->mesh_ptr[0]); meshmanip->recalculateNormals(f->mesh_ptr[0], true, false); } //Cache 6dfacedir and wallmounted rotated clones of meshes if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) { for (u16 j = 1; j < 24; j++) { f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]); rotateMeshBy6dFacedir(f->mesh_ptr[j], j); recalculateBoundingBox(f->mesh_ptr[j]); meshmanip->recalculateNormals(f->mesh_ptr[j], true, false); } } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) { static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2}; for (u16 j = 1; j < 6; j++) { f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]); rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]); recalculateBoundingBox(f->mesh_ptr[j]); meshmanip->recalculateNormals(f->mesh_ptr[j], true, false); } rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]); recalculateBoundingBox(f->mesh_ptr[0]); meshmanip->recalculateNormals(f->mesh_ptr[0], true, false); } } if (progress_callback) progress_callback(progress_callback_args, i, size); #endif } }
bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args) { init_args(game_params, cmd_args); // List video modes if requested if (list_video_modes) return print_video_modes(); if (!init_engine(game_params.log_level)) { errorstream << "Could not initialize game engine." << std::endl; return false; } // Create time getter g_timegetter = new IrrlichtTimeGetter(device); // Speed tests (done after irrlicht is loaded to get timer) if (cmd_args.getFlag("speedtests")) { dstream << "Running speed tests" << std::endl; speed_tests(); return true; } video::IVideoDriver *video_driver = device->getVideoDriver(); if (video_driver == NULL) { errorstream << "Could not initialize video driver." << std::endl; return false; } porting::setXorgClassHint(video_driver->getExposedVideoData(), PROJECT_NAME_C); /* This changes the minimum allowed number of vertices in a VBO. Default is 500. */ //driver->setMinHardwareBufferVertexCount(50); // Create game callback for menus g_gamecallback = new MainGameCallback(device); device->setResizable(true); if (random_input) input = new RandomInputHandler(); else input = new RealInputHandler(device, receiver); smgr = device->getSceneManager(); smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); guienv = device->getGUIEnvironment(); skin = guienv->getSkin(); skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255)); skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0)); skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30)); skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0)); skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 120, 50)); skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255)); g_fontengine = new FontEngine(g_settings, guienv); FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed."); #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2 // Irrlicht 1.8 input colours skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128)); skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49)); #endif // Create the menu clouds if (!g_menucloudsmgr) g_menucloudsmgr = smgr->createNewSceneManager(); if (!g_menuclouds) g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(), g_menucloudsmgr, -1, rand(), 100); g_menuclouds->update(v2f(0, 0), video::SColor(255, 200, 200, 255)); scene::ICameraSceneNode* camera; camera = g_menucloudsmgr->addCameraSceneNode(0, v3f(0, 0, 0), v3f(0, 60, 100)); camera->setFarValue(10000); /* GUI stuff */ ChatBackend chat_backend; // If an error occurs, this is set to something by menu(). // It is then displayed before the menu shows on the next call to menu() std::string error_message; bool first_loop = true; /* Menu-game loop */ bool retval = true; bool *kill = porting::signal_handler_killstatus(); while (device->run() && !*kill && !g_gamecallback->shutdown_requested) { // Set the window caption const wchar_t *text = wgettext("Main Menu"); device->setWindowCaption((narrow_to_wide(PROJECT_NAME_C) + L" [" + text + L"]").c_str()); delete[] text; try { // This is used for catching disconnects guienv->clear(); /* We need some kind of a root node to be able to add custom gui elements directly on the screen. Otherwise they won't be automatically drawn. */ guiroot = guienv->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000)); bool game_has_run = launch_game(error_message, game_params, cmd_args); // If skip_main_menu, we only want to startup once if (skip_main_menu && !first_loop) break; first_loop = false; if (!game_has_run) { if (skip_main_menu) break; else continue; } // Break out of menu-game loop to shut down cleanly if (!device->run() || *kill) { if (g_settings_path != "") g_settings->updateConfigFile(g_settings_path.c_str()); break; } if (current_playername.length() > PLAYERNAME_SIZE-1) { error_message = gettext("Player name too long."); playername = current_playername.substr(0, PLAYERNAME_SIZE-1); g_settings->set("name", playername); continue; } device->getVideoDriver()->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map")); #ifdef HAVE_TOUCHSCREENGUI receiver->m_touchscreengui = new TouchScreenGUI(device, receiver); g_touchscreengui = receiver->m_touchscreengui; #endif the_game( kill, random_input, input, device, worldspec.path, current_playername, current_password, current_address, current_port, error_message, chat_backend, gamespec, simple_singleplayer_mode ); smgr->clear(); #ifdef HAVE_TOUCHSCREENGUI delete g_touchscreengui; g_touchscreengui = NULL; receiver->m_touchscreengui = NULL; #endif } //try catch (con::PeerNotFoundException &e) { error_message = gettext("Connection error (timed out?)"); errorstream << error_message << std::endl; } #ifdef NDEBUG catch (std::exception &e) { std::string error_message = "Some exception: \""; error_message += e.what(); error_message += "\""; errorstream << error_message << std::endl; } #endif // If no main menu, show error and exit if (skip_main_menu) { if (!error_message.empty()) { verbosestream << "error_message = " << error_message << std::endl; retval = false; } break; } } // Menu-game loop g_menuclouds->drop(); g_menucloudsmgr->drop(); return retval; }
void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc, scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip, IGameDef *gamedef, const TextureSettings &tsettings) { // minimap pixel color - the average color of a texture if (tsettings.enable_minimap && tiledef[0].name != "") minimap_color = tsrc->getTextureAverageColor(tiledef[0].name); // Figure out the actual tiles to use TileDef tdef[6]; for (u32 j = 0; j < 6; j++) { tdef[j] = tiledef[j]; if (tdef[j].name == "") tdef[j].name = "unknown_node.png"; } bool is_liquid = false; bool is_water_surface = false; u8 material_type = (alpha == 255) ? TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; switch (drawtype) { default: case NDT_NORMAL: solidness = 2; break; case NDT_AIRLIKE: solidness = 0; break; case NDT_LIQUID: assert(liquid_type == LIQUID_SOURCE); if (tsettings.opaque_water) alpha = 255; solidness = 1; is_liquid = true; break; case NDT_FLOWINGLIQUID: assert(liquid_type == LIQUID_FLOWING); solidness = 0; if (tsettings.opaque_water) alpha = 255; is_liquid = true; break; case NDT_GLASSLIKE: solidness = 0; visual_solidness = 1; break; case NDT_GLASSLIKE_FRAMED: solidness = 0; visual_solidness = 1; break; case NDT_GLASSLIKE_FRAMED_OPTIONAL: solidness = 0; visual_solidness = 1; drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE; break; case NDT_ALLFACES: solidness = 0; visual_solidness = 1; break; case NDT_ALLFACES_OPTIONAL: if (tsettings.leaves_style == LEAVES_FANCY) { drawtype = NDT_ALLFACES; solidness = 0; visual_solidness = 1; } else if (tsettings.leaves_style == LEAVES_SIMPLE) { for (u32 j = 0; j < 6; j++) { if (tiledef_special[j].name != "") tdef[j].name = tiledef_special[j].name; } drawtype = NDT_GLASSLIKE; solidness = 0; visual_solidness = 1; } else { drawtype = NDT_NORMAL; solidness = 2; for (u32 i = 0; i < 6; i++) tdef[i].name += std::string("^[noalpha"); } if (waving == 1) material_type = TILE_MATERIAL_WAVING_LEAVES; break; case NDT_PLANTLIKE: solidness = 0; if (waving == 1) material_type = TILE_MATERIAL_WAVING_PLANTS; break; case NDT_FIRELIKE: solidness = 0; break; case NDT_MESH: solidness = 0; break; case NDT_TORCHLIKE: case NDT_SIGNLIKE: case NDT_FENCELIKE: case NDT_RAILLIKE: case NDT_NODEBOX: solidness = 0; break; } if (is_liquid) { material_type = (alpha == 255) ? TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT; if (name == "default:water_source") is_water_surface = true; } u32 tile_shader[6]; for (u16 j = 0; j < 6; j++) { tile_shader[j] = shdsrc->getShader("nodes_shader", material_type, drawtype); } if (is_water_surface) { tile_shader[0] = shdsrc->getShader("water_surface_shader", material_type, drawtype); } // Tiles (fill in f->tiles[]) for (u16 j = 0; j < 6; j++) { fillTileAttribs(tsrc, &tiles[j], &tdef[j], tile_shader[j], tsettings.use_normal_texture, tiledef[j].backface_culling, alpha, material_type); } // Special tiles (fill in f->special_tiles[]) for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) { fillTileAttribs(tsrc, &special_tiles[j], &tiledef_special[j], tile_shader[j], tsettings.use_normal_texture, tiledef_special[j].backface_culling, alpha, material_type); } if ((drawtype == NDT_MESH) && (mesh != "")) { // Meshnode drawtype // Read the mesh and apply scale mesh_ptr[0] = gamedef->getMesh(mesh); if (mesh_ptr[0]){ v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale; scaleMesh(mesh_ptr[0], scale); recalculateBoundingBox(mesh_ptr[0]); meshmanip->recalculateNormals(mesh_ptr[0], true, false); } } else if ((drawtype == NDT_NODEBOX) && ((node_box.type == NODEBOX_REGULAR) || (node_box.type == NODEBOX_FIXED)) && (!node_box.fixed.empty())) { //Convert regular nodebox nodes to meshnodes //Change the drawtype and apply scale drawtype = NDT_MESH; mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed); v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale; scaleMesh(mesh_ptr[0], scale); recalculateBoundingBox(mesh_ptr[0]); meshmanip->recalculateNormals(mesh_ptr[0], true, false); } //Cache 6dfacedir and wallmounted rotated clones of meshes if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_FACEDIR)) { for (u16 j = 1; j < 24; j++) { mesh_ptr[j] = cloneMesh(mesh_ptr[0]); rotateMeshBy6dFacedir(mesh_ptr[j], j); recalculateBoundingBox(mesh_ptr[j]); meshmanip->recalculateNormals(mesh_ptr[j], true, false); } } else if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_WALLMOUNTED)) { static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2}; for (u16 j = 1; j < 6; j++) { mesh_ptr[j] = cloneMesh(mesh_ptr[0]); rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]); recalculateBoundingBox(mesh_ptr[j]); meshmanip->recalculateNormals(mesh_ptr[j], true, false); } rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]); recalculateBoundingBox(mesh_ptr[0]); meshmanip->recalculateNormals(mesh_ptr[0], true, false); } }
//! renders the node. void Sky::render() { if(!m_visible) return; video::IVideoDriver* driver = SceneManager->getVideoDriver(); scene::ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera || !driver) return; //ScopeProfiler sp(g_profiler, "Sky::render()", SPT_AVG); // draw perspective skybox core::matrix4 translate(AbsoluteTransformation); translate.setTranslation(camera->getAbsolutePosition()); // Draw the sky box between the near and far clip plane const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f; core::matrix4 scale; scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance)); driver->setTransform(video::ETS_WORLD, translate * scale); if(m_sunlight_seen) { float sunsize = 0.07; video::SColorf suncolor_f(1, 1, 0, 1); suncolor_f.r = 1; suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7+m_time_brightness*(0.5))); suncolor_f.b = MYMAX(0.0, m_brightness*0.95); video::SColorf suncolor2_f(1, 1, 1, 1); suncolor_f.r = 1; suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85+m_time_brightness*(0.5))); suncolor_f.b = MYMAX(0.0, m_brightness); float moonsize = 0.04; video::SColorf mooncolor_f(0.50, 0.57, 0.65, 1); video::SColorf mooncolor2_f(0.85, 0.875, 0.9, 1); float nightlength = 0.415; float wn = nightlength / 2; float wicked_time_of_day = 0; if(m_time_of_day > wn && m_time_of_day < 1.0 - wn) wicked_time_of_day = (m_time_of_day - wn)/(1.0-wn*2)*0.5 + 0.25; else if(m_time_of_day < 0.5) wicked_time_of_day = m_time_of_day / wn * 0.25; else wicked_time_of_day = 1.0 - ((1.0-m_time_of_day) / wn * 0.25); /*std::cerr<<"time_of_day="<<m_time_of_day<<" -> " <<"wicked_time_of_day="<<wicked_time_of_day<<std::endl;*/ video::SColor suncolor = suncolor_f.toSColor(); video::SColor suncolor2 = suncolor2_f.toSColor(); video::SColor mooncolor = mooncolor_f.toSColor(); video::SColor mooncolor2 = mooncolor2_f.toSColor(); // Calculate offset normalized to the X dimension of a 512x1 px tonemap float offset=(1.0-fabs(sin((m_time_of_day - 0.5)*irr::core::PI)))*511; if (m_sun_tonemap){ u8 * texels = (u8 *)m_sun_tonemap->lock(); if (!texels) return; video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4); video::SColor texel_color (255,texel->getRed(),texel->getGreen(), texel->getBlue()); m_sun_tonemap->unlock(); m_materials[3].EmissiveColor = texel_color; } if (m_moon_tonemap){ u8 * texels = (u8 *)m_moon_tonemap->lock(); if (!texels) return; video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4); video::SColor texel_color (255,texel->getRed(),texel->getGreen(), texel->getBlue()); m_moon_tonemap->unlock(); m_materials[4].EmissiveColor = texel_color; } const f32 t = 1.0f; const f32 o = 0.0f; static const u16 indices[4] = {0,1,2,3}; video::S3DVertex vertices[4]; driver->setMaterial(m_materials[1]); //video::SColor cloudyfogcolor(255,255,255,255); video::SColor cloudyfogcolor = m_bgcolor; //video::SColor cloudyfogcolor = m_bgcolor.getInterpolated(m_skycolor, 0.5); v3POS player_position = floatToInt(camera->getPosition(), BS)+camera_offset; float shift1 = -(float)player_position.Y / MAP_GENERATION_LIMIT; float shifty = shift1 * 0.4; // Draw far cloudy fog thing for(u32 j=0; j<4; j++) { video::SColor c = cloudyfogcolor.getInterpolated(m_skycolor, 0.45); vertices[0] = video::S3DVertex(-1, 0.08+shifty,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( 1, 0.08+shifty,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( 1, 0.12+shifty,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-1, 0.12+shifty,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ if(j==0) // Don't switch {} else if(j==1) // Switch from -Z (south) to +X (east) vertices[i].Pos.rotateXZBy(90); else if(j==2) // Switch from -Z (south) to -X (west) vertices[i].Pos.rotateXZBy(-90); else // Switch from -Z (south) to -Z (north) vertices[i].Pos.rotateXZBy(-180); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } for(u32 j=0; j<4; j++) { video::SColor c = cloudyfogcolor; vertices[0] = video::S3DVertex(-1,-1.0, 0, 0,0,0, c, t, t); vertices[1] = video::S3DVertex( 1,-1.0, 0, 0,0,0, c, o, t); vertices[2] = video::S3DVertex( 1, 0.08+shifty,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-1, 0.08+shifty,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ if(j==0) // Don't switch {} else if(j==1) // Switch from -Z (south) to +X (east) vertices[i].Pos.rotateXZBy(90); else if(j==2) // Switch from -Z (south) to -X (west) vertices[i].Pos.rotateXZBy(-90); else // Switch from -Z (south) to -Z (north) vertices[i].Pos.rotateXZBy(-180); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } driver->setMaterial(m_materials[2]); { float mid1 = 0.25 + 0.06 * shift1; float mid = (wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1)); float a_ = 1.0 - fabs(wicked_time_of_day - mid) * 35.0; float a = easeCurve(MYMAX(0, MYMIN(1, a_))); //std::cerr<<"a_="<<a_<<" a="<<a<<std::endl; video::SColor c(255,255,255,255); float y = -(1.0 - a) * 0.2; vertices[0] = video::S3DVertex(-1,-0.05+y+shifty,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( 1,-0.05+y+shifty,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( 1, 0.2+y+shifty,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-1, 0.2+y+shifty,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ if(wicked_time_of_day < 0.5) // Switch from -Z (south) to +X (east) vertices[i].Pos.rotateXZBy(90); else // Switch from -Z (south) to -X (west) vertices[i].Pos.rotateXZBy(-90); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } bool sun_light_drawed = false; // Draw sun if(wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85){ if (!m_sun_texture){ driver->setMaterial(m_materials[1]); float d = sunsize * 1.7; video::SColor c = suncolor; c.setAlpha(0.05*255); vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to +X (east) sky_rotate(camera, SKY_ROTATE::SUN, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); d = sunsize * 1.2; c = suncolor; c.setAlpha(0.15*255); vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to +X (east) sky_rotate(camera, SKY_ROTATE::SUN, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); d = sunsize; vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to +X (east) sky_rotate(camera, SKY_ROTATE::SUN, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); d = sunsize * 0.7; vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor2, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor2, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor2, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor2, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to +X (east) sky_rotate(camera, SKY_ROTATE::SUN, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } else { driver->setMaterial(m_materials[3]); float d = sunsize * 1.7; video::SColor c; if (m_sun_tonemap) c = video::SColor (0,0,0,0); else c = video::SColor (255,255,255,255); vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to +X (east) sky_rotate(camera, SKY_ROTATE::SUN, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } if (sun_moon_light) { auto light_vector = core::vector3df(0, MAP_GENERATION_LIMIT*BS*2, 0); sky_rotate(camera, SKY_ROTATE::SUNLIGHT, wicked_time_of_day, light_vector); if (light_vector.Y > 0) { sun_moon_light->setPosition(light_vector); sun_light_drawed = true; } } } // Draw moon if(wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7) { if (!m_moon_texture){ driver->setMaterial(m_materials[1]); float d = moonsize * 1.9; video::SColor c = mooncolor; c.setAlpha(0.05*255); vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to -X (west) sky_rotate(camera, SKY_ROTATE::MOON, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); d = moonsize * 1.3; c = mooncolor; c.setAlpha(0.15*255); vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to -X (west) sky_rotate(camera, SKY_ROTATE::MOON, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); d = moonsize; vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, mooncolor, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, mooncolor, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, mooncolor, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to -X (west) sky_rotate(camera, SKY_ROTATE::MOON, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); float d2 = moonsize * 0.6; vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor2, t, t); vertices[1] = video::S3DVertex( d2,-d,-1, 0,0,1, mooncolor2, o, t); vertices[2] = video::S3DVertex( d2, d2,-1, 0,0,1, mooncolor2, o, o); vertices[3] = video::S3DVertex(-d, d2,-1, 0,0,1, mooncolor2, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to -X (west) sky_rotate(camera, SKY_ROTATE::MOON, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } else { driver->setMaterial(m_materials[4]); float d = moonsize * 1.9; video::SColor c; if (m_moon_tonemap) c = video::SColor (0,0,0,0); else c = video::SColor (255,255,255,255); vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ // Switch from -Z (south) to -X (west) sky_rotate(camera, SKY_ROTATE::MOON, wicked_time_of_day, vertices[i].Pos); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } if (!sun_light_drawed && sun_moon_light) { auto light_vector = core::vector3df(0, -MAP_GENERATION_LIMIT*BS*2, 0); sky_rotate(camera, SKY_ROTATE::MOONLIGHT, wicked_time_of_day, light_vector); if (light_vector.Y > 0) sun_moon_light->setPosition(light_vector); } } // Stars driver->setMaterial(m_materials[1]); do{ float starbrightness = MYMAX(0, MYMIN(1, (0.285 - fabs(wicked_time_of_day < 0.5 ? wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10)); float f = starbrightness; float d = 0.007; video::SColor starcolor(255, f*90,f*90,f*90); if(starcolor.getBlue() < m_skycolor.getBlue()) break; u16 indices[SKY_STAR_COUNT*4]; video::S3DVertex vertices[SKY_STAR_COUNT*4]; for(u32 i=0; i<SKY_STAR_COUNT; i++){ indices[i*4+0] = i*4+0; indices[i*4+1] = i*4+1; indices[i*4+2] = i*4+2; indices[i*4+3] = i*4+3; v3f p = m_stars[i]; core::CMatrix4<f32> a; a.buildRotateFromTo(v3f(0,1,0), v3f(d,1+d/2,0)); v3f p1 = p; a.rotateVect(p1); a.buildRotateFromTo(v3f(0,1,0), v3f(d,1,d)); v3f p2 = p; a.rotateVect(p2); a.buildRotateFromTo(v3f(0,1,0), v3f(0,1-d/2,d)); v3f p3 = p; a.rotateVect(p3); p.rotateXYBy(wicked_time_of_day * 360 - 90); p1.rotateXYBy(wicked_time_of_day * 360 - 90); p2.rotateXYBy(wicked_time_of_day * 360 - 90); p3.rotateXYBy(wicked_time_of_day * 360 - 90); vertices[i*4+0].Pos = p; vertices[i*4+0].Color = starcolor; vertices[i*4+1].Pos = p1; vertices[i*4+1].Color = starcolor; vertices[i*4+2].Pos = p2; vertices[i*4+2].Color = starcolor; vertices[i*4+3].Pos = p3; vertices[i*4+3].Color = starcolor; } driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT*4, indices, SKY_STAR_COUNT, video::EVT_STANDARD, scene::EPT_QUADS, video::EIT_16BIT); }while(0); for(u32 j=0; j<2; j++) { //video::SColor c = m_skycolor; video::SColor c = cloudyfogcolor; vertices[0] = video::S3DVertex(-1,-1.0,-1, 0,0,1, c, t, t); vertices[1] = video::S3DVertex( 1,-1.0,-1, 0,0,1, c, o, t); vertices[2] = video::S3DVertex( 1,-0.02+shifty,-1, 0,0,1, c, o, o); vertices[3] = video::S3DVertex(-1,-0.02+shifty,-1, 0,0,1, c, t, o); for(u32 i=0; i<4; i++){ //if(wicked_time_of_day < 0.5) if(j==0) // Switch from -Z (south) to +X (east) vertices[i].Pos.rotateXZBy(90); else // Switch from -Z (south) to -X (west) vertices[i].Pos.rotateXZBy(-90); } driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2); } } }
void NodeBox::serialize(std::ostream &os, u16 protocol_version) const { int version = 1; if (protocol_version >= 27) version = 3; else if (protocol_version >= 21) version = 2; writeU8(os, version); switch (type) { case NODEBOX_LEVELED: case NODEBOX_FIXED: if (version == 1) writeU8(os, NODEBOX_FIXED); else writeU8(os, type); writeU16(os, fixed.size()); for (std::vector<aabb3f>::const_iterator i = fixed.begin(); i != fixed.end(); ++i) { writeV3F1000(os, i->MinEdge); writeV3F1000(os, i->MaxEdge); } break; case NODEBOX_WALLMOUNTED: writeU8(os, type); writeV3F1000(os, wall_top.MinEdge); writeV3F1000(os, wall_top.MaxEdge); writeV3F1000(os, wall_bottom.MinEdge); writeV3F1000(os, wall_bottom.MaxEdge); writeV3F1000(os, wall_side.MinEdge); writeV3F1000(os, wall_side.MaxEdge); break; case NODEBOX_CONNECTED: if (version <= 2) { // send old clients nodes that can't be walked through // to prevent abuse writeU8(os, NODEBOX_FIXED); writeU16(os, 1); writeV3F1000(os, v3f(-BS/2, -BS/2, -BS/2)); writeV3F1000(os, v3f(BS/2, BS/2, BS/2)); } else { writeU8(os, type); #define WRITEBOX(box) do { \ writeU16(os, (box).size()); \ for (std::vector<aabb3f>::const_iterator \ i = (box).begin(); \ i != (box).end(); ++i) { \ writeV3F1000(os, i->MinEdge); \ writeV3F1000(os, i->MaxEdge); \ }; } while (0) WRITEBOX(fixed); WRITEBOX(connect_top); WRITEBOX(connect_bottom); WRITEBOX(connect_front); WRITEBOX(connect_left); WRITEBOX(connect_back); WRITEBOX(connect_right); } break; default: writeU8(os, type); break; } }
<< "unsupported ser_fmt_ver"<< std::endl; return; } m_server_ser_ver = server_ser_ver; // We can be totally wrong with this guess // but we only need some value < 25. m_proto_ver = 24; // Get player position v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0); if (pkt->getSize() >= 1 + 6) { *pkt >> playerpos_s16; } v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0); // Set player position Player *player = m_env.getLocalPlayer(); assert(player != NULL); player->setPosition(playerpos_f); if (pkt->getSize() >= 1 + 6 + 8) { // Get map seed *pkt >> m_map_seed; infostream << "Client: received map seed: " << m_map_seed << std::endl; } if (pkt->getSize() >= 1 + 6 + 8 + 4) { *pkt >> m_recommended_send_interval;
*/ #include "dungeongen.h" #include "mapgen.h" #include "voxel.h" #include "noise.h" #include "mapblock.h" #include "mapnode.h" #include "map.h" #include "nodedef.h" #include "profiler.h" #include "settings.h" //#define DGEN_USE_TORCHES NoiseParams nparams_dungeon_density(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0); NoiseParams nparams_dungeon_alt_wall(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0); /////////////////////////////////////////////////////////////////////////////// DungeonGen::DungeonGen(INodeDefManager *ndef, GenerateNotifier *gennotify, DungeonParams *dparams) { assert(ndef); this->ndef = ndef; this->gennotify = gennotify; #ifdef DGEN_USE_TORCHES
void MapgenV6::generateCaves(int max_stone_y) { // 24ms @cs=8 //TimeTaker timer1("caves"); /*double cave_amount = 6.0 + 6.0 * noise2d_perlin( 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250, data->seed+34329, 3, 0.50);*/ const s16 max_spread_amount = MAP_BLOCKSIZE; float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed); cave_amount = MYMAX(0.0, cave_amount); u32 caves_count = cave_amount * volume_nodes / 50000; u32 bruises_count = 1; PseudoRandom ps(blockseed + 21343); PseudoRandom ps2(blockseed + 1032); if (ps.range(1, 6) == 1) bruises_count = ps.range(0, ps.range(0, 2)); if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) { caves_count /= 3; bruises_count /= 3; } for(u32 jj = 0; jj < caves_count + bruises_count; jj++) { /*int avg_height = (int) ((base_rock_level_2d(data->seed, v2s16(node_min.X, node_min.Z)) + base_rock_level_2d(data->seed, v2s16(node_max.X, node_max.Z))) / 2); if ((node_max.Y + node_min.Y) / 2 > avg_height) break;*/ bool large_cave = (jj >= caves_count); Cave cave; defineCave(cave, ps, node_min, large_cave); v3f main_direction(0,0,0); // Allowed route area size in nodes v3s16 ar = central_area_size; // Area starting point in nodes v3s16 of = node_min; // Allow a bit more //(this should be more than the maximum radius of the tunnel) s16 insure = 10; s16 more = max_spread_amount - cave.max_tunnel_diameter / 2 - insure; ar += v3s16(1,0,1) * more * 2; of -= v3s16(1,0,1) * more; s16 route_y_min = 0; // Allow half a diameter + 7 over stone surface s16 route_y_max = -of.Y + max_stone_y + cave.max_tunnel_diameter/2 + 7; // Limit maximum to area route_y_max = rangelim(route_y_max, 0, ar.Y-1); if(large_cave) { s16 min = 0; if(node_min.Y < water_level && node_max.Y > water_level) { min = water_level - cave.max_tunnel_diameter/3 - of.Y; route_y_max = water_level + cave.max_tunnel_diameter/3 - of.Y; } route_y_min = ps.range(min, min + cave.max_tunnel_diameter); route_y_min = rangelim(route_y_min, 0, route_y_max); } s16 route_start_y_min = route_y_min; s16 route_start_y_max = route_y_max; route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1); route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1); // Randomize starting position v3f orp( (float)(ps.next()%ar.X)+0.5, (float)(ps.range(route_start_y_min, route_start_y_max))+0.5, (float)(ps.next()%ar.Z)+0.5 ); v3s16 startp(orp.X, orp.Y, orp.Z); startp += of; MapNode airnode(CONTENT_AIR); MapNode waternode(c_water_source); MapNode lavanode(c_lava_source); /* Generate some tunnel starting from orp */ for(u16 j=0; j<cave.tunnel_routepoints; j++) { if(j%cave.dswitchint==0 && large_cave == false) { main_direction = v3f( ((float)(ps.next()%20)-(float)10)/10, ((float)(ps.next()%20)-(float)10)/30, ((float)(ps.next()%20)-(float)10)/10 ); main_direction *= (float)ps.range(0, 10)/10; } // Randomize size s16 min_d = cave.min_tunnel_diameter; s16 max_d = cave.max_tunnel_diameter; s16 rs = ps.range(min_d, max_d); // Every second section is rough bool randomize_xz = (ps2.range(1,2) == 1); v3s16 maxlen; if(large_cave) { maxlen = v3s16( rs*cave.part_max_length_rs, rs*cave.part_max_length_rs/2, rs*cave.part_max_length_rs ); } else { maxlen = v3s16( rs*cave.part_max_length_rs, ps.range(1, rs*cave.part_max_length_rs), rs*cave.part_max_length_rs ); } v3f vec; vec = v3f( (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2, (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2, (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2 ); // Jump downward sometimes if(!large_cave && ps.range(0,12) == 0) { vec = v3f( (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2, (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2, (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2 ); } /*if(large_cave){ v3f p = orp + vec; s16 h = find_ground_level_clever(vmanip, v2s16(p.X, p.Z), ndef); route_y_min = h - rs/3; route_y_max = h + rs; }*/ vec += main_direction; v3f rp = orp + vec; if(rp.X < 0) rp.X = 0; else if(rp.X >= ar.X) rp.X = ar.X-1; if(rp.Y < route_y_min) rp.Y = route_y_min; else if(rp.Y >= route_y_max) rp.Y = route_y_max-1; if(rp.Z < 0) rp.Z = 0; else if(rp.Z >= ar.Z) rp.Z = ar.Z-1; vec = rp - orp; for(float f=0; f<1.0; f+=1.0/vec.getLength()) { v3f fp = orp + vec * f; fp.X += 0.1*ps.range(-10,10); fp.Z += 0.1*ps.range(-10,10); v3s16 cp(fp.X, fp.Y, fp.Z); s16 d0 = -rs/2; s16 d1 = d0 + rs; if(randomize_xz){ d0 += ps.range(-1,1); d1 += ps.range(-1,1); } for(s16 z0=d0; z0<=d1; z0++) { s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1); for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++) { s16 maxabsxz = MYMAX(abs(x0), abs(z0)); s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1); for(s16 y0=-si2; y0<=si2; y0++) { /*// Make better floors in small caves if(y0 <= -rs/2 && rs<=7) continue;*/ if (cave.large_cave_is_flat) { // Make large caves not so tall if (rs > 7 && abs(y0) >= rs/3) continue; } s16 z = cp.Z + z0; s16 y = cp.Y + y0; s16 x = cp.X + x0; v3s16 p(x,y,z); p += of; if(vm->m_area.contains(p) == false) continue; u32 i = vm->m_area.index(p); if(large_cave) { if (cave.flooded && full_node_min.Y < water_level && full_node_max.Y > water_level) { if (p.Y <= water_level) vm->m_data[i] = waternode; else vm->m_data[i] = airnode; } else if (cave.flooded && full_node_max.Y < water_level) { if (p.Y < startp.Y - 2) vm->m_data[i] = lavanode; else vm->m_data[i] = airnode; } else { vm->m_data[i] = airnode; } } else { // Don't replace air or water or lava or ignore if (vm->m_data[i].getContent() == CONTENT_IGNORE || vm->m_data[i].getContent() == CONTENT_AIR || vm->m_data[i].getContent() == c_water_source || vm->m_data[i].getContent() == c_lava_source) continue; vm->m_data[i] = airnode; // Set tunnel flag vm->m_flags[i] |= VMANIP_FLAG_CAVE; } } } } } orp = rp; } } }
void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc, scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings) { // minimap pixel color - the average color of a texture if (tsettings.enable_minimap && !tiledef[0].name.empty()) minimap_color = tsrc->getTextureAverageColor(tiledef[0].name); // Figure out the actual tiles to use TileDef tdef[6]; for (u32 j = 0; j < 6; j++) { tdef[j] = tiledef[j]; if (tdef[j].name.empty()) tdef[j].name = "unknown_node.png"; } // also the overlay tiles TileDef tdef_overlay[6]; for (u32 j = 0; j < 6; j++) tdef_overlay[j] = tiledef_overlay[j]; // also the special tiles TileDef tdef_spec[6]; for (u32 j = 0; j < CF_SPECIAL_COUNT; j++) tdef_spec[j] = tiledef_special[j]; bool is_liquid = false; u8 material_type = (alpha == 255) ? TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; switch (drawtype) { default: case NDT_NORMAL: material_type = (alpha == 255) ? TILE_MATERIAL_OPAQUE : TILE_MATERIAL_ALPHA; solidness = 2; break; case NDT_AIRLIKE: solidness = 0; break; case NDT_LIQUID: assert(liquid_type == LIQUID_SOURCE); if (tsettings.opaque_water) alpha = 255; solidness = 1; is_liquid = true; break; case NDT_FLOWINGLIQUID: assert(liquid_type == LIQUID_FLOWING); solidness = 0; if (tsettings.opaque_water) alpha = 255; is_liquid = true; break; case NDT_GLASSLIKE: solidness = 0; visual_solidness = 1; break; case NDT_GLASSLIKE_FRAMED: solidness = 0; visual_solidness = 1; break; case NDT_GLASSLIKE_FRAMED_OPTIONAL: solidness = 0; visual_solidness = 1; drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE; break; case NDT_ALLFACES: solidness = 0; visual_solidness = 1; break; case NDT_ALLFACES_OPTIONAL: if (tsettings.leaves_style == LEAVES_FANCY) { drawtype = NDT_ALLFACES; solidness = 0; visual_solidness = 1; } else if (tsettings.leaves_style == LEAVES_SIMPLE) { for (u32 j = 0; j < 6; j++) { if (!tdef_spec[j].name.empty()) tdef[j].name = tdef_spec[j].name; } drawtype = NDT_GLASSLIKE; solidness = 0; visual_solidness = 1; } else { drawtype = NDT_NORMAL; solidness = 2; for (TileDef &td : tdef) td.name += std::string("^[noalpha"); } if (waving >= 1) material_type = TILE_MATERIAL_WAVING_LEAVES; break; case NDT_PLANTLIKE: solidness = 0; if (waving >= 1) material_type = TILE_MATERIAL_WAVING_PLANTS; break; case NDT_FIRELIKE: solidness = 0; break; case NDT_MESH: case NDT_NODEBOX: solidness = 0; if (waving == 1) material_type = TILE_MATERIAL_WAVING_PLANTS; else if (waving == 2) material_type = TILE_MATERIAL_WAVING_LEAVES; break; case NDT_TORCHLIKE: case NDT_SIGNLIKE: case NDT_FENCELIKE: case NDT_RAILLIKE: solidness = 0; break; case NDT_PLANTLIKE_ROOTED: solidness = 2; break; } if (is_liquid) { // Vertex alpha is no longer supported, correct if necessary. correctAlpha(tdef, 6); correctAlpha(tdef_overlay, 6); correctAlpha(tdef_spec, CF_SPECIAL_COUNT); material_type = (alpha == 255) ? TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT; } u32 tile_shader = shdsrc->getShader("nodes_shader", material_type, drawtype); u8 overlay_material = material_type; if (overlay_material == TILE_MATERIAL_OPAQUE) overlay_material = TILE_MATERIAL_BASIC; else if (overlay_material == TILE_MATERIAL_LIQUID_OPAQUE) overlay_material = TILE_MATERIAL_LIQUID_TRANSPARENT; u32 overlay_shader = shdsrc->getShader("nodes_shader", overlay_material, drawtype); // Tiles (fill in f->tiles[]) for (u16 j = 0; j < 6; j++) { tiles[j].world_aligned = isWorldAligned(tdef[j].align_style, tsettings.world_aligned_mode, drawtype); fillTileAttribs(tsrc, &tiles[j].layers[0], tiles[j], tdef[j], color, material_type, tile_shader, tdef[j].backface_culling, tsettings); if (!tdef_overlay[j].name.empty()) fillTileAttribs(tsrc, &tiles[j].layers[1], tiles[j], tdef_overlay[j], color, overlay_material, overlay_shader, tdef[j].backface_culling, tsettings); } u8 special_material = material_type; if (drawtype == NDT_PLANTLIKE_ROOTED) { if (waving == 1) special_material = TILE_MATERIAL_WAVING_PLANTS; else if (waving == 2) special_material = TILE_MATERIAL_WAVING_LEAVES; } u32 special_shader = shdsrc->getShader("nodes_shader", special_material, drawtype); // Special tiles (fill in f->special_tiles[]) for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) fillTileAttribs(tsrc, &special_tiles[j].layers[0], special_tiles[j], tdef_spec[j], color, special_material, special_shader, tdef_spec[j].backface_culling, tsettings); if (param_type_2 == CPT2_COLOR || param_type_2 == CPT2_COLORED_FACEDIR || param_type_2 == CPT2_COLORED_WALLMOUNTED) palette = tsrc->getPalette(palette_name); if (drawtype == NDT_MESH && !mesh.empty()) { // Meshnode drawtype // Read the mesh and apply scale mesh_ptr[0] = client->getMesh(mesh); if (mesh_ptr[0]){ v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale; scaleMesh(mesh_ptr[0], scale); recalculateBoundingBox(mesh_ptr[0]); meshmanip->recalculateNormals(mesh_ptr[0], true, false); } } //Cache 6dfacedir and wallmounted rotated clones of meshes if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_FACEDIR || param_type_2 == CPT2_COLORED_FACEDIR)) { for (u16 j = 1; j < 24; j++) { mesh_ptr[j] = cloneMesh(mesh_ptr[0]); rotateMeshBy6dFacedir(mesh_ptr[j], j); recalculateBoundingBox(mesh_ptr[j]); meshmanip->recalculateNormals(mesh_ptr[j], true, false); } } else if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_WALLMOUNTED || param_type_2 == CPT2_COLORED_WALLMOUNTED)) { static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 }; for (u16 j = 1; j < 6; j++) { mesh_ptr[j] = cloneMesh(mesh_ptr[0]); rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]); recalculateBoundingBox(mesh_ptr[j]); meshmanip->recalculateNormals(mesh_ptr[j], true, false); } rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]); recalculateBoundingBox(mesh_ptr[0]); meshmanip->recalculateNormals(mesh_ptr[0], true, false); } }
v3s16 LocalPlayer::getStandingNodePos() { if(m_sneak_node_exists) return m_sneak_node; return floatToInt(getPosition() - v3f(0, BS, 0), BS); }
v3s16 Player::getLightPosition() const { return floatToInt(m_position + v3f(0,BS+BS/2,0), BS); }
v3f random_v3f(v3f min, v3f max) { return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X, rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y, rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z); }
virtual void updateTexturesAndMeshes(IGameDef *gamedef) { #ifndef SERVER infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating " <<"textures and meshes in item definitions"<<std::endl; ITextureSource *tsrc = gamedef->getTextureSource(); INodeDefManager *nodedef = gamedef->getNodeDefManager(); IrrlichtDevice *device = tsrc->getDevice(); video::IVideoDriver *driver = device->getVideoDriver(); for(std::map<std::string, ItemDefinition*>::iterator i = m_item_definitions.begin(); i != m_item_definitions.end(); i++) { ItemDefinition *def = i->second; bool need_node_mesh = false; // Create an inventory texture def->inventory_texture = NULL; if(def->inventory_image != "") { def->inventory_texture = tsrc->getTextureRaw(def->inventory_image); } else if(def->type == ITEM_NODE) { need_node_mesh = true; } // Create a wield mesh if(def->wield_mesh != NULL) { def->wield_mesh->drop(); def->wield_mesh = NULL; } if(def->type == ITEM_NODE && def->wield_image == "") { need_node_mesh = true; } else if(def->wield_image != "" || def->inventory_image != "") { // Extrude the wield image into a mesh std::string imagename; if(def->wield_image != "") imagename = def->wield_image; else imagename = def->inventory_image; def->wield_mesh = createExtrudedMesh( tsrc->getTextureRaw(imagename), driver, def->wield_scale * v3f(40.0, 40.0, 4.0)); if(def->wield_mesh == NULL) { infostream<<"ItemDefManager: WARNING: " <<"updateTexturesAndMeshes(): " <<"Unable to create extruded mesh for item " <<def->name<<std::endl; } } if(need_node_mesh) { /* Get node properties */ content_t id = nodedef->getId(def->name); const ContentFeatures &f = nodedef->get(id); u8 param1 = 0; if(f.param_type == CPT_LIGHT) param1 = 0xee; /* Make a mesh from the node */ MeshMakeData mesh_make_data(gamedef); MapNode mesh_make_node(id, param1, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data); scene::IMesh *node_mesh = mapblock_mesh.getMesh(); assert(node_mesh); setMeshColor(node_mesh, video::SColor(255, 255, 255, 255)); /* Scale and translate the mesh so it's a unit cube centered on the origin */ scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS)); translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0)); /* Draw node mesh into a render target texture */ if(def->inventory_texture == NULL) { core::dimension2d<u32> dim(64,64); std::string rtt_texture_name = "INVENTORY_" + def->name + "_RTT"; v3f camera_position(0, 1.0, -1.5); camera_position.rotateXZBy(45); v3f camera_lookat(0, 0, 0); core::CMatrix4<f32> camera_projection_matrix; // Set orthogonal projection camera_projection_matrix.buildProjectionMatrixOrthoLH( 1.65, 1.65, 0, 100); video::SColorf ambient_light(0.2,0.2,0.2); v3f light_position(10, 100, -50); video::SColorf light_color(0.5,0.5,0.5); f32 light_radius = 1000; def->inventory_texture = generateTextureFromMesh( node_mesh, device, dim, rtt_texture_name, camera_position, camera_lookat, camera_projection_matrix, ambient_light, light_position, light_color, light_radius); // render-to-target didn't work if(def->inventory_texture == NULL) { def->inventory_texture = tsrc->getTextureRaw(f.tiledef[0].name); } } /* Use the node mesh as the wield mesh */ if(def->wield_mesh == NULL) { // Scale to proper wield mesh proportions scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0) * def->wield_scale); def->wield_mesh = node_mesh; def->wield_mesh->grab(); } // falling outside of here deletes node_mesh } } #endif }