drag-resizing for doom3/quake4 light_radius

git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@29 8a3a26a2-13c4-0310-b231-cf6edde360e5
This commit is contained in:
spog 2006-03-01 00:14:03 +00:00
parent cb67131f78
commit 93060cb634
6 changed files with 168 additions and 51 deletions

View File

@ -1,6 +1,10 @@
This is the changelog for developers, != changelog for the end user
that we distribute with the binaries. (see changelog)
28/02/2006
namespace, SPoG
- Added drag-resizing for doom3/quake4 light_radius boxes.
25/02/2006
SPoG
- Fixed objects sometimes dissappearing when at high zoom level in Ortho views.

View File

@ -27,6 +27,28 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "math/aabb.h"
#include "math/line.h"
// local must be a pure rotation
inline Vector3 translation_to_local(const Vector3& translation, const Matrix4& local)
{
return matrix4_get_translation_vec3(
matrix4_multiplied_by_matrix4(
matrix4_translated_by_vec3(matrix4_transposed(local), translation),
local
)
);
}
// local must be a pure rotation
inline Vector3 translation_from_local(const Vector3& translation, const Matrix4& local)
{
return matrix4_get_translation_vec3(
matrix4_multiplied_by_matrix4(
matrix4_translated_by_vec3(local, translation),
matrix4_transposed(local)
)
);
}
class DragPlanes
{
public:
@ -65,13 +87,14 @@ public:
m_selectable_top.setSelected(selected);
m_selectable_bottom.setSelected(selected);
}
void selectPlanes(const AABB& aabb, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
void selectPlanes(const AABB& aabb, Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback, const Matrix4& rotation = g_matrix4_identity)
{
Line line(test.getNear(), test.getFar());
Vector3 corners[8];
aabb_corners(aabb, corners);
aabb_corners_oriented(aabb, rotation, corners);
Plane3 planes[6];
aabb_planes(aabb, planes);
aabb_planes_oriented(aabb, rotation, planes);
for(Vector3* i = corners; i != corners + 8; ++i)
{
@ -129,16 +152,16 @@ public:
&& vector3_dot(planes[5].normal(), corners[7]) > 0)
{
Selector_add(selector, m_selectable_bottom);
//globalOutputStream() << "bottom\n";
selectedPlaneCallback(planes[5]);
//globalOutputStream() << "bottom\n";
}
m_bounds = aabb;
}
void selectReversedPlanes(const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes)
void selectReversedPlanes(const AABB& aabb, Selector& selector, const SelectedPlanes& selectedPlanes, const Matrix4& rotation = g_matrix4_identity)
{
Plane3 planes[6];
aabb_planes(aabb, planes);
aabb_planes_oriented(aabb, rotation, planes);
if(selectedPlanes.contains(plane3_flipped(planes[0])))
{
@ -165,13 +188,11 @@ public:
Selector_add(selector, m_selectable_bottom);
}
}
Matrix4 evaluateTransform(const Vector3& translation) const
AABB evaluateResize(const Vector3& translation) const
{
Vector3 min = m_bounds.origin - m_bounds.extents;
Vector3 max = m_bounds.origin + m_bounds.extents;
Vector3 origin = m_bounds.origin;
Vector3 extents = m_bounds.extents;
if(extents[0] != 0)
if(m_bounds.extents[0] != 0)
{
if(m_selectable_right.isSelected())
{
@ -184,7 +205,7 @@ public:
//globalOutputStream() << "moving left\n";
}
}
if(extents[1] != 0)
if(m_bounds.extents[1] != 0)
{
if(m_selectable_front.isSelected())
{
@ -197,7 +218,7 @@ public:
//globalOutputStream() << "moving back\n";
}
}
if(extents[2] != 0)
if(m_bounds.extents[2] != 0)
{
if(m_selectable_top.isSelected())
{
@ -211,36 +232,19 @@ public:
}
}
Vector3 originTransformed(vector3_mid(min, max));
Vector3 scale(vector3_scaled(vector3_subtracted(max, min), 0.5));
return AABB(vector3_mid(min, max), vector3_scaled(vector3_subtracted(max, min), 0.5));
}
Matrix4 evaluateTransform(const Vector3& translation) const
{
AABB aabb(evaluateResize(translation));
Vector3 scale(
m_bounds.extents[0] != 0 ? aabb.extents[0] / m_bounds.extents[0] : 1,
m_bounds.extents[1] != 0 ? aabb.extents[1] / m_bounds.extents[1] : 1,
m_bounds.extents[2] != 0 ? aabb.extents[2] / m_bounds.extents[2] : 1
);
if(extents[0] != 0)
{
scale[0] /= extents[0];
}
else
{
scale[0] = 1;
}
if(extents[1] != 0)
{
scale[1] /= extents[1];
}
else
{
scale[1] = 1;
}
if(extents[2] != 0)
{
scale[2] /= extents[2];
}
else
{
scale[2] = 1;
}
Matrix4 matrix(matrix4_translation_for_vec3(originTransformed - origin));
matrix4_pivoted_scale_by_vec3(matrix, scale, origin);
Matrix4 matrix(matrix4_translation_for_vec3(aabb.origin - m_bounds.origin));
matrix4_pivoted_scale_by_vec3(matrix, scale, m_bounds.origin);
return matrix;
}

View File

@ -241,6 +241,22 @@ inline void aabb_corners(const AABB& aabb, Vector3 corners[8])
corners[7] = Vector3(min[0], min[1], min[2]);
}
inline void aabb_corners_oriented(const AABB& aabb, const Matrix4& rotation, Vector3 corners[8])
{
Vector3 x = Vector3(rotation.x()) * aabb.extents.x();
Vector3 y = Vector3(rotation.y()) * aabb.extents.y();
Vector3 z = Vector3(rotation.z()) * aabb.extents.z();
corners[0] = aabb.origin + -x + y + z;
corners[1] = aabb.origin + x + y + z;
corners[2] = aabb.origin + x + -y + z;
corners[3] = aabb.origin + -x + -y + z;
corners[4] = aabb.origin + -x + y + -z;
corners[5] = aabb.origin + x + y + -z;
corners[6] = aabb.origin + x + -y + -z;
corners[7] = aabb.origin + -x + -y + -z;
}
inline void aabb_planes(const AABB& aabb, Plane3 planes[6])
{
planes[0] = Plane3(g_vector3_axes[0], aabb.origin[0] + aabb.extents[0]);
@ -251,6 +267,20 @@ inline void aabb_planes(const AABB& aabb, Plane3 planes[6])
planes[5] = Plane3(vector3_negated(g_vector3_axes[2]), -(aabb.origin[2] - aabb.extents[2]));
}
inline void aabb_planes_oriented(const AABB& aabb, const Matrix4& rotation, Plane3 planes[6])
{
double x = vector3_dot(Vector3(rotation.x()), aabb.origin);
double y = vector3_dot(Vector3(rotation.y()), aabb.origin);
double z = vector3_dot(Vector3(rotation.z()), aabb.origin);
planes[0] = Plane3(Vector3(rotation.x()), x + aabb.extents[0]);
planes[1] = Plane3(-Vector3(rotation.x()), -(x - aabb.extents[0]));
planes[2] = Plane3(Vector3(rotation.y()), y + aabb.extents[1]);
planes[3] = Plane3(-Vector3(rotation.y()), -(y - aabb.extents[1]));
planes[4] = Plane3(Vector3(rotation.z()), z + aabb.extents[2]);
planes[5] = Plane3(-Vector3(rotation.z()), -(z - aabb.extents[2]));
}
const Vector3 aabb_normals[6] = {
Vector3( 1, 0, 0 ),
Vector3( 0, 1, 0 ),

View File

@ -651,6 +651,11 @@ inline BasicVector3<Element> vector3_negated(const BasicVector3<Element>& self)
{
return BasicVector3<Element>(-self.x(), -self.y(), -self.z());
}
template<typename Element>
inline BasicVector3<Element> operator-(const BasicVector3<Element>& self)
{
return vector3_negated(self);
}
template<typename Element>
inline void vector3_negate(BasicVector3<Element>& self)

View File

@ -52,6 +52,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "render.h"
#include "stringio.h"
#include "traverselib.h"
#include "dragplanes.h"
#include "targetable.h"
#include "origin.h"
@ -541,6 +542,7 @@ class Doom3LightRadius
{
public:
Vector3 m_radius;
Vector3 m_radiusTransformed;
Vector3 m_center;
Callback m_changed;
bool m_useCenterKey;
@ -555,6 +557,7 @@ public:
{
m_radius = c_defaultDoom3LightRadius;
}
m_radiusTransformed = m_radius;
m_changed();
SceneChangeNotify();
}
@ -992,7 +995,7 @@ class Light :
void updateLightRadiiBox() const
{
const Matrix4& rotation = rotation_toMatrix(m_rotation);
aabb_corners(AABB(Vector3(0, 0, 0), m_doom3Radius.m_radius), m_radii_box.m_points);
aabb_corners(AABB(Vector3(0, 0, 0), m_doom3Radius.m_radiusTransformed), m_radii_box.m_points);
matrix4_transform_point(rotation, m_radii_box.m_points[0]);
vector3_add(m_radii_box.m_points[0], m_aabb_light.origin);
matrix4_transform_point(rotation, m_radii_box.m_points[1]);
@ -1277,10 +1280,20 @@ public:
m_originKey.write(&m_entity);
}
}
void setLightRadius(const AABB& aabb)
{
m_aabb_light.origin = aabb.origin;
m_doom3Radius.m_radiusTransformed = aabb.extents;
}
void transformLightRadius(const Matrix4& transform)
{
matrix4_transform_point(transform, m_aabb_light.origin);
}
void revertTransform()
{
m_aabb_light.origin = m_useLightOrigin ? m_lightOrigin : m_originKey.m_origin;
rotation_assign(m_rotation, m_useLightRotation ? m_lightRotation : m_rotationKey.m_rotation);
m_doom3Radius.m_radiusTransformed = m_doom3Radius.m_radius;
}
void freezeTransform()
{
@ -1315,6 +1328,16 @@ public:
rotation_assign(m_rotationKey.m_rotation, m_rotation);
write_rotation(m_rotationKey.m_rotation, &m_entity);
m_doom3Radius.m_radius = m_doom3Radius.m_radiusTransformed;
if(m_doom3Radius.m_radius == c_defaultDoom3LightRadius)
{
m_entity.setKeyValue("light_radius", "");
}
else
{
write_origin(m_doom3Radius.m_radius, &m_entity, "light_radius");
}
}
}
void transformChanged()
@ -1340,7 +1363,7 @@ public:
const AABB& aabb() const
{
m_doom3AABB = AABB(m_aabb_light.origin, m_doom3Radius.m_radius);
m_doom3AABB = AABB(m_aabb_light.origin, m_doom3Radius.m_radiusTransformed);
return m_doom3AABB;
}
bool testAABB(const AABB& other) const
@ -1540,7 +1563,9 @@ class LightInstance :
public TransformModifier,
public Renderable,
public SelectionTestable,
public RendererLight
public RendererLight,
public PlaneSelectable,
public ComponentSelectionTestable
{
class TypeCasts
{
@ -1554,6 +1579,8 @@ class LightInstance :
InstanceStaticCast<LightInstance, Renderable>::install(m_casts);
InstanceStaticCast<LightInstance, SelectionTestable>::install(m_casts);
InstanceStaticCast<LightInstance, Transformable>::install(m_casts);
InstanceStaticCast<LightInstance, PlaneSelectable>::install(m_casts);
InstanceStaticCast<LightInstance, ComponentSelectionTestable>::install(m_casts);
InstanceIdentityCast<LightInstance>::install(m_casts);
}
InstanceTypeCastTable& get()
@ -1563,6 +1590,7 @@ class LightInstance :
};
Light& m_contained;
DragPlanes m_dragPlanes;// dragplanes for lightresizing using mousedrag
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
@ -1576,7 +1604,8 @@ public:
LightInstance(const scene::Path& path, scene::Instance* parent, Light& contained) :
TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
TransformModifier(Light::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
m_contained(contained)
m_contained(contained),
m_dragPlanes(SelectedChangedComponentCaller(*this))
{
m_contained.instanceAttach(Instance::path());
@ -1613,6 +1642,38 @@ public:
m_contained.testSelect(selector, test, Instance::localToWorld());
}
void selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
{
test.BeginMesh(localToWorld());
m_dragPlanes.selectPlanes(m_contained.aabb(), selector, test, selectedPlaneCallback, rotation());
}
void selectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
{
m_dragPlanes.selectReversedPlanes(m_contained.aabb(), selector, selectedPlanes, rotation());
}
bool isSelectedComponents() const
{
return m_dragPlanes.isSelected();
}
void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode)
{
if(mode == SelectionSystem::eFace)
{
m_dragPlanes.setSelected(false);
}
}
void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
{
}
void selectedChangedComponent(const Selectable& selectable)
{
GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
GlobalSelectionSystem().onComponentSelection(*this, selectable);
}
typedef MemberCaller1<LightInstance, const Selectable&, &LightInstance::selectedChangedComponent> SelectedChangedComponentCaller;
void evaluateTransform()
{
if(getType() == TRANSFORM_PRIMITIVE)
@ -1620,6 +1681,16 @@ public:
m_contained.translate(getTranslation());
m_contained.rotate(getRotation());
}
else
{
//globalOutputStream() << getTranslation() << "\n";
m_dragPlanes.m_bounds = m_contained.aabb();
AABB aabb(m_dragPlanes.evaluateResize(translation_to_local(getTranslation(), rotation())));
aabb.origin = m_contained.aabb().origin + translation_from_local(aabb.origin - m_contained.aabb().origin, rotation());
m_contained.setLightRadius(aabb);
}
}
void applyTransform()
{

View File

@ -474,6 +474,7 @@ inline unsigned int buttons_for_state(guint state)
void XYWnd::SetScale(float f)
{
m_fScale = f;
updateProjection();
updateModelview();
XYWnd_Update(*this);
}
@ -844,6 +845,7 @@ XYWnd::XYWnd() :
Map_addValidCallback(g_map, DeferredDrawOnMapValidChangedCaller(m_deferredDraw));
updateProjection();
updateModelview();
AddSceneChangeCallback(ReferenceCaller<XYWnd, &XYWnd_Update>(*this));
@ -2086,7 +2088,7 @@ void XYWnd::updateProjection()
{
m_projection[0] = 1.0f / static_cast<float>(m_nWidth / 2);
m_projection[5] = 1.0f / static_cast<float>(m_nHeight / 2);
m_projection[10] = 1.0f / g_MaxWorldCoord;
m_projection[10] = 1.0f / (g_MaxWorldCoord * m_fScale);
m_projection[12] = 0.0f;
m_projection[13] = 0.0f;
@ -2109,6 +2111,7 @@ void XYWnd::updateProjection()
m_view.Construct(m_projection, m_modelview, m_nWidth, m_nHeight);
}
// note: modelview matrix must have a uniform scale, otherwise strange things happen when rendering the rotation manipulator.
void XYWnd::updateModelview()
{
int nDim1 = (m_viewType == YZ) ? 1 : 0;
@ -2117,7 +2120,7 @@ void XYWnd::updateModelview()
// translation
m_modelview[12] = -m_vOrigin[nDim1] * m_fScale;
m_modelview[13] = -m_vOrigin[nDim2] * m_fScale;
m_modelview[14] = static_cast<float>(g_MaxWorldCoord);
m_modelview[14] = g_MaxWorldCoord * m_fScale;
// axis base
switch(m_viewType)
@ -2133,7 +2136,7 @@ void XYWnd::updateModelview()
m_modelview[8] = 0;
m_modelview[9] = 0;
m_modelview[10] = -1.0;
m_modelview[10] = -m_fScale;
break;
case XZ:
m_modelview[0] = m_fScale;
@ -2142,7 +2145,7 @@ void XYWnd::updateModelview()
m_modelview[4] = 0;
m_modelview[5] = 0;
m_modelview[6] = 1.0;
m_modelview[6] = m_fScale;
m_modelview[8] = 0;
m_modelview[9] = m_fScale;
@ -2151,7 +2154,7 @@ void XYWnd::updateModelview()
case YZ:
m_modelview[0] = 0;
m_modelview[1] = 0;
m_modelview[2] = -1.0;
m_modelview[2] = -m_fScale;
m_modelview[4] = m_fScale;
m_modelview[5] = 0;