Skip to content

Commit

Permalink
#5263: Add (failing) unit test covering the faulty behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Oct 11, 2020
1 parent edbdeed commit 407bcc4
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 0 deletions.
63 changes: 63 additions & 0 deletions test/ModelScale.cpp
@@ -0,0 +1,63 @@
#include "RadiantTest.h"

#include "algorithm/Scene.h"
#include "iscenegraph.h"
#include "imodel.h"
#include "itransformable.h"
#include "icommandsystem.h"
#include "iselectable.h"
#include "iselection.h"
#include "math/Vector3.h"
#include "registry/registry.h"

namespace test
{

// #5263: "Model Scaler" doesn't handle model duplication correctly
TEST_F(RadiantTest, DuplicateScaledModel)
{
loadMap("duplicate_scaled_model.map");

const std::string funcStaticName("moss01");
const Vector3 scale(3, 4, 2);
auto func_static = algorithm::getEntityByName(GlobalSceneGraph().root(), funcStaticName);

// Apply the scale to the model beneath the entity
func_static->foreachNode([&](const scene::INodePtr& node)
{
ITransformablePtr transformable = Node_getTransformable(node);

if (transformable)
{
transformable->setType(TRANSFORM_PRIMITIVE);
transformable->setScale(scale);
transformable->freezeTransform();
}

return true;
});

auto model = algorithm::findChildModel(func_static);

ASSERT_TRUE(model->hasModifiedScale());
ASSERT_TRUE(model->getModelScale() == scale);

// Select the func_static and duplicate it
GlobalSelectionSystem().setSelectedAll(false);
Node_setSelected(func_static, true);

registry::setValue("user/ui/offsetClonedObjects", 0);
GlobalCommandSystem().executeCommand("CloneSelection");

auto duplicate = GlobalSelectionSystem().ultimateSelected();

// This must be the duplicate
ASSERT_TRUE(Node_getEntity(duplicate)->getKeyValue("name") != funcStaticName);

// The new model must have a modified scale too
auto duplicatedModel = algorithm::findChildModel(duplicate);
ASSERT_TRUE(duplicatedModel->hasModifiedScale());
ASSERT_TRUE(duplicatedModel->getModelScale() == scale);
}

}
50 changes: 50 additions & 0 deletions test/algorithm/Scene.h
Expand Up @@ -4,6 +4,7 @@
#include "inode.h"
#include "ientity.h"
#include "ibrush.h"
#include "imodel.h"

namespace test::algorithm
{
Expand Down Expand Up @@ -60,4 +61,53 @@ inline scene::INodePtr findFirstBrushWithMaterial(const scene::INodePtr& parent,
});
}

inline scene::INodePtr findFirstEntity(const scene::INodePtr& parent,
const std::function<bool(IEntityNode&)>& predicate)
{
IEntityNodePtr candidate;

parent->foreachNode([&](const scene::INodePtr& node)
{
auto entity = std::dynamic_pointer_cast<IEntityNode>(node);

if (entity && predicate(*entity))
{
candidate = entity;
return false;
}

return true;
});

return candidate;
}

inline scene::INodePtr getEntityByName(const scene::INodePtr& parent, const std::string& name)
{
return findFirstEntity(parent, [&](IEntityNode& entity)
{
return entity.getEntity().getKeyValue("name") == name;
});
}

