drag-resizing for doom3/quake4 light_radius
authorspog <spog>
Wed, 1 Mar 2006 00:14:03 +0000 (00:14 +0000)
committerspog <spog>
Wed, 1 Mar 2006 00:14:03 +0000 (00:14 +0000)
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@29 8a3a26a2-13c4-0310-b231-cf6edde360e5

CHANGES
libs/dragplanes.h
libs/math/aabb.h
libs/math/vector.h
plugins/entity/light.cpp
radiant/xywindow.cpp

diff --git a/CHANGES b/CHANGES
index 36939db..effb845 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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.
index 1f2e77a..287b0ab 100644 (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,39 +232,22 @@ public:
       }
     }
 
-    Vector3 originTransformed(vector3_mid(min, max));
-    Vector3 scale(vector3_scaled(vector3_subtracted(max, min), 0.5));
-
-    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;
-    }
+    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
+    );
 
-    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;
-  }
+  }  
 };
 
 #endif
index 9a6b5df..a2476e4 100644 (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 ),
index a9dae79..ef0d225 100644 (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)
index 65aeeea..901e79d 100644 (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()
   {
index b0c2c05..50dbf87 100644 (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;