diff --git a/src/client.cpp b/src/client.cpp index d43b97a3ceb1952188de3738b05cdd316ba7f4c3..af2b375f48dbf52d5f81f72ce38e07c5c9d358bb 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -66,14 +66,9 @@ void * ClientUpdateThread::Thread() Client::Client( IrrlichtDevice *device, const char *playername, - JMutex &range_mutex, - float &viewing_range_nodes, - bool &viewing_range_all): + MapDrawControl &control): m_thread(this), - m_env(new ClientMap(this, - range_mutex, - viewing_range_nodes, - viewing_range_all, + m_env(new ClientMap(this, control, device->getSceneManager()->getRootSceneNode(), device->getSceneManager(), 666), dout_client), diff --git a/src/client.h b/src/client.h index e48c8ec69e2aa6deae433e0a8631adfad14d9eb8..c56b615cb6d86edb08dcd3684ce1a2a2ee20ae3a 100644 --- a/src/client.h +++ b/src/client.h @@ -110,9 +110,7 @@ class Client : public con::PeerHandler Client( IrrlichtDevice *device, const char *playername, - JMutex &range_mutex, - float &viewing_range_nodes, - bool &viewing_range_all + MapDrawControl &control ); ~Client(); diff --git a/src/main.cpp b/src/main.cpp index b7a1b6b328c5f3fa625c30f3bb86ec22e599d278..2f22caeb011b499cc5fe076eba5d6048cd426154 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -253,25 +253,7 @@ TODO: Fix viewing range updater's oscillation when there is large non- IrrlichtWrapper *g_irrlicht; -// All range-related stuff below is locked behind this -JMutex g_range_mutex; - -// Blocks are viewed in this range from the player -float g_viewing_range_nodes = 60; -//s16 g_viewing_range_nodes = 0; - -// This is updated by the client's fetchBlocks routine -//s16 g_actual_viewing_range_nodes = VIEWING_RANGE_NODES_DEFAULT; - -// If true, the preceding value has no meaning and all blocks -// already existing in memory are drawn -bool g_viewing_range_all = false; - -// This is the freetime ratio imposed by the dynamic viewing -// range changing code. -// It is controlled by the main loop to the smallest value that -// inhibits glitches (dtime jitter) in the main loop. -//float g_freetime_ratio = FREETIME_RATIO_MAX; +MapDrawControl draw_control; /* Settings. @@ -455,15 +437,14 @@ class MyEventReceiver : public IEventReceiver // Viewing range selection if(event.KeyInput.Key == irr::KEY_KEY_R) { - JMutexAutoLock lock(g_range_mutex); - if(g_viewing_range_all) + if(draw_control.range_all) { - g_viewing_range_all = false; + draw_control.range_all = false; dstream<<DTIME<<"Disabled full viewing range"<<std::endl; } else { - g_viewing_range_all = true; + draw_control.range_all = true; dstream<<DTIME<<"Enabled full viewing range"<<std::endl; } } @@ -853,7 +834,7 @@ class RandomInputHandler : public InputHandler void updateViewingRange(f32 frametime, Client *client) { // Range_all messes up frametime_avg - if(g_viewing_range_all == true) + if(draw_control.range_all == true) return; float wanted_fps = g_settings.getFloat("wanted_fps"); @@ -887,7 +868,7 @@ void updateViewingRange(f32 frametime, Client *client) float fraction_unbiased = frametime_avg / frametime_wanted; - float fraction = pow(fraction_unbiased, 20./(float)g_viewing_range_nodes); + float fraction = pow(fraction_unbiased, 20./(float)draw_control.wanted_range); /*float fraction = 1.0; // If frametime is too high @@ -948,7 +929,7 @@ void updateViewingRange(f32 frametime, Client *client) s16 viewing_range_nodes_min = g_settings.getS16("viewing_range_nodes_min"); s16 viewing_range_nodes_max = g_settings.getS16("viewing_range_nodes_max"); - s16 n = (float)g_viewing_range_nodes / fraction; + s16 n = (float)draw_control.wanted_range / fraction; if(n < viewing_range_nodes_min) n = viewing_range_nodes_min; if(n > viewing_range_nodes_max) @@ -956,20 +937,20 @@ void updateViewingRange(f32 frametime, Client *client) bool can_change = true; - if(client->isFetchingBlocks() == true && n > g_viewing_range_nodes) + if(client->isFetchingBlocks() == true && n > draw_control.wanted_range) can_change = false; if(can_change) - g_viewing_range_nodes = n; + draw_control.wanted_range = n; - /*dstream<<"g_viewing_range_nodes = " - <<g_viewing_range_nodes<<std::endl;*/ + /*dstream<<"draw_control.wanted_range = " + <<draw_control.wanted_range<<std::endl;*/ } #endif void updateViewingRange(f32 frametime_in, Client *client) { - if(g_viewing_range_all == true) + if(draw_control.range_all == true) return; static f32 added_frametime = 0; @@ -990,7 +971,29 @@ void updateViewingRange(f32 frametime_in, Client *client) <<": Collected "<<added_frames<<" frames, total of " <<added_frametime<<"s."<<std::endl; - f32 frametime = added_frametime / added_frames; + dstream<<"draw_control.blocks_drawn=" + <<draw_control.blocks_drawn + <<", draw_control.blocks_would_have_drawn=" + <<draw_control.blocks_would_have_drawn + <<std::endl; + + float range_min = g_settings.getS16("viewing_range_nodes_min"); + float range_max = g_settings.getS16("viewing_range_nodes_max"); + + draw_control.wanted_min_range = range_min; + draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1; + + float block_draw_ratio = 1.0; + if(draw_control.blocks_would_have_drawn != 0) + { + block_draw_ratio = (float)draw_control.blocks_drawn + / (float)draw_control.blocks_would_have_drawn; + } + + // Calculate the average frametime in the case that all wanted + // blocks had been drawn + f32 frametime = added_frametime / added_frames / block_draw_ratio; + added_frametime = 0.0; added_frames = 0; @@ -1007,7 +1010,7 @@ void updateViewingRange(f32 frametime_in, Client *client) return; } - float range = g_viewing_range_nodes; + float range = draw_control.wanted_range; float new_range = range; static s16 range_old = 0; @@ -1029,16 +1032,24 @@ void updateViewingRange(f32 frametime_in, Client *client) // A high value here results in slow changing range (0.0025) // SUGG: This could be dynamically adjusted so that when // the camera is turning, this is lower - float min_time_per_range = 0.001; + //float min_time_per_range = 0.0015; + float min_time_per_range = 0.0010; + //float min_time_per_range = 0.05 / range; if(time_per_range < min_time_per_range) + { time_per_range = min_time_per_range; - - dstream<<"time_per_range="<<time_per_range<<std::endl; + dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl; + } + else + { + dstream<<"time_per_range="<<time_per_range<<std::endl; + } f32 wanted_range_change = wanted_frametime_change / time_per_range; // Dampen the change a bit to kill oscillations //wanted_range_change *= 0.9; - wanted_range_change *= 0.75; + //wanted_range_change *= 0.75; + wanted_range_change *= 0.5; dstream<<"wanted_range_change="<<wanted_range_change<<std::endl; // If needed range change is very small, just return @@ -1051,9 +1062,6 @@ void updateViewingRange(f32 frametime_in, Client *client) new_range += wanted_range_change; dstream<<"new_range="<<new_range/*<<std::endl*/; - float range_min = g_settings.getS16("viewing_range_nodes_min"); - float range_max = g_settings.getS16("viewing_range_nodes_max"); - float new_range_unclamped = new_range; if(new_range < range_min) new_range = range_min; @@ -1065,9 +1073,7 @@ void updateViewingRange(f32 frametime_in, Client *client) else dstream<<std::endl; - JMutexAutoLock lock(g_range_mutex); - - g_viewing_range_nodes = new_range; + draw_control.wanted_range = new_range; range_old = new_range; frametime_old = frametime; @@ -1324,6 +1330,7 @@ int main(int argc, char *argv[]) // Initialize random seed srand(time(0)); + mysrand(time(0)); /* Run unit tests @@ -1334,12 +1341,6 @@ int main(int argc, char *argv[]) run_tests(); } - /* - Global range mutex - */ - g_range_mutex.Init(); - assert(g_range_mutex.IsInitialized()); - // Read map parameters from settings HMParams hm_params; @@ -1584,10 +1585,7 @@ int main(int argc, char *argv[]) Create client */ - Client client(device, playername, - g_range_mutex, - g_viewing_range_nodes, - g_viewing_range_all); + Client client(device, playername, draw_control); g_client = &client; @@ -2409,8 +2407,8 @@ int main(int argc, char *argv[]) if(g_settings.getBool("enable_fog") == true) { - f32 range = g_viewing_range_nodes * BS; - if(g_viewing_range_all) + f32 range = draw_control.wanted_range * BS; + if(draw_control.range_all) range = 100000*BS; driver->setFog( @@ -2435,13 +2433,13 @@ int main(int argc, char *argv[]) wchar_t temptext[150]; static float drawtime_avg = 0; - drawtime_avg = drawtime_avg * 0.98 + (float)drawtime*0.02; + drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05; static float beginscenetime_avg = 0; - beginscenetime_avg = beginscenetime_avg * 0.98 + (float)beginscenetime*0.02; + beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05; static float scenetime_avg = 0; - scenetime_avg = scenetime_avg * 0.98 + (float)scenetime*0.02; + scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05; static float endscenetime_avg = 0; - endscenetime_avg = endscenetime_avg * 0.98 + (float)endscenetime*0.02; + endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05; swprintf(temptext, 150, L"Minetest-c55 (" L"F: item=%i" @@ -2449,7 +2447,7 @@ int main(int argc, char *argv[]) L")" L" drawtime=%.0f, beginscenetime=%.0f, scenetime=%.0f, endscenetime=%.0f", g_selected_item, - g_viewing_range_all, + draw_control.range_all, drawtime_avg, beginscenetime_avg, scenetime_avg, @@ -2472,7 +2470,7 @@ int main(int argc, char *argv[]) busytime_jitter1_min_sample, busytime_jitter1_max_sample, dtime_jitter1_max_fraction * 100.0, - g_viewing_range_nodes + draw_control.wanted_range ); guitext2->setText(temptext); diff --git a/src/map.cpp b/src/map.cpp index d5a61d408f0c49d4101d4b774ecb96168b5bc4ee..b092e1fa538780dcfc656cd2d47246a4b6f52c83 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2889,9 +2889,7 @@ void ServerMap::PrintInfo(std::ostream &out) ClientMap::ClientMap( Client *client, - JMutex &range_mutex, - float &viewing_range_nodes, - bool &viewing_range_all, + MapDrawControl &control, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id @@ -2900,9 +2898,7 @@ ClientMap::ClientMap( scene::ISceneNode(parent, mgr, id), m_client(client), mesh(NULL), - m_range_mutex(range_mutex), - m_viewing_range_nodes(viewing_range_nodes), - m_viewing_range_all(viewing_range_all) + m_control(control) { mesh_mutex.Init(); @@ -3003,24 +2999,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) */ int time1 = time(0); - //s32 daynight_i = m_client->getDayNightIndex(); u32 daynight_ratio = m_client->getDayNightRatio(); - /* - Collect all blocks that are in the view range - - Should not optimize more here as we want to auto-update - all changed nodes in viewing range at the next step. - */ - - float viewing_range_nodes; - bool viewing_range_all; - { - JMutexAutoLock lock(m_range_mutex); - viewing_range_nodes = m_viewing_range_nodes; - viewing_range_all = m_viewing_range_all; - } - m_camera_mutex.Lock(); v3f camera_position = m_camera_position; v3f camera_direction = m_camera_direction; @@ -3035,7 +3015,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) camera_position.Y / BS, camera_position.Z / BS); - v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1); + v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1); v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d; v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d; @@ -3054,12 +3034,14 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // For limiting number of mesh updates per frame u32 mesh_update_count = 0; + + u32 blocks_would_have_drawn = 0; + u32 blocks_drawn = 0; //NOTE: The sectors map should be locked but we're not doing it // because it'd cause too much delays int timecheck_counter = 0; - core::map<v2s16, MapSector*>::Iterator si; si = m_sectors.getIterator(); for(; si.atEnd() == false; si++) @@ -3082,7 +3064,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) MapSector *sector = si.getNode()->getValue(); v2s16 sp = sector->getPos(); - if(viewing_range_all == false) + if(m_control.range_all == false) { if(sp.X < p_blocks_min.X || sp.X > p_blocks_max.X @@ -3126,12 +3108,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // Total distance f32 d = blockpos_relative.getLength(); - if(viewing_range_all == false) + if(m_control.range_all == false) { // If block is far away, don't draw it - if(d > viewing_range_nodes * BS) + if(d > m_control.wanted_range * BS) // This is nicer when fog is used - //if((dforward+d)/2 > viewing_range_nodes * BS) + //if((dforward+d)/2 > m_control.wanted_range * BS) continue; } @@ -3175,7 +3157,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) } f32 faraway = BS*50; - //f32 faraway = viewing_range_nodes * BS; + //f32 faraway = m_control.wanted_range * BS; /* This has to be done with the mesh_mutex unlocked @@ -3217,6 +3199,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) if(mesh == NULL) continue; + + blocks_would_have_drawn++; + if(blocks_drawn >= m_control.wanted_max_blocks + && m_control.range_all == false + && d > m_control.wanted_min_range * BS) + continue; + blocks_drawn++; u32 c = mesh->getMeshBufferCount(); @@ -3238,6 +3227,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) } } // foreach sectorblocks } + + m_control.blocks_drawn = blocks_drawn; + m_control.blocks_would_have_drawn = blocks_would_have_drawn; /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/ diff --git a/src/map.h b/src/map.h index 8952bc1108faae56aab8a99afe9feace4da14b53..d4b790abf4739ed68aa38991cf04096d93190bca 100644 --- a/src/map.h +++ b/src/map.h @@ -543,6 +543,31 @@ class ServerMap : public Map #ifndef SERVER +struct MapDrawControl +{ + MapDrawControl(): + range_all(false), + wanted_range(50), + wanted_max_blocks(0), + wanted_min_range(0), + blocks_drawn(0), + blocks_would_have_drawn(0) + { + } + // Overrides limits by drawing everything + bool range_all; + // Wanted drawing range + float wanted_range; + // Maximum number of blocks to draw + u32 wanted_max_blocks; + // Blocks in this range are drawn regardless of number of blocks drawn + float wanted_min_range; + // Number of blocks rendered is written here by the renderer + u32 blocks_drawn; + // Number of blocks that would have been drawn in wanted_range + u32 blocks_would_have_drawn; +}; + class Client; class ClientMap : public Map, public scene::ISceneNode @@ -550,9 +575,7 @@ class ClientMap : public Map, public scene::ISceneNode public: ClientMap( Client *client, - JMutex &range_mutex, - float &viewing_range_nodes, - bool &viewing_range_all, + MapDrawControl &control, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id @@ -618,10 +641,8 @@ class ClientMap : public Map, public scene::ISceneNode // This is the master heightmap mesh scene::SMesh *mesh; JMutex mesh_mutex; - - JMutex &m_range_mutex; - float &m_viewing_range_nodes; - bool &m_viewing_range_all; + + MapDrawControl &m_control; }; #endif diff --git a/src/servermain.cpp b/src/servermain.cpp index 9a35a4b0e1f92f2bcbfc6d07f579e22462e9e295..594f7f4a236c8657bc7f71f89b363dd366d14da0 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -239,6 +239,7 @@ int main(int argc, char *argv[]) // Initialize random seed srand(time(0)); + mysrand(time(0)); /* Run unit tests diff --git a/src/utility.cpp b/src/utility.cpp index 7126cbbdc57a3f2bdcaa2335d4977c1388560cbe..924324b90a8c4ff38cc9f4b6e3aad9eb397f4925 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -88,4 +88,18 @@ const v3s16 g_26dirs[26] = // 26 }; +static unsigned long next = 1; + +/* RAND_MAX assumed to be 32767 */ +int myrand(void) +{ + next = next * 1103515245 + 12345; + return((unsigned)(next/65536) % 32768); +} + +void mysrand(unsigned seed) +{ + next = seed; +} + diff --git a/src/utility.h b/src/utility.h index 3764616d09373370e1873ec8d49f5552ae2a1ee5..008a95c3834c5c3f75e513056f16fa3f65b6d377 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1323,5 +1323,10 @@ class RequestQueue MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue; }; +// Pseudo-random (VC++ rand() sucks) +int myrand(void); +void mysrand(unsigned seed); +#define MYRAND_MAX 32767 + #endif