+ GenericEntity(EntityClass *eclass, scene::Node &node, const Callback<void()> &transformChanged,
+ const Callback<void()> &evaluateTransform) :
+ m_entity(eclass),
+ m_originKey(OriginChangedCaller(*this)),
+ m_origin(ORIGINKEY_IDENTITY),
+ m_anglesKey(AnglesChangedCaller(*this)),
+ m_angles(ANGLESKEY_IDENTITY),
+ m_filter(m_entity, node),
+ m_named(m_entity),
+ m_nameKeys(m_entity),
+ m_arrow(m_aabb_local.origin, m_angles),
+ m_aabb_solid(m_aabb_local),
+ m_aabb_wire(m_aabb_local),
+ m_renderName(m_named, g_vector3_identity),
+ m_transformChanged(transformChanged),
+ m_evaluateTransform(evaluateTransform)
+ {
+ construct();
+ }
+
+ GenericEntity(const GenericEntity &other, scene::Node &node, const Callback<void()> &transformChanged,
+ const Callback<void()> &evaluateTransform) :
+ m_entity(other.m_entity),
+ m_originKey(OriginChangedCaller(*this)),
+ m_origin(ORIGINKEY_IDENTITY),
+ m_anglesKey(AnglesChangedCaller(*this)),
+ m_angles(ANGLESKEY_IDENTITY),
+ m_filter(m_entity, node),
+ m_named(m_entity),
+ m_nameKeys(m_entity),
+ m_arrow(m_aabb_local.origin, m_angles),
+ m_aabb_solid(m_aabb_local),
+ m_aabb_wire(m_aabb_local),
+ m_renderName(m_named, g_vector3_identity),
+ m_transformChanged(transformChanged),
+ m_evaluateTransform(evaluateTransform)
+ {
+ construct();
+ }
+
+ 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()));
+ m_entity.attach(m_keyObservers);
+ }
+ }
+
+ void instanceDetach(const scene::Path &path)
+ {
+ if (--m_instanceCounter.m_count == 0) {
+ m_entity.detach(m_keyObservers);
+ 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;
+ }
+
+ Namespaced &getNamespaced()
+ {
+ return m_nameKeys;
+ }
+
+ Nameable &getNameable()
+ {
+ return m_named;
+ }
+
+ TransformNode &getTransformNode()
+ {
+ return m_transform;
+ }
+
+ const AABB &localAABB() const
+ {
+ return m_aabb_local;
+ }
+
+ VolumeIntersectionValue intersectVolume(const VolumeTest &volume, const Matrix4 &localToWorld) const
+ {
+ return volume.TestAABB(localAABB(), localToWorld);
+ }
+
+ void renderArrow(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
+ {
+ if (g_showAngles) {
+ renderer.addRenderable(m_arrow, localToWorld);
+ }
+ }
+
+ void renderSolid(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
+ {
+ renderer.SetState(m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials);
+ renderer.addRenderable(m_aabb_solid, localToWorld);
+ renderArrow(renderer, volume, localToWorld);
+ }
+
+ void renderWireframe(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
+ {
+ renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
+ renderer.addRenderable(m_aabb_wire, localToWorld);
+ renderArrow(renderer, volume, localToWorld);
+ 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_local, test, best);
+ if (best.valid()) {
+ selector.addIntersection(best);
+ }
+ }
+
+ void translate(const Vector3 &translation)
+ {
+ m_origin = origin_translated(m_origin, translation);
+ }
+
+ void rotate(const Quaternion &rotation)
+ {
+ m_angles = angles_rotated(m_angles, rotation);
+ }
+
+ void snapto(float snap)
+ {
+ m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
+ m_originKey.write(&m_entity);
+ }
+
+ void revertTransform()
+ {
+ m_origin = m_originKey.m_origin;
+ m_angles = m_anglesKey.m_angles;
+ }
+
+ void freezeTransform()
+ {
+ m_originKey.m_origin = m_origin;
+ m_originKey.write(&m_entity);
+ m_anglesKey.m_angles = m_angles;
+ m_anglesKey.write(&m_entity);
+ }
+
+ void transformChanged()
+ {
+ revertTransform();
+ m_evaluateTransform();
+ updateTransform();
+ }
+
+ typedef MemberCaller<GenericEntity, void(), &GenericEntity::transformChanged> TransformChangedCaller;