diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c316d4..28a80d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ project(minetest) # Also remember to set PROTOCOL_VERSION in clientserver.h when releasing set(VERSION_MAJOR 0) set(VERSION_MINOR 3) -set(VERSION_PATCH dev-20111021) +set(VERSION_PATCH 1) set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") MESSAGE(STATUS "*** Will build version ${VERSION_STRING} ***") @@ -66,7 +66,7 @@ elseif(UNIX) # Linux, BSD etc set(EXAMPLE_CONF_DIR "share/doc/${PROJECT_NAME}") endif() -install(FILES "doc/README.txt" DESTINATION "${DOCDIR}") +install(FILES "README.txt" DESTINATION "${DOCDIR}") install(FILES "doc/changelog.txt" DESTINATION "${DOCDIR}") install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}") diff --git a/README.txt b/README.txt index cbe29db..0603924 100644 --- a/README.txt +++ b/README.txt @@ -54,12 +54,12 @@ Compiling on GNU/Linux: ----------------------- Install dependencies. Here's an example for Debian/Ubuntu: -$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev +$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev Download source, extract (this is the URL to the latest of source repository, which might not work at all times): -$ wget https://bitbucket.org/celeron55/minetest/get/tip.tar.gz -$ tar xf tip.tar.gz -$ cd minetest +$ wget https://github.com/celeron55/minetest/tarball/master -O master.tar.gz +$ tar xf master.tar.gz +$ cd celeron55-minetest-286edd4 (or similar) Build a version that runs directly from the source directory: $ cmake . -DRUN_IN_PLACE=1 @@ -73,7 +73,7 @@ $ ./minetest - If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0 - You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0 - You can select between Release and Debug build by -DCMAKE_BUILD_TYPE= - - Note that the Debug build is considerably slower + - Debug build is slower, but gives much more useful output in a debugger Compiling on Windows: --------------------- @@ -90,16 +90,18 @@ Compiling on Windows: http://www.winimage.com/zLibDll/index.html * Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip): http://www.winimage.com/zLibDll/index.html - * gettext bibrary and tools: + * Optional: gettext bibrary and tools: http://gnuwin32.sourceforge.net/downlinks/gettext.php + - This is used for other UI languages. Feel free to leave it out. * And, of course, Minetest-c55: http://celeron.55.lt/~celeron55/minetest/download - Steps: - Select a directory called DIR hereafter in which you will operate. - Make sure you have CMake and a compiler installed. - - Download all the other stuff to DIR and extract them into there. All those - packages contain a nice base directory in them, which should end up being - the direct subdirectories of DIR. + - Download all the other stuff to DIR and extract them into there. + ("extract here", not "extract to packagename/") + - All those packages contain a nice base directory in them, which + should end up being the direct subdirectories of DIR. - You will end up with a directory structure like this (+=dir, -=file): ----------------- + DIR @@ -119,7 +121,7 @@ Compiling on Windows: + lib + include ... - + gettext + + gettext (optional) +bin +include +lib @@ -163,7 +165,8 @@ Compiling on Windows: If using MSVC: - Open the generated minetest.sln - The project defaults to the "Debug" configuration. Make very sure to - select "Release", unless you want to debug some stuff (it's slower) + select "Release", unless you want to debug some stuff (it's slower + and might not even work at all) - Build the ALL_BUILD project - Build the INSTALL project - You should now have a working game with the executable in @@ -176,6 +179,30 @@ Compiling on Windows: - You should now have a working game with the executable in DIR/minetest/bin/minetest.exe +Windows releases of minetest are built using a bat script like this: +-------------------------------------------------------------------- + +set installpath="C:\tmp\minetest_install" +set irrlichtpath="C:\tmp\irrlicht-1.7.2" + +set sourcedir=%CD% +set builddir=%sourcedir%\bvc10 +mkdir %builddir% +pushd %builddir% +cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DRUN_IN_PLACE=1 -DCMAKE_INSTALL_PREFIX=%installpath% +"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" ALL_BUILD.vcxproj /p:Configuration=Release +"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" INSTALL.vcxproj /p:Configuration=Release +"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" PACKAGE.vcxproj /p:Configuration=Release +popd + +License of Minetest-c55 textures +-------------------------------- + +This does not apply to texture packs made by others. + +Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) +http://creativecommons.org/licenses/by-sa/3.0/ + License of Minetest-c55 ----------------------- diff --git a/doc/README.txt b/doc/README.txt deleted file mode 100644 index 6ae2365..0000000 --- a/doc/README.txt +++ /dev/null @@ -1,254 +0,0 @@ -Minetest-c55 ---------------- -An InfiniMiner/Minecraft inspired game. -Copyright (c) 2010-2011 Perttu Ahola - -Further documentation: ----------------------- -- Website: http://celeron.55.lt/~celeron55/minetest/ -- Wiki: http://celeron.55.lt/~celeron55/minetest/wiki/ -- Forum: http://celeron.55.lt/~celeron55/minetest/forum/ - -This is a development version: ------------------------------- -- Don't expect it to work as well as a finished game will. -- Please report any bugs to me. That way I can fix them to the next release. - - debug.txt is useful when the game crashes. - -Controls: ---------- -- See the in-game pause menu -- Settable in the configuration file, see the section below. - -Map directory: --------------- -- Map is stored in a directory, which can be removed to generate a new map. -- There is a command-line option for it: --map-dir -- For a RUN_IN_PLACE build, it is located in: - ../map -- Otherwise something like this: - Windows: C:\Documents and Settings\user\Application Data\minetest\map - Linux: ~/.minetest/map - OS X: ~/Library/Application Support/minetest/map - -Configuration file: -------------------- -- An optional configuration file can be used. See minetest.conf.example. -- Path to file can be passed as a parameter to the executable: - --config -- Defaults: - - If built with -DRUN_IN_PLACE=1: - ../minetest.conf - ../../minetest.conf - - Otherwise something like this: - Windows: C:\Documents and Settings\user\Application Data\minetest\minetest.conf - Linux: ~/.minetest/minetest.conf - OS X: ~/Library/Application Support/minetest.conf - -Command-line options: ---------------------- -- Use --help - -Compiling on GNU/Linux: ------------------------ - -Install dependencies. Here's an example for Debian/Ubuntu: -$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev - -Download source, extract (this is the URL to the latest of source repository, which might not work at all times): -$ wget https://github.com/celeron55/minetest/tarball/master -O master.tar.gz -$ tar xf master.tar.gz -$ cd celeron55-minetest-286edd4 (or similar) - -Build a version that runs directly from the source directory: -$ cmake . -DRUN_IN_PLACE=1 -$ make -j2 - -Run it: -$ cd bin -$ ./minetest - -- Use cmake . -LH to see all CMake options and their current state -- If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0 -- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0 -- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE= - - Note that the Debug build is considerably slower - -Compiling on Windows: ---------------------- - -- You need: - * CMake: - http://www.cmake.org/cmake/resources/software.html - * MinGW or Visual Studio - http://www.mingw.org/ - http://msdn.microsoft.com/en-us/vstudio/default - * Irrlicht SDK 1.7: - http://irrlicht.sourceforge.net/downloads.html - * Zlib headers (zlib125.zip) - http://www.winimage.com/zLibDll/index.html - * Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip): - http://www.winimage.com/zLibDll/index.html - * And, of course, Minetest-c55: - http://celeron.55.lt/~celeron55/minetest/download -- Steps: - - Select a directory called DIR hereafter in which you will operate. - - Make sure you have CMake and a compiler installed. - - Download all the other stuff to DIR and extract them into there. All those - packages contain a nice base directory in them, which should end up being - the direct subdirectories of DIR. - - You will end up with a directory structure like this (+=dir, -=file): - ----------------- - + DIR - - zlib-1.2.5.tar.gz - - zlib125dll.zip - - irrlicht-1.7.1.zip - - 110214175330.zip (or whatever, this is the minetest source) - + zlib-1.2.5 - - zlib.h - + win32 - ... - + zlib125dll - - readme.txt - + dll32 - ... - + irrlicht-1.7.1 - + lib - + include - ... - + minetest - + src - + doc - - CMakeLists.txt - ... - ----------------- - - Start up the CMake GUI - - Select "Browse Source..." and select DIR/minetest - - Now, if using MSVC: - - Select "Browse Build..." and select DIR/minetest-build - - Else if using MinGW: - - Select "Browse Build..." and select DIR/minetest - - Select "Configure" - - Select your compiler - - It will warn about missing stuff, ignore that at this point. (later don't) - - Make sure the configuration is as follows - (note that the versions may differ for you): - ----------------- - BUILD_CLIENT [X] - BUILD_SERVER [ ] - CMAKE_BUILD_TYPE Release - CMAKE_INSTALL_PREFIX DIR/minetest-install - IRRLICHT_SOURCE_DIR DIR/irrlicht-1.7.1 - RUN_IN_PLACE [X] - WARN_ALL [ ] - ZLIB_DLL DIR/zlib125dll/dll32/zlibwapi.dll - ZLIB_INCLUDE_DIR DIR/zlib-1.2.5 - ZLIB_LIBRARIES DIR/zlib125dll/dll32/zlibwapi.lib - ----------------- - - Hit "Configure" - - Hit "Generate" - If using MSVC: - - Open the generated minetest.sln - - The project defaults to the "Debug" configuration. Make very sure to - select "Release", unless you want to debug some stuff (it's slower) - - Build the ALL_BUILD project - - Build the INSTALL project - - You should now have a working game with the executable in - DIR/minetest-install/bin/minetest.exe - - Additionally you may create a zip package by building the PACKAGE - project. - If using MinGW: - - Using the command line, browse to the build directory and run 'make' - (or mingw32-make or whatever it happens to be) - - You should now have a working game with the executable in - DIR/minetest/bin/minetest.exe - -Windows releases of minetest are built using a bat script like this: --------------------------------------------------------------------- - -set installpath="C:\tmp\minetest_install" -set irrlichtpath="C:\tmp\irrlicht-1.7.2" - -set sourcedir=%CD% -set builddir=%sourcedir%\bvc10 -mkdir %builddir% -pushd %builddir% -cmake %sourcedir% -G "Visual Studio 10" -DIRRLICHT_SOURCE_DIR=%irrlichtpath% -DRUN_IN_PLACE=1 -DCMAKE_INSTALL_PREFIX=%installpath% -"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" ALL_BUILD.vcxproj /p:Configuration=Release -"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" INSTALL.vcxproj /p:Configuration=Release -"C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" PACKAGE.vcxproj /p:Configuration=Release -popd - -License of Minetest-c55 ------------------------ - -Minetest-c55 -Copyright (C) 2010-2011 celeron55, Perttu Ahola - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Irrlicht ---------------- - -This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/ - - The Irrlicht Engine License - -Copyright © 2002-2005 Nikolaus Gebhardt - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source - distribution. - - -JThread ---------------- - -This program uses the JThread library. License for JThread follows: - -Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - - diff --git a/doc/changelog.txt b/doc/changelog.txt index b600345..b27fc50 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -3,17 +3,29 @@ Minetest-c55 changelog This should contain all the major changes. For minor stuff, refer to the commit log of the repository. +0.3.1: (released on 2011-11-09) +- Fix frustum culling (previous versions have rendered too much stuff that is not actually visible (about 180 degrees, while should have been more like 100.)) +- Add occlusion culling (improves performance a lot) +- Add “3d clouds” on/off checkbox in main menu +- Add “opaque water” on/off checkbox +- Fix some random minor stuff +- Turn mipmapping off (This makes far-away textures a bit noisier but better looking) +- Add Command-line signal handler for Windows (contributed by SpeedProg) +- Fix network layer segmentation fault introduced in 0.3.dev-20111021 +- Fix water-glass and water-lava and lava-glass surfaces + +0.3.0: (released on 2011-11-01) +- Some small fixes 0.3.dev-20111021: - Modify dungeon masters to only try to shoot players - Fix object duplication bug at block load/unload bug - Improve network layer - 0.3.dev-20111016: -- Locked chest +- Locked chest (contributed) - Server user limit setting (max_users) -- Wielded tool is shown in HUD -- View bobbing -- Saplings that drop from leaf blocks and when placed on ground will grow to trees +- Wielded tool is shown in HUD (contributed) +- View bobbing (contributed) +- Saplings that drop from leaf blocks and when placed on ground will grow to trees (contributed) - Optimized map saving (does not re-save everything all the time) - New mob system and new mob: dungeon master - Death/respawn screen diff --git a/src/client.cpp b/src/client.cpp index e2f9873..e379fc2 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -665,14 +665,13 @@ void Client::ReceiveAll() void Client::Receive() { DSTACK(__FUNCTION_NAME); - u32 data_maxsize = 200000; - Buffer data(data_maxsize); + SharedBuffer data; u16 sender_peer_id; u32 datasize; { //TimeTaker t1("con mutex and receive", m_device); //JMutexAutoLock lock(m_con_mutex); //bulk comment-out - datasize = m_con.Receive(sender_peer_id, *data, data_maxsize); + datasize = m_con.Receive(sender_peer_id, data); } //TimeTaker t1("ProcessData", m_device); ProcessData(*data, datasize, sender_peer_id); diff --git a/src/clouds.cpp b/src/clouds.cpp index 063a4b1..2324365 100644 --- a/src/clouds.cpp +++ b/src/clouds.cpp @@ -81,9 +81,9 @@ void Clouds::render() ScopeProfiler sp(g_profiler, "Rendering of clouds, avg", SPT_AVG); - int num_faces_to_draw = 6; - if(g_settings->getBool("enable_2d_clouds")) - num_faces_to_draw = 1; + int num_faces_to_draw = 1; + if(g_settings->getBool("enable_3d_clouds")) + num_faces_to_draw = 6; driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); driver->setMaterial(m_material); diff --git a/src/connection.cpp b/src/connection.cpp index cdf8cd3..b9c5d2a 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -670,7 +670,7 @@ void Connection::receive() // TODO: We can not know how many layers of header there are. // For now, just assume there are no other than the base headers. u32 packet_maxsize = datasize + BASE_HEADER_SIZE; - Buffer packetdata(packet_maxsize); + SharedBuffer packetdata(packet_maxsize); bool single_wait_done = false; @@ -1577,7 +1577,7 @@ void Connection::Disconnect() putCommand(c); } -u32 Connection::Receive(u16 &peer_id, u8 *data, u32 datasize) +u32 Connection::Receive(u16 &peer_id, SharedBuffer &data) { for(;;){ ConnectionEvent e = waitEvent(m_bc_receive_timeout); @@ -1589,7 +1589,7 @@ u32 Connection::Receive(u16 &peer_id, u8 *data, u32 datasize) throw NoIncomingDataException("No incoming data"); case CONNEVENT_DATA_RECEIVED: peer_id = e.peer_id; - memcpy(data, *e.data, e.data.getSize()); + data = SharedBuffer(e.data); return e.data.getSize(); case CONNEVENT_PEER_ADDED: { Peer tmp(e.peer_id, e.address); diff --git a/src/connection.h b/src/connection.h index 570bc92..6d26e2e 100644 --- a/src/connection.h +++ b/src/connection.h @@ -430,7 +430,7 @@ struct ConnectionEvent { enum ConnectionEventType type; u16 peer_id; - SharedBuffer data; + Buffer data; bool timeout; Address address; @@ -489,7 +489,7 @@ struct ConnectionCommand Address address; u16 peer_id; u8 channelnum; - SharedBuffer data; + Buffer data; bool reliable; ConnectionCommand(): type(CONNCMD_NONE) {} @@ -551,7 +551,7 @@ public: void Connect(Address address); bool Connected(); void Disconnect(); - u32 Receive(u16 &peer_id, u8 *data, u32 datasize); + u32 Receive(u16 &peer_id, SharedBuffer &data); void SendToAll(u8 channelnum, SharedBuffer data, bool reliable); void Send(u16 peer_id, u8 channelnum, SharedBuffer data, bool reliable); void RunTimeouts(float dtime); // dummy diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 559f750..5a2866b 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -446,6 +446,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data, assert(content_features(n).special_material); video::SMaterial &liquid_material = *content_features(n).special_material; + video::SMaterial &liquid_material_bfculled = + *content_features(n).special_material2; + assert(content_features(n).special_atlas); AtlasPointer &pa_liquid1 = *content_features(n).special_atlas; @@ -598,10 +601,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data, continue; content_t neighbor_content = neighbor_contents[dir]; + ContentFeatures &n_feat = content_features(neighbor_content); - // Don't draw face if neighbor is not air or liquid - if(neighbor_content != CONTENT_AIR - && content_liquid(neighbor_content) == false) + // Don't draw face if neighbor is blocking the view + if(n_feat.solidness == 2) continue; bool neighbor_is_same_liquid = (neighbor_content == c_source @@ -612,6 +615,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data, if(neighbor_is_same_liquid == true && top_is_same_liquid == false) continue; + + // Use backface culled material if neighbor doesn't have a + // solidness of 0 + video::SMaterial *current_material = &liquid_material; + if(n_feat.solidness != 0 || n_feat.visual_solidness != 0) + current_material = &liquid_material_bfculled; video::S3DVertex vertices[4] = { @@ -675,17 +684,17 @@ void mapblock_mesh_generate_special(MeshMakeData *data, // Do this to not cause glitches when two liquids are // side-by-side - if(neighbor_is_same_liquid == false){ + /*if(neighbor_is_same_liquid == false){ vertices[j].Pos.X *= 0.98; vertices[j].Pos.Z *= 0.98; - } + }*/ vertices[j].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector - collector.append(liquid_material, vertices, 4, indices, 6); + collector.append(*current_material, vertices, 4, indices, 6); } /* diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index ee3b333..9b4ff4b 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -107,6 +107,7 @@ void content_mapnode_init() bool new_style_water = g_settings->getBool("new_style_water"); bool new_style_leaves = g_settings->getBool("new_style_leaves"); bool invisible_stone = g_settings->getBool("invisible_stone"); + bool opaque_water = g_settings->getBool("opaque_water"); content_t i; ContentFeatures *f = NULL; @@ -398,7 +399,8 @@ void content_mapnode_init() f->liquid_alternative_source = CONTENT_WATERSOURCE; f->liquid_viscosity = WATER_VISC; #ifndef SERVER - f->vertex_alpha = WATER_ALPHA; + if(!opaque_water) + f->vertex_alpha = WATER_ALPHA; f->post_effect_color = video::SColor(64, 100, 100, 200); if(f->special_material == NULL && g_texturesource) { @@ -408,10 +410,17 @@ void content_mapnode_init() f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false); f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false); f->special_material->setFlag(video::EMF_FOG_ENABLE, true); - f->special_material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + if(!opaque_water) + f->special_material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; AtlasPointer *pa_water1 = new AtlasPointer(g_texturesource->getTexture( g_texturesource->getTextureId("water.png"))); f->special_material->setTexture(0, pa_water1->atlas); + + // Flowing water material, backface culled + f->special_material2 = new video::SMaterial; + *f->special_material2 = *f->special_material; + f->special_material2->setFlag(video::EMF_BACK_FACE_CULLING, true); + f->special_atlas = pa_water1; } #endif @@ -432,8 +441,10 @@ void content_mapnode_init() if(g_texturesource) t.texture = g_texturesource->getTexture("water.png"); - t.alpha = WATER_ALPHA; - t.material_type = MATERIAL_ALPHA_VERTEX; + if(!opaque_water){ + t.alpha = WATER_ALPHA; + t.material_type = MATERIAL_ALPHA_VERTEX; + } t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; f->setAllTiles(t); #endif @@ -450,11 +461,12 @@ void content_mapnode_init() f->liquid_alternative_source = CONTENT_WATERSOURCE; f->liquid_viscosity = WATER_VISC; #ifndef SERVER - f->vertex_alpha = WATER_ALPHA; + if(!opaque_water) + f->vertex_alpha = WATER_ALPHA; f->post_effect_color = video::SColor(64, 100, 100, 200); if(f->special_material == NULL && g_texturesource) { - // Flowing water material + // New-style water source material (mostly unused) f->special_material = new video::SMaterial; f->special_material->setFlag(video::EMF_LIGHTING, false); f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false); @@ -476,7 +488,7 @@ void content_mapnode_init() f->light_propagates = false; f->light_source = LIGHT_MAX-1; f->solidness = 0; // Drawn separately, makes no faces - f->visual_solidness = 2; + f->visual_solidness = 1; // Does not completely cover block boundaries f->walkable = false; f->pointable = false; f->diggable = false; @@ -497,10 +509,17 @@ void content_mapnode_init() f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false); f->special_material->setFlag(video::EMF_FOG_ENABLE, true); f->special_material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + AtlasPointer *pa_lava1 = new AtlasPointer( g_texturesource->getTexture( g_texturesource->getTextureId("lava.png"))); f->special_material->setTexture(0, pa_lava1->atlas); + + // Flowing lava material, backface culled + f->special_material2 = new video::SMaterial; + *f->special_material2 = *f->special_material; + f->special_material2->setFlag(video::EMF_BACK_FACE_CULLING, true); + f->special_atlas = pa_lava1; } #endif @@ -544,7 +563,7 @@ void content_mapnode_init() f->post_effect_color = video::SColor(192, 255, 64, 0); if(f->special_material == NULL && g_texturesource) { - // Flowing lava material + // New-style lava source material (mostly unused) f->special_material = new video::SMaterial; f->special_material->setFlag(video::EMF_LIGHTING, false); f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false); @@ -555,6 +574,7 @@ void content_mapnode_init() g_texturesource->getTexture( g_texturesource->getTextureId("lava.png"))); f->special_material->setTexture(0, pa_lava1->atlas); + f->special_atlas = pa_lava1; } #endif diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index bfc50db..c735d5a 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -46,6 +46,7 @@ void set_default_settings(Settings *settings) settings->setDefault("keymap_screenshot", "KEY_F12"); settings->setDefault("keymap_toggle_profiler", "KEY_F2"); settings->setDefault("keymap_toggle_force_fog_off", "KEY_F3"); + settings->setDefault("keymap_toggle_update_camera", "KEY_F4"); // Some (temporary) keys for debugging settings->setDefault("keymap_print_debug_stacks", "KEY_KEY_P"); @@ -62,7 +63,7 @@ void set_default_settings(Settings *settings) settings->setDefault("fov", "72"); settings->setDefault("view_bobbing", "true"); settings->setDefault("new_style_water", "false"); - settings->setDefault("new_style_leaves", "true"); + settings->setDefault("new_style_leaves", "false"); settings->setDefault("smooth_lighting", "true"); settings->setDefault("frametime_graph", "false"); settings->setDefault("enable_texture_atlas", "true"); @@ -77,7 +78,8 @@ void set_default_settings(Settings *settings) settings->setDefault("invisible_stone", "false"); settings->setDefault("screenshot_path", "."); settings->setDefault("view_bobbing_amount", "1.0"); - settings->setDefault("enable_2d_clouds", "false"); + settings->setDefault("enable_3d_clouds", "false"); + settings->setDefault("opaque_water", "false"); // Server stuff // "map-dir" doesn't exist by default. diff --git a/src/game.cpp b/src/game.cpp index baad032..7e7300e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -956,11 +956,11 @@ void the_game( //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0)); core::list chat_lines; - // Profiler text + // Profiler text (size is updated when text is updated) gui::IGUIStaticText *guitext_profiler = guienv->addStaticText( L"", - core::rect(6, 4+(text_height+5)*3, 400, - (text_height+5)*3 + text_height*35), + core::rect(6, 4+(text_height+5)*2, 400, + (text_height+5)*2 + text_height*35), false, false); guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0)); guitext_profiler->setVisible(false); @@ -1019,8 +1019,8 @@ void the_game( bool respawn_menu_active = false; bool show_profiler = false; - bool force_fog_off = false; + bool disable_camera_update = false; /* Main loop @@ -1259,9 +1259,18 @@ void the_game( std::ostringstream os(std::ios_base::binary); g_profiler->print(os); - guitext_profiler->setText(narrow_to_wide(os.str()).c_str()); + std::wstring text = narrow_to_wide(os.str()); + guitext_profiler->setText(text.c_str()); g_profiler->clear(); + + s32 w = font->getDimension(text.c_str()).Width; + if(w < 400) + w = 400; + core::rect rect(6, 4+(text_height+5)*2, 12+w, + 8+(text_height+5)*2 + + font->getDimension(text.c_str()).Height); + guitext_profiler->setRelativePosition(rect); } /* @@ -1395,10 +1404,26 @@ void the_game( { show_profiler = !show_profiler; guitext_profiler->setVisible(show_profiler); + if(show_profiler) + chat_lines.push_back(ChatLine(L"Profiler disabled")); + else + chat_lines.push_back(ChatLine(L"Profiler enabled")); } else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off"))) { force_fog_off = !force_fog_off; + if(force_fog_off) + chat_lines.push_back(ChatLine(L"Fog disabled")); + else + chat_lines.push_back(ChatLine(L"Fog enabled")); + } + else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera"))) + { + disable_camera_update = !disable_camera_update; + if(disable_camera_update) + chat_lines.push_back(ChatLine(L"Camera update disabled")); + else + chat_lines.push_back(ChatLine(L"Camera update enabled")); } // Item selection with mouse wheel @@ -1645,11 +1670,10 @@ void the_game( v3f camera_direction = camera.getDirection(); f32 camera_fov = camera.getFovMax(); - if(FIELD_OF_VIEW_TEST) - client.updateCamera(v3f(0,0,0), v3f(0,0,1), camera_fov); - else + if(!disable_camera_update){ client.updateCamera(camera_position, camera_direction, camera_fov); + } //timer2.stop(); //TimeTaker //timer3("//timer3"); @@ -2566,4 +2590,3 @@ void the_game( } } - diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp index cf9b8ed..43ec85c 100644 --- a/src/guiMainMenu.cpp +++ b/src/guiMainMenu.cpp @@ -80,6 +80,8 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) bool enable_damage; bool fancy_trees; bool smooth_lighting; + bool clouds_3d; + bool opaque_water; // Client options { @@ -117,6 +119,20 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) else smooth_lighting = m_data->smooth_lighting; } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB); + if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) + clouds_3d = ((gui::IGUICheckBox*)e)->isChecked(); + else + clouds_3d = m_data->clouds_3d; + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB); + if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) + opaque_water = ((gui::IGUICheckBox*)e)->isChecked(); + else + opaque_water = m_data->opaque_water; + } // Server options { @@ -242,10 +258,22 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) } { core::rect rect(0, 0, 250, 30); - rect += topleft_client + v2s32(35, 150+30); + rect += topleft_client + v2s32(35, 150+20); Environment->addCheckBox(smooth_lighting, rect, this, GUI_ID_SMOOTH_LIGHTING_CB, wgettext("Smooth Lighting")); } + { + core::rect rect(0, 0, 250, 30); + rect += topleft_client + v2s32(35, 150+40); + Environment->addCheckBox(clouds_3d, rect, this, GUI_ID_3D_CLOUDS_CB, + wgettext("3D Clouds")); + } + { + core::rect rect(0, 0, 250, 30); + rect += topleft_client + v2s32(35, 150+60); + Environment->addCheckBox(opaque_water, rect, this, GUI_ID_OPAQUE_WATER_CB, + wgettext("Opaque water")); + } // Start game button { core::rect rect(0, 0, 180, 30); @@ -362,15 +390,25 @@ void GUIMainMenu::acceptInput() if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->enable_damage = ((gui::IGUICheckBox*)e)->isChecked(); } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB); + if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) + m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); + } { gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked(); } { - gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB); + gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) - m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); + m_data->clouds_3d = ((gui::IGUICheckBox*)e)->isChecked(); + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB); + if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) + m_data->opaque_water = ((gui::IGUICheckBox*)e)->isChecked(); } m_accepted = true; diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h index 87561f7..ba2fc6b 100644 --- a/src/guiMainMenu.h +++ b/src/guiMainMenu.h @@ -35,6 +35,8 @@ enum GUI_ID_PORT_INPUT, GUI_ID_FANCYTREE_CB, GUI_ID_SMOOTH_LIGHTING_CB, + GUI_ID_3D_CLOUDS_CB, + GUI_ID_OPAQUE_WATER_CB, GUI_ID_DAMAGE_CB, GUI_ID_CREATIVE_CB, GUI_ID_JOIN_GAME_BUTTON, @@ -64,6 +66,8 @@ struct MainMenuData std::wstring password; bool fancy_trees; bool smooth_lighting; + bool clouds_3d; + bool opaque_water; // Server options bool creative_mode; bool enable_damage; diff --git a/src/main.cpp b/src/main.cpp index bc44775..b959d8c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1407,6 +1407,21 @@ int main(int argc, char *argv[]) if (device == 0) return 1; // could not create selected driver. + /* + Continue initialization + */ + + video::IVideoDriver* driver = device->getVideoDriver(); + + // Disable mipmaps (because some of them look ugly) + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + /* + This changes the minimum allowed number of vertices in a VBO. + Default is 500. + */ + //driver->setMinHardwareBufferVertexCount(50); + // Set the window caption device->setWindowCaption(L"Minetest [Main Menu]"); @@ -1439,18 +1454,6 @@ int main(int argc, char *argv[]) else input = new RealInputHandler(device, &receiver); - /* - Continue initialization - */ - - //video::IVideoDriver* driver = device->getVideoDriver(); - - /* - This changes the minimum allowed number of vertices in a VBO. - Default is 500. - */ - //driver->setMinHardwareBufferVertexCount(50); - scene::ISceneManager* smgr = device->getSceneManager(); guienv = device->getGUIEnvironment(); @@ -1543,6 +1546,8 @@ int main(int argc, char *argv[]) menudata.port = narrow_to_wide(itos(port)); menudata.fancy_trees = g_settings->getBool("new_style_leaves"); menudata.smooth_lighting = g_settings->getBool("smooth_lighting"); + menudata.clouds_3d = g_settings->getBool("enable_3d_clouds"); + menudata.opaque_water = g_settings->getBool("opaque_water"); menudata.creative_mode = g_settings->getBool("creative_mode"); menudata.enable_damage = g_settings->getBool("enable_damage"); @@ -1615,6 +1620,8 @@ int main(int argc, char *argv[]) port = newport; g_settings->set("new_style_leaves", itos(menudata.fancy_trees)); g_settings->set("smooth_lighting", itos(menudata.smooth_lighting)); + g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d)); + g_settings->set("opaque_water", itos(menudata.opaque_water)); g_settings->set("creative_mode", itos(menudata.creative_mode)); g_settings->set("enable_damage", itos(menudata.enable_damage)); diff --git a/src/map.cpp b/src/map.cpp index 92c1694..7985b11 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3649,6 +3649,35 @@ void ClientMap::OnRegisterSceneNode() ISceneNode::OnRegisterSceneNode(); } +static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac, + float start_off, float end_off, u32 needed_count) +{ + float d0 = (float)BS * p0.getDistanceFrom(p1); + v3s16 u0 = p1 - p0; + v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS; + uf.normalize(); + v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS; + u32 count = 0; + for(float s=start_off; sgetNodeNoEx(p); + bool is_transparent = false; + ContentFeatures &f = content_features(n); + if(f.solidness == 0) + is_transparent = (f.visual_solidness != 2); + else + is_transparent = (f.solidness != 2); + if(!is_transparent){ + count++; + if(count >= needed_count) + return true; + } + step *= stepfac; + } + return false; +} + void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) { //m_dout<::Iterator si; - si = m_sectors.getIterator(); - for(; si.atEnd() == false; si++) - { - { - timecheck_counter++; - if(timecheck_counter > 50) - { - timecheck_counter = 0; - int time2 = time(0); - if(time2 > time1 + 4) - { - infostream<<"ClientMap::renderMap(): " - "Rendering takes ages, returning." - < drawset; + { + ScopeProfiler sp(g_profiler, prefix+"collecting blocks for drawing", SPT_AVG); + + for(core::map::Iterator + si = m_sectors.getIterator(); + si.atEnd() == false; si++) + { MapSector *sector = si.getNode()->getValue(); v2s16 sp = sector->getPos(); @@ -3762,11 +3788,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) sector->getBlocks(sectorblocks); /* - Draw blocks + Loop through blocks in sector */ - - u32 sector_blocks_drawn = 0; + u32 sector_blocks_drawn = 0; + core::list< MapBlock * >::Iterator i; for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++) { @@ -3780,7 +3806,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) float range = 100000 * BS; if(m_control.range_all == false) range = m_control.wanted_range * BS; - + float d = 0.0; if(isBlockInSight(block->getPos(), camera_position, camera_direction, camera_fov, @@ -3789,16 +3815,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) continue; } - // Okay, this block will be drawn. Reset usage timer. - block->resetUsageTimer(); - // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && d - 0.5*BS*MAP_BLOCKSIZE > range) continue;*/ - - blocks_in_range++; + blocks_in_range++; + #if 1 /* Update expired mesh (used for day/night change) @@ -3848,10 +3871,51 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) mesh_expired = false; } - #endif + /* - Draw the faces of the block + Occlusion culling + */ + + v3s16 cpn = block->getPos() * MAP_BLOCKSIZE; + cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2); + float step = BS*1; + float stepfac = 1.1; + float startoff = BS*1; + float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42; + v3s16 spn = cam_pos_nodes + v3s16(0,0,0); + s16 bs2 = MAP_BLOCKSIZE/2 + 1; + u32 needed_count = 1; + if( + isOccluded(this, spn, cpn + v3s16(0,0,0), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2), + step, stepfac, startoff, endoff, needed_count) && + isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2), + step, stepfac, startoff, endoff, needed_count) + ) + { + blocks_occlusion_culled++; + continue; + } + + // This block is in range. Reset usage timer. + block->resetUsageTimer(); + + /* + Ignore if mesh doesn't exist */ { JMutexAutoLock lock(block->mesh_mutex); @@ -3862,72 +3926,112 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) blocks_in_range_without_mesh++; 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++; - sector_blocks_drawn++; - - u32 c = mesh->getMeshBufferCount(); - bool stuff_actually_drawn = false; - for(u32 i=0; igetMeshBuffer(i); - const video::SMaterial& material = buf->getMaterial(); - video::IMaterialRenderer* rnd = - driver->getMaterialRenderer(material.MaterialType); - bool transparent = (rnd && rnd->isTransparent()); - // Render transparent on transparent pass and likewise. - if(transparent == is_transparent_pass) - { - if(buf->getVertexCount() == 0) - errorstream<<"Block ["<setMaterial(buf->getMaterial()); - driver->drawMeshBuffer(buf); - vertex_count += buf->getVertexCount(); - meshbuffer_count++; - stuff_actually_drawn = true; - } - } - if(stuff_actually_drawn) - blocks_had_pass_meshbuf++; - else - blocks_without_stuff++; } + + // Limit block count in case of a sudden increase + 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; + + // Add to set + drawset[block->getPos()] = block; + + sector_blocks_drawn++; + blocks_drawn++; + } // foreach sectorblocks if(sector_blocks_drawn != 0) - { m_last_drawn_sectors[sp] = true; + } + } // ScopeProfiler + + /* + Draw the selected MapBlocks + */ + + { + ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG); + + int timecheck_counter = 0; + for(core::map::Iterator + i = drawset.getIterator(); + i.atEnd() == false; i++) + { + { + timecheck_counter++; + if(timecheck_counter > 50) + { + timecheck_counter = 0; + int time2 = time(0); + if(time2 > time1 + 4) + { + infostream<<"ClientMap::renderMap(): " + "Rendering takes ages, returning." + <getValue(); + + /* + Draw the faces of the block + */ + { + JMutexAutoLock lock(block->mesh_mutex); + + scene::SMesh *mesh = block->mesh; + assert(mesh); + + u32 c = mesh->getMeshBufferCount(); + bool stuff_actually_drawn = false; + for(u32 i=0; igetMeshBuffer(i); + const video::SMaterial& material = buf->getMaterial(); + video::IMaterialRenderer* rnd = + driver->getMaterialRenderer(material.MaterialType); + bool transparent = (rnd && rnd->isTransparent()); + // Render transparent on transparent pass and likewise. + if(transparent == is_transparent_pass) + { + if(buf->getVertexCount() == 0) + errorstream<<"Block ["<setMaterial(buf->getMaterial()); + driver->drawMeshBuffer(buf); + vertex_count += buf->getVertexCount(); + meshbuffer_count++; + stuff_actually_drawn = true; + } + } + if(stuff_actually_drawn) + blocks_had_pass_meshbuf++; + else + blocks_without_stuff++; } } + } // ScopeProfiler - std::string prefix = "CM: "; - // Log only on solid pass because values are the same if(pass == scene::ESNRP_SOLID){ - g_profiler->avg(prefix+"blocks in range", blocks_in_range); + g_profiler->avg("CM: blocks in range", blocks_in_range); + g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled); if(blocks_in_range != 0) - g_profiler->avg(prefix+"blocks in range without mesh (frac)", + g_profiler->avg("CM: blocks in range without mesh (frac)", (float)blocks_in_range_without_mesh/blocks_in_range); - g_profiler->avg(prefix+"blocks drawn", blocks_drawn); + g_profiler->avg("CM: blocks drawn", blocks_drawn); } - if(pass == scene::ESNRP_SOLID) - prefix = "CM: solid: "; - else - prefix = "CM: transparent: "; - g_profiler->avg(prefix+"vertices drawn", vertex_count); if(blocks_had_pass_meshbuf != 0) g_profiler->avg(prefix+"meshbuffers per block", diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index 7ee4998..5a29fbe 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -427,7 +427,8 @@ void getTileInfo( // This is hackish content_t content0 = getNodeContent(p, n0, temp_mods); content_t content1 = getNodeContent(p + face_dir, n1, temp_mods); - u8 mf = face_contents(content0, content1); + bool equivalent = false; + u8 mf = face_contents(content0, content1, &equivalent); if(mf == 0) { @@ -450,6 +451,10 @@ void getTileInfo( face_dir_corrected = -face_dir; } + // eg. water and glass + if(equivalent) + tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; + if(smooth_lighting == false) { lights[0] = lights[1] = lights[2] = lights[3] = diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 982093d..382d3c3 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -168,6 +168,9 @@ void init_mapnode() f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; } + // Make CONTENT_IGNORE to not block the view when occlusion culling + content_features(CONTENT_IGNORE).solidness = 0; + /* Initialize mapnode content */ @@ -175,6 +178,57 @@ void init_mapnode() } +/* + Nodes make a face if contents differ and solidness differs. + Return value: + 0: No face + 1: Face uses m1's content + 2: Face uses m2's content + equivalent: Whether the blocks share the same face (eg. water and glass) +*/ +u8 face_contents(content_t m1, content_t m2, bool *equivalent) +{ + *equivalent = false; + + if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE) + return 0; + + bool contents_differ = (m1 != m2); + + // Contents don't differ for different forms of same liquid + if(content_liquid(m1) && content_liquid(m2) + && make_liquid_flowing(m1) == make_liquid_flowing(m2)) + contents_differ = false; + + u8 c1 = content_solidness(m1); + u8 c2 = content_solidness(m2); + + bool solidness_differs = (c1 != c2); + bool makes_face = contents_differ && solidness_differs; + + if(makes_face == false) + return 0; + + if(c1 == 0) + c1 = content_features(m1).visual_solidness; + if(c2 == 0) + c2 = content_features(m2).visual_solidness; + + if(c1 == c2){ + *equivalent = true; + // If same solidness, liquid takes precense + if(content_features(m1).liquid_type != LIQUID_NONE) + return 1; + if(content_features(m2).liquid_type != LIQUID_NONE) + return 2; + } + + if(c1 > c2) + return 1; + else + return 2; +} + v3s16 facedir_rotate(u8 facedir, v3s16 dir) { /* diff --git a/src/mapnode.h b/src/mapnode.h index fb72443..51bee05 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -121,6 +121,7 @@ struct ContentFeatures video::SColor post_effect_color; // Special irrlicht material, used sometimes video::SMaterial *special_material; + video::SMaterial *special_material2; AtlasPointer *special_atlas; #endif @@ -199,6 +200,7 @@ struct ContentFeatures vertex_alpha = 255; post_effect_color = video::SColor(0, 0, 0, 0); special_material = NULL; + special_material2 = NULL; special_atlas = NULL; #endif param_type = CPT_NONE; @@ -377,30 +379,9 @@ inline bool content_buildable_to(content_t m) 0: No face 1: Face uses m1's content 2: Face uses m2's content + equivalent: Whether the blocks share the same face (eg. water and glass) */ -inline u8 face_contents(content_t m1, content_t m2) -{ - if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE) - return 0; - - bool contents_differ = (m1 != m2); - - // Contents don't differ for different forms of same liquid - if(content_liquid(m1) && content_liquid(m2) - && make_liquid_flowing(m1) == make_liquid_flowing(m2)) - contents_differ = false; - - bool solidness_differs = (content_solidness(m1) != content_solidness(m2)); - bool makes_face = contents_differ && solidness_differs; - - if(makes_face == false) - return 0; - - if(content_solidness(m1) > content_solidness(m2)) - return 1; - else - return 2; -} +u8 face_contents(content_t m1, content_t m2, bool *equivalent); /* Packs directions like (1,0,0), (1,-1,0) diff --git a/src/porting.cpp b/src/porting.cpp index 217f092..f3a0ab0 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -75,10 +75,45 @@ void signal_handler_init(void) } #else // _WIN32 + #include + #include + + BOOL WINAPI event_handler(DWORD sig) + { + switch(sig) + { + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + if(g_killed == false) + { + dstream< data(data_maxsize); + SharedBuffer data; u16 peer_id; u32 datasize; try{ { JMutexAutoLock conlock(m_con_mutex); - datasize = m_con.Receive(peer_id, *data, data_maxsize); + datasize = m_con.Receive(peer_id, data); } // This has to be called so that the client list gets synced @@ -4808,8 +4807,7 @@ v3f findSpawnPos(ServerMap &map) { //return v3f(50,50,50)*BS; - v2s16 nodepos; - s16 groundheight = 0; + v3s16 nodepos; #if 0 nodepos = v2s16(0,0); @@ -4822,13 +4820,11 @@ v3f findSpawnPos(ServerMap &map) { s32 range = 1 + i; // We're going to try to throw the player to this position - nodepos = v2s16(-range + (myrand()%(range*2)), + v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)), -range + (myrand()%(range*2))); - v2s16 sectorpos = getNodeSectorPos(nodepos); - // Get sector (NOTE: Don't get because it's slow) - //m_env.getMap().emergeSector(sectorpos); + //v2s16 sectorpos = getNodeSectorPos(nodepos2d); // Get ground height at point (fallbacks to heightmap function) - groundheight = map.findGroundLevel(nodepos); + s16 groundheight = map.findGroundLevel(nodepos2d); // Don't go underwater if(groundheight < WATER_LEVEL) { @@ -4841,22 +4837,33 @@ v3f findSpawnPos(ServerMap &map) //infostream<<"-> Underwater"<= 2){ + is_good = true; + nodepos.Y -= 1; + break; + } + } + nodepos.Y++; + } + if(is_good){ + // Found a good place + //infostream<<"Searched through "< data; infostream<<"** running client.Receive()"< recvdata; infostream<<"** running server.Receive()"< data1 = SharedBufferFromString("hello1"); @@ -983,29 +987,29 @@ struct TestConnection infostream<<"*** Receiving the packets"< recvdata; u32 size; infostream<<"** running client.Receive()"< 5000) break; try{ - size = client.Receive(peer_id, recvdata, datasize + 1000); + size = client.Receive(peer_id, recvdata); received = true; }catch(con::NoIncomingDataException &e){ } @@ -1071,13 +1116,13 @@ struct TestConnection infostream<<"Received data (size="<20) infostream<<"..."; infostream< block_max_radius) - { - // Cosine of the angle between the camera direction - // and the block direction (camera_dir is an unit vector) - f32 cosangle = dforward / d; - - // Compensate for the size of the block - // (as the block has to be shown even if it's a bit off FOV) - // This is an estimate. - cosangle += block_max_radius / dforward; + if(d < block_max_radius) + return true; + + // Cosine of the angle between the camera direction + // and the block direction (camera_dir is an unit vector) + f32 cosangle = dforward / d; + + // Compensate for the size of the block + // (as the block has to be shown even if it's a bit off FOV) + // This is an estimate, plus an arbitary factor + cosangle += block_max_radius / d * 0.5; - // If block is not in the field of view, skip it - if(cosangle < cos(camera_fov / 2)) - return false; - } + // If block is not in the field of view, skip it + if(cosangle < cos(camera_fov / 2)) + return false; return true; } diff --git a/src/utility.h b/src/utility.h index c08ce1c..1c32253 100644 --- a/src/utility.h +++ b/src/utility.h @@ -222,13 +222,13 @@ inline u16 readU16(std::istream &is) return readU16((u8*)buf); } -inline void writeU32(std::ostream &os, u16 p) +inline void writeU32(std::ostream &os, u32 p) { char buf[4]; writeU16((u8*)buf, p); os.write(buf, 4); } -inline u16 readU32(std::istream &is) +inline u32 readU32(std::istream &is) { char buf[4]; is.read(buf, 4); @@ -343,26 +343,59 @@ template class Buffer { public: + Buffer() + { + m_size = 0; + data = NULL; + } Buffer(unsigned int size) { m_size = size; - data = new T[size]; + if(size != 0) + data = new T[size]; + else + data = NULL; } Buffer(const Buffer &buffer) { m_size = buffer.m_size; - data = new T[buffer.m_size]; - memcpy(data, buffer.data, buffer.m_size); + if(m_size != 0) + { + data = new T[buffer.m_size]; + memcpy(data, buffer.data, buffer.m_size); + } + else + data = NULL; } Buffer(T *t, unsigned int size) { m_size = size; - data = new T[size]; - memcpy(data, t, size); + if(size != 0) + { + data = new T[size]; + memcpy(data, t, size); + } + else + data = NULL; } ~Buffer() { - delete[] data; + drop(); + } + Buffer& operator=(const Buffer &buffer) + { + if(this == &buffer) + return *this; + drop(); + m_size = buffer.m_size; + if(m_size != 0) + { + data = new T[buffer.m_size]; + memcpy(data, buffer.data, buffer.m_size); + } + else + data = NULL; + return *this; } T & operator[](unsigned int i) const { @@ -377,6 +410,11 @@ public: return m_size; } private: + void drop() + { + if(data) + delete[] data; + } T *data; unsigned int m_size; }; @@ -471,6 +509,10 @@ public: { return m_size; } + operator Buffer() const + { + return Buffer(data, m_size); + } private: void drop() {