Add meshgen tests

This commit is contained in:
numzero 2023-12-17 18:03:14 +03:00 committed by rubenwardy
parent 753f03ff6a
commit 0d30a3071a
2 changed files with 269 additions and 0 deletions

@ -44,6 +44,7 @@ set (UNITTEST_SRCS
set (UNITTEST_CLIENT_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/mesh_compare.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_clientactiveobjectmgr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_content_mapblock.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_eventmanager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_gameui.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_mesh_compare.cpp

@ -0,0 +1,268 @@
/*
Minetest
Copyright (C) 2023 Vitaliy Lobachevskiy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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.
*/
#include "test.h"
#include <algorithm>
#include <numeric>
#include "gamedef.h"
#include "dummygamedef.h"
#include "client/content_mapblock.h"
#include "client/mapblock_mesh.h"
#include "client/meshgen/collector.h"
#include "mesh_compare.h"
#include "util/directiontables.h"
namespace {
class MockGameDef : public DummyGameDef {
public:
IWritableItemDefManager *item_mgr() noexcept {
return static_cast<IWritableItemDefManager *>(m_itemdef);
}
NodeDefManager *node_mgr() noexcept {
return const_cast<NodeDefManager *>(m_nodedef);
}
content_t registerNode(ItemDefinition itemdef, ContentFeatures nodedef) {
item_mgr()->registerItem(itemdef);
return node_mgr()->set(nodedef.name, nodedef);
}
void finalize() {
node_mgr()->resolveCrossrefs();
}
MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true, bool for_shaders = true)
{
MeshMakeData data{ndef(), 1, for_shaders};
data.setSmoothLighting(smooth_lighting);
data.m_blockpos = {0, 0, 0};
for (s16 x = -1; x <= 1; x++)
for (s16 y = -1; y <= 1; y++)
for (s16 z = -1; z <= 1; z++)
data.m_vmanip.setNode({x, y, z}, {CONTENT_AIR, 0, 0});
return data;
}
content_t addSimpleNode(std::string name, u32 texture)
{
ItemDefinition itemdef;
itemdef.type = ITEM_NODE;
itemdef.name = "test:" + name;
itemdef.description = name;
ContentFeatures f;
f.name = itemdef.name;
f.drawtype = NDT_NORMAL;
f.solidness = 2;
f.alpha = ALPHAMODE_OPAQUE;
for (TileDef &tiledef : f.tiledef)
tiledef.name = name + ".png";
for (TileSpec &tile : f.tiles)
tile.layers[0].texture_id = texture;
return registerNode(itemdef, f);
}
content_t addLiquidSource(std::string name, u32 texture)
{
ItemDefinition itemdef;
itemdef.type = ITEM_NODE;
itemdef.name = "test:" + name + "_source";
itemdef.description = name;
ContentFeatures f;
f.name = itemdef.name;
f.drawtype = NDT_LIQUID;
f.solidness = 1;
f.alpha = ALPHAMODE_BLEND;
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.liquid_type = LIQUID_SOURCE;
f.liquid_viscosity = 4;
f.groups["liquids"] = 3;
f.liquid_alternative_source = "test:" + name + "_source";
f.liquid_alternative_flowing = "test:" + name + "_flowing";
for (TileDef &tiledef : f.tiledef)
tiledef.name = name + ".png";
for (TileSpec &tile : f.tiles)
tile.layers[0].texture_id = texture;
return registerNode(itemdef, f);
}
content_t addLiquidFlowing(std::string name, u32 texture_top, u32 texture_side)
{
ItemDefinition itemdef;
itemdef.type = ITEM_NODE;
itemdef.name = "test:" + name + "_flowing";
itemdef.description = name;
ContentFeatures f;
f.name = itemdef.name;
f.drawtype = NDT_FLOWINGLIQUID;
f.solidness = 0;
f.alpha = ALPHAMODE_BLEND;
f.light_propagates = true;
f.param_type = CPT_LIGHT;
f.liquid_type = LIQUID_FLOWING;
f.liquid_viscosity = 4;
f.groups["liquids"] = 3;
f.liquid_alternative_source = "test:" + name + "_source";
f.liquid_alternative_flowing = "test:" + name + "_flowing";
f.tiledef_special[0].name = name + "_top.png";
f.tiledef_special[1].name = name + "_side.png";
f.special_tiles[0].layers[0].texture_id = texture_top;
f.special_tiles[1].layers[0].texture_id = texture_side;
return registerNode(itemdef, f);
}
};
void set_light_decode_table()
{
u8 table[LIGHT_SUN + 1] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
};
memcpy(const_cast<u8 *>(light_decode_table), table, sizeof(table));
}
class TestMapblockMeshGenerator : public TestBase {
public:
TestMapblockMeshGenerator() { TestManager::registerTestModule(this); }
const char *getName() override { return "TestMapblockMeshGenerator"; }
void runTests(IGameDef *gamedef) override;
void testSimpleNode();
void testSurroundedNode();
void testInterliquidSame();
void testInterliquidDifferent();
};
static TestMapblockMeshGenerator g_test_instance;
void TestMapblockMeshGenerator::runTests(IGameDef *gamedef)
{
set_light_decode_table();
TEST(testSimpleNode);
TEST(testSurroundedNode);
TEST(testInterliquidSame);
TEST(testInterliquidDifferent);
}
namespace quad {
constexpr float h = BS / 2.0f;
const Quad zp{{{{-h, -h, h}, {0, 0, 1}, 0, {1, 1}}, {{h, -h, h}, {0, 0, 1}, 0, {0, 1}}, {{h, h, h}, {0, 0, 1}, 0, {0, 0}}, {{-h, h, h}, {0, 0, 1}, 0, {1, 0}}}};
const Quad yp{{{{-h, h, -h}, {0, 1, 0}, 0, {0, 1}}, {{-h, h, h}, {0, 1, 0}, 0, {0, 0}}, {{h, h, h}, {0, 1, 0}, 0, {1, 0}}, {{h, h, -h}, {0, 1, 0}, 0, {1, 1}}}};
const Quad xp{{{{h, -h, -h}, {1, 0, 0}, 0, {0, 1}}, {{h, h, -h}, {1, 0, 0}, 0, {0, 0}}, {{h, h, h}, {1, 0, 0}, 0, {1, 0}}, {{h, -h, h}, {1, 0, 0}, 0, {1, 1}}}};
const Quad zn{{{{-h, -h, -h}, {0, 0, -1}, 0, {0, 1}}, {{-h, h, -h}, {0, 0, -1}, 0, {0, 0}}, {{h, h, -h}, {0, 0, -1}, 0, {1, 0}}, {{h, -h, -h}, {0, 0, -1}, 0, {1, 1}}}};
const Quad yn{{{{-h, -h, -h}, {0, -1, 0}, 0, {0, 0}}, {{h, -h, -h}, {0, -1, 0}, 0, {1, 0}}, {{h, -h, h}, {0, -1, 0}, 0, {1, 1}}, {{-h, -h, h}, {0, -1, 0}, 0, {0, 1}}}};
const Quad xn{{{{-h, -h, -h}, {-1, 0, 0}, 0, {1, 1}}, {{-h, -h, h}, {-1, 0, 0}, 0, {0, 1}}, {{-h, h, h}, {-1, 0, 0}, 0, {0, 0}}, {{-h, h, -h}, {-1, 0, 0}, 0, {1, 0}}}};
}
void TestMapblockMeshGenerator::testSimpleNode()
{
MockGameDef gamedef;
content_t stone = gamedef.addSimpleNode("stone", 42);
gamedef.finalize();
MeshMakeData data = gamedef.makeSingleNodeMMD();
data.m_vmanip.setNode({0, 0, 0}, {stone, 0, 0});
MeshCollector col{{}};
MapblockMeshGenerator mg{&data, &col, nullptr};
mg.generate();
UASSERTEQ(std::size_t, col.prebuffers[0].size(), 1);
UASSERTEQ(std::size_t, col.prebuffers[1].size(), 0);
auto &&buf = col.prebuffers[0][0];
UASSERTEQ(u32, buf.layer.texture_id, 42);
UASSERT(checkMeshEqual(buf.vertices, buf.indices, {quad::xn, quad::xp, quad::yn, quad::yp, quad::zn, quad::zp}));
}
void TestMapblockMeshGenerator::testSurroundedNode()
{
MockGameDef gamedef;
content_t stone = gamedef.addSimpleNode("stone", 42);
content_t wood = gamedef.addSimpleNode("wood", 13);
gamedef.finalize();
MeshMakeData data = gamedef.makeSingleNodeMMD();
data.m_vmanip.setNode({0, 0, 0}, {stone, 0, 0});
data.m_vmanip.setNode({1, 0, 0}, {wood, 0, 0});
MeshCollector col{{}};
MapblockMeshGenerator mg{&data, &col, nullptr};
mg.generate();
UASSERTEQ(std::size_t, col.prebuffers[0].size(), 1);
UASSERTEQ(std::size_t, col.prebuffers[1].size(), 0);
auto &&buf = col.prebuffers[0][0];
UASSERTEQ(u32, buf.layer.texture_id, 42);
UASSERT(checkMeshEqual(buf.vertices, buf.indices, {quad::xn, quad::yn, quad::yp, quad::zn, quad::zp}));
}
void TestMapblockMeshGenerator::testInterliquidSame()
{
MockGameDef gamedef;
auto water = gamedef.addLiquidSource("water", 42);
gamedef.finalize();
MeshMakeData data = gamedef.makeSingleNodeMMD();
data.m_vmanip.setNode({0, 0, 0}, {water, 0, 0});
data.m_vmanip.setNode({1, 0, 0}, {water, 0, 0});
MeshCollector col{{}};
MapblockMeshGenerator mg{&data, &col, nullptr};
mg.generate();
UASSERTEQ(std::size_t, col.prebuffers[0].size(), 1);
UASSERTEQ(std::size_t, col.prebuffers[1].size(), 0);
auto &&buf = col.prebuffers[0][0];
UASSERTEQ(u32, buf.layer.texture_id, 42);
UASSERT(checkMeshEqual(buf.vertices, buf.indices, {quad::xn, quad::yn, quad::yp, quad::zn, quad::zp}));
}
void TestMapblockMeshGenerator::testInterliquidDifferent()
{
MockGameDef gamedef;
auto water = gamedef.addLiquidSource("water", 42);
auto lava = gamedef.addLiquidSource("lava", 13);
gamedef.finalize();
MeshMakeData data = gamedef.makeSingleNodeMMD();
data.m_vmanip.setNode({0, 0, 0}, {water, 0, 0});
data.m_vmanip.setNode({0, 0, 1}, {lava, 0, 0});
MeshCollector col{{}};
MapblockMeshGenerator mg{&data, &col, nullptr};
mg.generate();
UASSERTEQ(std::size_t, col.prebuffers[0].size(), 1);
UASSERTEQ(std::size_t, col.prebuffers[1].size(), 0);
auto &&buf = col.prebuffers[0][0];
UASSERTEQ(u32, buf.layer.texture_id, 42);
UASSERT(checkMeshEqual(buf.vertices, buf.indices, {quad::xn, quad::xp, quad::yn, quad::yp, quad::zn, quad::zp}));
}
}