inline model::ModelNodePtr findChildModel(const scene::INodePtr& parent)
{
model::ModelNodePtr candidate;

parent->foreachNode([&](const scene::INodePtr& node)
{
auto model = Node_getModel(node);

if (model)
{
candidate = model;
return false;
}

return true;
});

return candidate;
}

}
93 changes: 93 additions & 0 deletions test/resources/tdm/maps/duplicate_scaled_model.map
@@ -0,0 +1,93 @@
Version 2
// entity 0
{
"classname" "worldspawn"
// primitive 0
{
brushDef3
{
( 0 0 1 -208 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 1 0 0 -384 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 -1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( -1 0 0 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 -1 192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
}
}
// primitive 1
{
brushDef3
{
( 0 0 1 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 1 0 -208 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 1 0 0 -384 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 -1 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( -1 0 0 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 -1 0 192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
}
}
// primitive 2
{
brushDef3
{
( 0 0 1 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 1 0 0 -400 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 -1 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 -1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( -1 0 0 384 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
}
}
// primitive 3
{
brushDef3
{
( 0 1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 1 0 0 -384 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 -1 -80 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 -1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( -1 0 0 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 1 64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
}
}
// primitive 4
{
brushDef3
{
( 0 0 1 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 1 0 0 -384 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 -1 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 -1 0 -208 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( -1 0 0 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 1 0 192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
}
}
// primitive 5
{
brushDef3
{
( 0 0 1 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 0 -1 -64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 0 -1 0 -192 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( -1 0 0 -80 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
( 1 0 0 64 ) ( ( 0.03125 0 0 ) ( 0 0.03125 0 ) ) "_default" 0 0 0
}
}
}
// entity 1
{
"classname" "light"
"name" "light_1"
"light_center" "0 0 0"
"light_radius" "160 176 320"
"origin" "32 112 -48"
}
// entity 2
{
"classname" "func_static"
"name" "moss01"
"model" "models/moss_patch.ase"
"origin" "130 8 -48"
"rotation" "1 0 0 0 1 0 0 0 1"
}
140 changes: 140 additions & 0 deletions test/resources/tdm/models/moss_patch.ase
@@ -0,0 +1,140 @@
*3DSMAX_ASCIIEXPORT 200
*COMMENT "moss patch, first version by greebo 05/2007"
*SCENE {
*SCENE_FILENAME "moss_patch.blend"
*SCENE_FIRSTFRAME 1
*SCENE_LASTFRAME 250
*SCENE_FRAMESPEED 25
*SCENE_TICKSPERFRAME 160
*SCENE_BACKGROUND_STATIC 0.0566 0.2208 0.4000
*SCENE_AMBIENT_STATIC 0.0000 0.0000 0.0000
}
*MATERIAL_LIST {
*MATERIAL_COUNT 1
*MATERIAL 0 {
*MATERIAL_NAME "moss_d.tga"
*MATERIAL_CLASS "Standard"
*MATERIAL_AMBIENT 0.0000 0.0000 0.0000
*MATERIAL_DIFFUSE 0.5882 0.5882 0.5882
*MATERIAL_SPECULAR 0.9000 0.9000 0.9000
*MATERIAL_SHINE 0.1000
*MATERIAL_SHINESTRENGTH 0.0000
*MATERIAL_TRANSPARENCY 0.0000
*MATERIAL_WIRESIZE 1.0000
*MATERIAL_SHADING Blinn
*MATERIAL_XP_FALLOFF 0.0000
*MATERIAL_SELFILLUM 0.0000
*MATERIAL_FALLOFF In
*MATERIAL_XP_TYPE Filter
*MAP_DIFFUSE {
*MAP_NAME "moss_d.tga"
*MAP_CLASS "Bitmap"
*MAP_SUBNO 1
*MAP_AMOUNT 1.0000
*BITMAP "//base/textures/darkmod/decals/vegetation/moss_patch_thick01"
*MAP_TYPE Screen
*UVW_U_OFFSET 0.0000
*UVW_V_OFFSET 0.0000
*UVW_U_TILING 1.0000
*UVW_V_TILING 1.0000
*UVW_ANGLE 0.0000
*UVW_BLUR 1.0000
*UVW_BLUR_OFFSET 0.0000
*UVW_NOUSE_AMT 1.0000
*UVW_NOISE_SIZE 1.0000
*UVW_NOISE_LEVEL 1
*UVW_NOISE_PHASE 0.0000
*BITMAP_FILTER Pyramidal
}
}
}
*GEOMOBJECT {
*NODE_NAME "Cube"
*NODE_TM {
*NODE_NAME "Cube"
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 1.0000 0.0000 0.0000
*TM_ROW1 0.0000 1.0000 0.0000
*TM_ROW2 0.0000 0.0000 1.0000
*TM_ROW3 0.0000 -0.0000 1.0843
*TM_POS 0.0000 -0.0000 1.0843
*TM_ROTAXIS 1.0000 0.0000 0.0000
*TM_ROTANGLE 0.0000
*TM_SCALE 1.0000 1.0000 1.0000
*TM_SCALEAXIS 1.0000 0.0000 0.0000
*TM_SCALEAXISANG 0.0000
}
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 5
*MESH_NUMFACES 6
*MESH_VERTEX_LIST {
*MESH_VERTEX 0 17.8587 17.8587 0.0434
*MESH_VERTEX 1 -17.8587 17.8587 0.0434
*MESH_VERTEX 2 17.8587 -17.8587 0.0434
*MESH_VERTEX 3 -17.8587 -17.8587 0.0434
*MESH_VERTEX 4 -0.0000 0.0000 2.1252
}
*MESH_FACE_LIST {
*MESH_FACE 0: A: 1 B: 3 C: 4 AB: 1 BC: 1 CA: 1 *MESH_SMOOTHING *MESH_MTLID 0
*MESH_FACE 1: A: 0 B: 1 C: 4 AB: 1 BC: 1 CA: 1 *MESH_SMOOTHING *MESH_MTLID 0
*MESH_FACE 2: A: 4 B: 3 C: 2 AB: 1 BC: 1 CA: 1 *MESH_SMOOTHING *MESH_MTLID 0
*MESH_FACE 3: A: 0 B: 4 C: 2 AB: 1 BC: 1 CA: 1 *MESH_SMOOTHING *MESH_MTLID 0
*MESH_FACE 4: A: 0 B: 2 C: 3 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING *MESH_MTLID 0
*MESH_FACE 5: A: 3 B: 1 C: 0 AB: 1 BC: 1 CA: 0 *MESH_SMOOTHING *MESH_MTLID 0
}
*MESH_NUMTVERTEX 9
*MESH_TVERTLIST {
*MESH_TVERT 0 0.0000 1.0000 0.0000
*MESH_TVERT 1 0.0000 0.0000 0.0000
*MESH_TVERT 2 0.5000 0.5000 0.0000
*MESH_TVERT 3 1.0000 1.0000 0.0000
*MESH_TVERT 4 1.0000 0.0000 0.0000
*MESH_TVERT 5 1.0000 0.0000 0.0000
*MESH_TVERT 6 1.0000 1.0000 0.0000
*MESH_TVERT 7 0.0000 1.0000 0.0000
*MESH_TVERT 8 0.0000 0.0000 0.0000
}
*MESH_NUMTVFACES 6
*MESH_TFACELIST {
*MESH_TFACE 0 0 1 2
*MESH_TFACE 1 3 0 2
*MESH_TFACE 2 2 1 4
*MESH_TFACE 3 3 2 4
*MESH_TFACE 4 5 6 7
*MESH_TFACE 5 7 8 5
}
*MESH_NORMALS {
*MESH_FACENORMAL 0 -0.1158 0.0000 0.9933
*MESH_VERTEXNORMAL 1 -0.1158 0.1158 0.9865
*MESH_VERTEXNORMAL 3 -0.7047 -0.7047 -0.0819
*MESH_VERTEXNORMAL 4 -0.0000 -0.0000 1.0000
*MESH_FACENORMAL 1 0.0000 0.1158 0.9933
*MESH_VERTEXNORMAL 0 0.7047 0.7047 -0.0819
*MESH_VERTEXNORMAL 1 -0.1158 0.1158 0.9865
*MESH_VERTEXNORMAL 4 -0.0000 -0.0000 1.0000
*MESH_FACENORMAL 2 -0.0000 -0.1158 0.9933
*MESH_VERTEXNORMAL 4 -0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 3 -0.7047 -0.7047 -0.0819
*MESH_VERTEXNORMAL 2 0.1158 -0.1158 0.9865
*MESH_FACENORMAL 3 0.1158 -0.0000 0.9933
*MESH_VERTEXNORMAL 0 0.7047 0.7047 -0.0819
*MESH_VERTEXNORMAL 4 -0.0000 -0.0000 1.0000
*MESH_VERTEXNORMAL 2 0.1158 -0.1158 0.9865
*MESH_FACENORMAL 4 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 0 0.7047 0.7047 -0.0819
*MESH_VERTEXNORMAL 2 0.1158 -0.1158 0.9865
*MESH_VERTEXNORMAL 3 -0.7047 -0.7047 -0.0819
*MESH_FACENORMAL 5 0.0000 0.0000 -1.0000
*MESH_VERTEXNORMAL 3 -0.7047 -0.7047 -0.0819
*MESH_VERTEXNORMAL 1 -0.1158 0.1158 0.9865
*MESH_VERTEXNORMAL 0 0.7047 0.7047 -0.0819
}
}
*PROP_MOTIONBLUR 0
*PROP_CASTSHADOW 1
*PROP_RECVSHADOW 1
*MATERIAL_REF 0
}
1 change: 1 addition & 0 deletions tools/msvc/Tests/Tests.vcxproj
Expand Up @@ -64,6 +64,7 @@
<ClCompile Include="..\..\..\test\Camera.cpp" />
<ClCompile Include="..\..\..\test\CSG.cpp" />
<ClCompile Include="..\..\..\test\HeadlessOpenGLContext.cpp" />
<ClCompile Include="..\..\..\test\ModelScale.cpp" />
<ClCompile Include="..\..\..\test\SelectionAlgorithm.cpp" />
</ItemGroup>
<ItemDefinitionGroup />
Expand Down
1 change: 1 addition & 0 deletions tools/msvc/Tests/Tests.vcxproj.filters
Expand Up @@ -5,6 +5,7 @@
<ClCompile Include="..\..\..\test\HeadlessOpenGLContext.cpp" />
<ClCompile Include="..\..\..\test\Camera.cpp" />
<ClCompile Include="..\..\..\test\SelectionAlgorithm.cpp" />
<ClCompile Include="..\..\..\test\ModelScale.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\test\HeadlessOpenGLContext.h" />
Expand Down

0 comments on commit 407bcc4

Please sign in to comment.