- Light(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
- m_entity(eclass),
- m_originKey(OriginChangedCaller(*this)),
- m_rotationKey(RotationChangedCaller(*this)),
- m_colour(Callback()),
- m_filter(m_entity, node),
- m_named(m_entity),
- m_nameKeys(m_entity),
- m_funcStaticOrigin(m_traverse, m_originKey.m_origin),
- m_radii_wire(m_radii, m_aabb_light.origin),
- m_radii_fill(m_radii, m_aabb_light.origin),
- m_radii_box(m_aabb_light.origin),
- m_render_center(m_doom3Radius.m_center, m_entity.getEntityClass()),
- m_renderName(m_named, m_aabb_light.origin),
- m_useLightOrigin(false),
- m_useLightRotation(false),
- m_renderProjection(m_doom3Projection),
- m_transformChanged(transformChanged),
- m_boundsChanged(boundsChanged),
- m_evaluateTransform(evaluateTransform)
- {
- construct();
- }
- Light(const Light& other, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
- m_entity(other.m_entity),
- m_originKey(OriginChangedCaller(*this)),
- m_rotationKey(RotationChangedCaller(*this)),
- m_colour(Callback()),
- m_filter(m_entity, node),
- m_named(m_entity),
- m_nameKeys(m_entity),
- m_funcStaticOrigin(m_traverse, m_originKey.m_origin),
- m_radii_wire(m_radii, m_aabb_light.origin),
- m_radii_fill(m_radii, m_aabb_light.origin),
- m_radii_box(m_aabb_light.origin),
- m_render_center(m_doom3Radius.m_center, m_entity.getEntityClass()),
- m_renderName(m_named, m_aabb_light.origin),
- m_useLightOrigin(false),
- m_useLightRotation(false),
- m_renderProjection(m_doom3Projection),
- m_transformChanged(transformChanged),
- m_boundsChanged(boundsChanged),
- m_evaluateTransform(evaluateTransform)
- {
- construct();
- }
- ~Light()
- {
- destroy();
- }
-
- InstanceCounter m_instanceCounter;
- void instanceAttach(const scene::Path& path)
- {
- if(++m_instanceCounter.m_count == 1)
- {
- m_filter.instanceAttach();
- m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
- if(g_lightType == LIGHTTYPE_DOOM3)
- {
- m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
- }
- m_entity.attach(m_keyObservers);
-
- if(g_lightType == LIGHTTYPE_DOOM3)
- {
- m_funcStaticOrigin.enable();
- }
- }
- }
- void instanceDetach(const scene::Path& path)
- {
- if(--m_instanceCounter.m_count == 0)
- {
- if(g_lightType == LIGHTTYPE_DOOM3)
- {
- m_funcStaticOrigin.disable();
- }
-
- m_entity.detach(m_keyObservers);
- if(g_lightType == LIGHTTYPE_DOOM3)
- {
- m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
- }
- m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
- m_filter.instanceDetach();
- }
- }
-
- EntityKeyValues& getEntity()
- {
- return m_entity;
- }
- const EntityKeyValues& getEntity() const
- {
- return m_entity;
- }
-
- scene::Traversable& getTraversable()
- {
- return m_traverse;
- }
- Namespaced& getNamespaced()
- {
- return m_nameKeys;
- }
- Nameable& getNameable()
- {
- return m_named;
- }
- TransformNode& getTransformNode()
- {
- return m_transform;
- }
-
- void attach(scene::Traversable::Observer* observer)
- {
- m_traverseObservers.attach(*observer);
- }
- void detach(scene::Traversable::Observer* observer)
- {
- m_traverseObservers.detach(*observer);
- }
-
- void render(RenderStateFlags state) const
- {
- if(!g_newLightDraw)
- {
- aabb_draw(m_aabb_light, state);
- }
- else
- {
- light_draw(m_aabb_light, state);
- }
- }
-
- VolumeIntersectionValue intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const
- {
- return volume.TestAABB(m_aabb_light, localToWorld);
- }
-
- // cache
- const AABB& localAABB() const
- {
- return m_aabb_light;
- }
-
-
- mutable Matrix4 m_projectionOrientation;
-
- void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
- {
- renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
- renderer.SetState(m_colour.state(), Renderer::eFullMaterials);
- renderer.addRenderable(*this, localToWorld);
-
- if(selected && g_lightRadii && string_empty(m_entity.getKeyValue("target")))
- {
- if(renderer.getStyle() == Renderer::eFullMaterials)
- {
- renderer.SetState(RenderLightRadiiFill::m_state, Renderer::eFullMaterials);
- renderer.Highlight(Renderer::ePrimitive, false);
- renderer.addRenderable(m_radii_fill, localToWorld);
- }
- else
- {
- renderer.addRenderable(m_radii_wire, localToWorld);
- }
- }
-
- renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
-
- if(g_lightType == LIGHTTYPE_DOOM3 && selected)
- {
- if(isProjected())
- {
- projection();
- m_projectionOrientation = rotation();
- vector4_to_vector3(m_projectionOrientation.t()) = localAABB().origin;
- renderer.addRenderable(m_renderProjection, m_projectionOrientation);
- }
- else
- {
- updateLightRadiiBox();
- renderer.addRenderable(m_radii_box, localToWorld);
- }
-
- //draw the center of the light
- if(m_doom3Radius.m_useCenterKey)
- {
- renderer.Highlight(Renderer::ePrimitive, false);
- renderer.Highlight(Renderer::eFace, false);
- renderer.SetState(m_render_center.m_state, Renderer::eFullMaterials);
- renderer.SetState(m_render_center.m_state, Renderer::eWireframeOnly);
- renderer.addRenderable(m_render_center, localToWorld);
- }
- }
- }
- void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
- {
- renderSolid(renderer, volume, localToWorld, selected);
- if(g_showNames)
- {
- renderer.addRenderable(m_renderName, localToWorld);
- }
- }
-
- void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
- {
- test.BeginMesh(localToWorld);
-
- SelectionIntersection best;
- aabb_testselect(m_aabb_light, test, best);
- if(best.valid())
- {
- selector.addIntersection(best);
- }
- }
-
- void translate(const Vector3& translation)
- {
- m_aabb_light.origin = origin_translated(m_aabb_light.origin, translation);
- }
- void rotate(const Quaternion& rotation)
- {
- rotation_rotate(m_rotation, rotation);
- }
- void snapto(float snap)
- {
- if(g_lightType == LIGHTTYPE_DOOM3 && !m_useLightOrigin && !m_traverse.empty())
- {
- m_useLightOrigin = true;
- m_lightOrigin = m_originKey.m_origin;
- }
-
- if(m_useLightOrigin)
- {
- m_lightOrigin = origin_snapped(m_lightOrigin, snap);
- writeLightOrigin();
- }
- else
- {
- m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
- 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()
- {
- if(g_lightType == LIGHTTYPE_DOOM3 && !m_useLightOrigin && !m_traverse.empty())
- {
- m_useLightOrigin = true;
- }
-
- if(m_useLightOrigin)
- {
- m_lightOrigin = m_aabb_light.origin;
- writeLightOrigin();
- }
- else
- {
- m_originKey.m_origin = m_aabb_light.origin;
- m_originKey.write(&m_entity);
- }
-
- if(g_lightType == LIGHTTYPE_DOOM3)
- {
- if(!m_useLightRotation && !m_traverse.empty())
- {
- m_useLightRotation = true;
- }
-
- if(m_useLightRotation)
- {
- rotation_assign(m_lightRotation, m_rotation);
- write_rotation(m_lightRotation, &m_entity, "light_rotation");
- }
-
- 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()
- {
- revertTransform();
- m_evaluateTransform();
- updateOrigin();
- }
- typedef MemberCaller<Light, &Light::transformChanged> TransformChangedCaller;
-
- mutable Matrix4 m_localPivot;
- const Matrix4& getLocalPivot() const
- {
- m_localPivot = rotation_toMatrix(m_rotation);
- vector4_to_vector3(m_localPivot.t()) = m_aabb_light.origin;
- return m_localPivot;
- }
-
- void setLightChangedCallback(const Callback& callback)
- {
- m_doom3Radius.m_changed = callback;
- }
-
- const AABB& aabb() const
- {
- m_doom3AABB = AABB(m_aabb_light.origin, m_doom3Radius.m_radiusTransformed);
- return m_doom3AABB;
- }
- bool testAABB(const AABB& other) const
- {
- if(isProjected())
- {
- Matrix4 transform = rotation();
- vector4_to_vector3(transform.t()) = localAABB().origin;
- projection();
- Frustum frustum(frustum_transformed(m_doom3Frustum, transform));
- return frustum_test_aabb(frustum, other) != c_volumeOutside;
- }
- // test against an AABB which contains the rotated bounds of this light.
- const AABB& bounds = aabb();
- return aabb_intersects_aabb(other, AABB(
- bounds.origin,
- Vector3(
- static_cast<float>(fabs(m_rotation[0] * bounds.extents[0])
- + fabs(m_rotation[3] * bounds.extents[1])
- + fabs(m_rotation[6] * bounds.extents[2])),
- static_cast<float>(fabs(m_rotation[1] * bounds.extents[0])
- + fabs(m_rotation[4] * bounds.extents[1])
- + fabs(m_rotation[7] * bounds.extents[2])),
- static_cast<float>(fabs(m_rotation[2] * bounds.extents[0])
- + fabs(m_rotation[5] * bounds.extents[1])
- + fabs(m_rotation[8] * bounds.extents[2]))
- )
- ));
- }
-
- const Matrix4& rotation() const
- {
- m_doom3Rotation = rotation_toMatrix(m_rotation);
- return m_doom3Rotation;
- }
- const Vector3& offset() const
- {
- return m_doom3Radius.m_center;
- }
- const Vector3& colour() const
- {
- return m_colour.m_colour;
- }
-
- bool isProjected() const
- {
- return m_useLightTarget && m_useLightUp && m_useLightRight;
- }
- void projectionChanged()
- {
- m_doom3ProjectionChanged = true;
- m_doom3Radius.m_changed();
- SceneChangeNotify();
- }
-
- const Matrix4& projection() const
- {
- if(!m_doom3ProjectionChanged)
- {
- return m_doom3Projection;
- }
- m_doom3ProjectionChanged = false;
- m_doom3Projection = g_matrix4_identity;
- matrix4_translate_by_vec3(m_doom3Projection, Vector3(0.5f, 0.5f, 0));
- matrix4_scale_by_vec3(m_doom3Projection, Vector3(0.5f, 0.5f, 1));
+Light( EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform ) :
+ m_entity( eclass ),
+ m_originKey( OriginChangedCaller( *this ) ),
+ m_rotationKey( RotationChangedCaller( *this ) ),
+ m_colour( Callback() ),
+ m_filter( m_entity, node ),
+ m_named( m_entity ),
+ m_nameKeys( m_entity ),
+ m_funcStaticOrigin( m_traverse, m_originKey.m_origin ),
+ m_doom3Radius( EntityClass_valueForKey( m_entity.getEntityClass(), "light_radius" ) ),
+ m_radii_wire( m_radii, m_aabb_light.origin ),
+ m_radii_fill( m_radii, m_aabb_light.origin ),
+ m_radii_box( m_aabb_light.origin ),
+ m_render_center( m_doom3Radius.m_center, m_entity.getEntityClass() ),
+ m_renderName( m_named, m_aabb_light.origin ),
+ m_useLightOrigin( false ),
+ m_useLightRotation( false ),
+ m_renderProjection( m_doom3Projection ),
+ m_transformChanged( transformChanged ),
+ m_boundsChanged( boundsChanged ),
+ m_evaluateTransform( evaluateTransform ){
+ construct();
+}
+Light( const Light& other, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform ) :
+ m_entity( other.m_entity ),
+ m_originKey( OriginChangedCaller( *this ) ),
+ m_rotationKey( RotationChangedCaller( *this ) ),
+ m_colour( Callback() ),
+ m_filter( m_entity, node ),
+ m_named( m_entity ),
+ m_nameKeys( m_entity ),
+ m_funcStaticOrigin( m_traverse, m_originKey.m_origin ),
+ m_doom3Radius( EntityClass_valueForKey( m_entity.getEntityClass(), "light_radius" ) ),
+ m_radii_wire( m_radii, m_aabb_light.origin ),
+ m_radii_fill( m_radii, m_aabb_light.origin ),
+ m_radii_box( m_aabb_light.origin ),
+ m_render_center( m_doom3Radius.m_center, m_entity.getEntityClass() ),
+ m_renderName( m_named, m_aabb_light.origin ),
+ m_useLightOrigin( false ),
+ m_useLightRotation( false ),
+ m_renderProjection( m_doom3Projection ),
+ m_transformChanged( transformChanged ),
+ m_boundsChanged( boundsChanged ),
+ m_evaluateTransform( evaluateTransform ){
+ construct();
+}
+~Light(){
+ destroy();
+}
+
+InstanceCounter m_instanceCounter;
+void instanceAttach( const scene::Path& path ){
+ if ( ++m_instanceCounter.m_count == 1 ) {
+ m_filter.instanceAttach();
+ m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
+ if ( g_lightType == LIGHTTYPE_DOOM3 ) {
+ m_traverse.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
+ }
+ m_entity.attach( m_keyObservers );
+
+ if ( g_lightType == LIGHTTYPE_DOOM3 ) {
+ m_funcStaticOrigin.enable();
+ }
+ }
+}
+void instanceDetach( const scene::Path& path ){
+ if ( --m_instanceCounter.m_count == 0 ) {
+ if ( g_lightType == LIGHTTYPE_DOOM3 ) {
+ m_funcStaticOrigin.disable();
+ }
+
+ m_entity.detach( m_keyObservers );
+ if ( g_lightType == LIGHTTYPE_DOOM3 ) {
+ m_traverse.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
+ }
+ m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
+ m_filter.instanceDetach();
+ }
+}
+
+EntityKeyValues& getEntity(){
+ return m_entity;
+}
+const EntityKeyValues& getEntity() const {
+ return m_entity;
+}
+
+scene::Traversable& getTraversable(){
+ return m_traverse;
+}
+Namespaced& getNamespaced(){
+ return m_nameKeys;
+}
+Nameable& getNameable(){
+ return m_named;
+}
+TransformNode& getTransformNode(){
+ return m_transform;
+}
+
+void attach( scene::Traversable::Observer* observer ){
+ m_traverseObservers.attach( *observer );
+}
+void detach( scene::Traversable::Observer* observer ){
+ m_traverseObservers.detach( *observer );
+}
+
+void render( RenderStateFlags state ) const {
+ if ( !g_newLightDraw ) {
+ aabb_draw( m_aabb_light, state );
+ }
+ else
+ {
+ light_draw( m_aabb_light, state );
+ }
+}
+
+VolumeIntersectionValue intersectVolume( const VolumeTest& volume, const Matrix4& localToWorld ) const {
+ return volume.TestAABB( m_aabb_light, localToWorld );
+}
+
+// cache
+const AABB& localAABB() const {
+ return m_aabb_light;
+}
+
+
+mutable Matrix4 m_projectionOrientation;
+
+void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
+ renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
+ renderer.SetState( m_colour.state(), Renderer::eFullMaterials );
+ renderer.addRenderable( *this, localToWorld );
+
+ if ( selected && g_lightRadii && string_empty( m_entity.getKeyValue( "target" ) ) ) {
+ if ( renderer.getStyle() == Renderer::eFullMaterials ) {
+ renderer.SetState( RenderLightRadiiFill::m_state, Renderer::eFullMaterials );
+ renderer.Highlight( Renderer::ePrimitive, false );
+ renderer.addRenderable( m_radii_fill, localToWorld );
+ }
+ else
+ {
+ renderer.addRenderable( m_radii_wire, localToWorld );
+ }
+ }
+
+ renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials );
+
+ if ( g_lightType == LIGHTTYPE_DOOM3 && selected ) {
+ if ( isProjected() ) {
+ projection();
+ m_projectionOrientation = rotation();
+ vector4_to_vector3( m_projectionOrientation.t() ) = localAABB().origin;
+ renderer.addRenderable( m_renderProjection, m_projectionOrientation );
+ }
+ else
+ {
+ updateLightRadiiBox();
+ renderer.addRenderable( m_radii_box, localToWorld );
+ }
+
+ //draw the center of the light
+ if ( m_doom3Radius.m_useCenterKey ) {
+ renderer.Highlight( Renderer::ePrimitive, false );
+ renderer.Highlight( Renderer::eFace, false );
+ renderer.SetState( m_render_center.m_state, Renderer::eFullMaterials );
+ renderer.SetState( m_render_center.m_state, Renderer::eWireframeOnly );
+ renderer.addRenderable( m_render_center, localToWorld );
+ }
+ }
+}
+void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
+ renderSolid( renderer, volume, localToWorld, selected );
+ if ( g_showNames ) {
+ renderer.addRenderable( m_renderName, localToWorld );
+ }
+}
+
+void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){
+ test.BeginMesh( localToWorld );
+
+ SelectionIntersection best;
+ aabb_testselect( m_aabb_light, test, best );
+ if ( best.valid() ) {
+ selector.addIntersection( best );
+ }
+}
+
+void translate( const Vector3& translation ){
+ m_aabb_light.origin = origin_translated( m_aabb_light.origin, translation );
+}
+void rotate( const Quaternion& rotation ){
+ rotation_rotate( m_rotation, rotation );
+}
+void snapto( float snap ){
+ if ( g_lightType == LIGHTTYPE_DOOM3 && !m_useLightOrigin && !m_traverse.empty() ) {
+ m_useLightOrigin = true;
+ m_lightOrigin = m_originKey.m_origin;
+ }
+
+ if ( m_useLightOrigin ) {
+ m_lightOrigin = origin_snapped( m_lightOrigin, snap );
+ writeLightOrigin();
+ }
+ else
+ {
+ m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap );
+ 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(){
+ if ( g_lightType == LIGHTTYPE_DOOM3 && !m_useLightOrigin && !m_traverse.empty() ) {
+ m_useLightOrigin = true;
+ }
+
+ if ( m_useLightOrigin ) {
+ m_lightOrigin = m_aabb_light.origin;
+ writeLightOrigin();
+ }
+ else
+ {
+ m_originKey.m_origin = m_aabb_light.origin;
+ m_originKey.write( &m_entity );
+ }
+
+ if ( g_lightType == LIGHTTYPE_DOOM3 ) {
+ if ( !m_useLightRotation && !m_traverse.empty() ) {
+ m_useLightRotation = true;
+ }
+
+ if ( m_useLightRotation ) {
+ rotation_assign( m_lightRotation, m_rotation );
+ write_rotation( m_lightRotation, &m_entity, "light_rotation" );
+ }
+
+ rotation_assign( m_rotationKey.m_rotation, m_rotation );
+ write_rotation( m_rotationKey.m_rotation, &m_entity );
+
+ m_doom3Radius.m_radius = m_doom3Radius.m_radiusTransformed;
+ write_origin( m_doom3Radius.m_radius, &m_entity, "light_radius" );
+ }
+}
+void transformChanged(){
+ revertTransform();
+ m_evaluateTransform();
+ updateOrigin();
+}
+typedef MemberCaller<Light, &Light::transformChanged> TransformChangedCaller;
+
+mutable Matrix4 m_localPivot;
+const Matrix4& getLocalPivot() const {
+ m_localPivot = rotation_toMatrix( m_rotation );
+ vector4_to_vector3( m_localPivot.t() ) = m_aabb_light.origin;
+ return m_localPivot;
+}
+
+void setLightChangedCallback( const Callback& callback ){
+ m_doom3Radius.m_changed = callback;
+}
+
+const AABB& aabb() const {
+ m_doom3AABB = AABB( m_aabb_light.origin, m_doom3Radius.m_radiusTransformed );
+ return m_doom3AABB;
+}
+bool testAABB( const AABB& other ) const {
+ if ( isProjected() ) {
+ Matrix4 transform = rotation();
+ vector4_to_vector3( transform.t() ) = localAABB().origin;
+ projection();
+ Frustum frustum( frustum_transformed( m_doom3Frustum, transform ) );
+ return frustum_test_aabb( frustum, other ) != c_volumeOutside;
+ }
+ // test against an AABB which contains the rotated bounds of this light.
+ const AABB& bounds = aabb();
+ return aabb_intersects_aabb( other, AABB(
+ bounds.origin,
+ Vector3(
+ static_cast<float>( fabs( m_rotation[0] * bounds.extents[0] )
+ + fabs( m_rotation[3] * bounds.extents[1] )
+ + fabs( m_rotation[6] * bounds.extents[2] ) ),
+ static_cast<float>( fabs( m_rotation[1] * bounds.extents[0] )
+ + fabs( m_rotation[4] * bounds.extents[1] )
+ + fabs( m_rotation[7] * bounds.extents[2] ) ),
+ static_cast<float>( fabs( m_rotation[2] * bounds.extents[0] )
+ + fabs( m_rotation[5] * bounds.extents[1] )
+ + fabs( m_rotation[8] * bounds.extents[2] ) )
+ )
+ ) );
+}
+
+const Matrix4& rotation() const {
+ m_doom3Rotation = rotation_toMatrix( m_rotation );
+ return m_doom3Rotation;
+}
+const Vector3& offset() const {
+ return m_doom3Radius.m_center;
+}
+const Vector3& colour() const {
+ return m_colour.m_colour;
+}
+
+bool isProjected() const {
+ return m_useLightTarget && m_useLightUp && m_useLightRight;
+}
+void projectionChanged(){
+ m_doom3ProjectionChanged = true;
+ m_doom3Radius.m_changed();
+ SceneChangeNotify();
+}
+
+const Matrix4& projection() const {
+ if ( !m_doom3ProjectionChanged ) {
+ return m_doom3Projection;
+ }
+ m_doom3ProjectionChanged = false;
+ m_doom3Projection = g_matrix4_identity;
+ matrix4_translate_by_vec3( m_doom3Projection, Vector3( 0.5f, 0.5f, 0 ) );
+ matrix4_scale_by_vec3( m_doom3Projection, Vector3( 0.5f, 0.5f, 1 ) );