X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=radiant%2Fbrush.h;h=66c057403a213da9d06d2bfd930aa7de5017b367;hp=851a9836524270ede2f6ce02c58a0251a38ac44b;hb=5a4c0cc6bcd809371f556be2d383a305c23d7881;hpb=70fe5a7feb56241108699fc89c8db4fccf66a3c4 diff --git a/radiant/brush.h b/radiant/brush.h index 851a9836..66c05740 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -1,4218 +1,89 @@ /* -Copyright (C) 1999-2006 Id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#if !defined(INCLUDED_BRUSH_H) -#define INCLUDED_BRUSH_H - -/// \file -/// \brief The brush primitive. -/// -/// A collection of planes that define a convex polyhedron. -/// The Boundary-Representation of this primitive is a manifold polygonal mesh. -/// Each face polygon is represented by a list of vertices in a \c Winding. -/// Each vertex is associated with another face that is adjacent to the edge -/// formed by itself and the next vertex in the winding. This information can -/// be used to find edge-pairs and vertex-rings. - - -#include "debugging/debugging.h" - -#include "itexdef.h" -#include "iundo.h" -#include "iselection.h" -#include "irender.h" -#include "imap.h" -#include "ibrush.h" -#include "igl.h" -#include "ifilter.h" -#include "nameable.h" -#include "moduleobserver.h" - -#include - -#include "cullable.h" -#include "renderable.h" -#include "selectable.h" -#include "editable.h" -#include "mapfile.h" - -#include "math/frustum.h" -#include "selectionlib.h" -#include "render.h" -#include "texturelib.h" -#include "container/container.h" -#include "generic/bitfield.h" -#include "signal/signalfwd.h" - -#include "winding.h" -#include "brush_primit.h" - -const unsigned int BRUSH_DETAIL_FLAG = 27; -const unsigned int BRUSH_DETAIL_MASK = (1 << BRUSH_DETAIL_FLAG); - -enum EBrushType -{ - eBrushTypeQuake, - eBrushTypeQuake2, - eBrushTypeQuake3, - eBrushTypeQuake3BP, - eBrushTypeDoom3, - eBrushTypeQuake4, - eBrushTypeHalfLife, -}; - - -#define BRUSH_CONNECTIVITY_DEBUG 0 -#define BRUSH_DEGENERATE_DEBUG 0 - -template -inline TextOuputStreamType& ostream_write(TextOuputStreamType& ostream, const Matrix4& m) -{ - return ostream << "(" << m[0] << " " << m[1] << " " << m[2] << " " << m[3] << ", " - << m[4] << " " << m[5] << " " << m[6] << " " << m[7] << ", " - << m[8] << " " << m[9] << " " << m[10] << " " << m[11] << ", " - << m[12] << " " << m[13] << " " << m[14] << " " << m[15] << ")"; -} - -inline void print_vector3(const Vector3& v) -{ - globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )\n"; -} - -inline void print_3x3(const Matrix4& m) -{ - globalOutputStream() << "( " << m.xx() << " " << m.xy() << " " << m.xz() << " ) " - << "( " << m.yx() << " " << m.yy() << " " << m.yz() << " ) " - << "( " << m.zx() << " " << m.zy() << " " << m.zz() << " )\n"; -} - - - -inline bool texdef_sane(const texdef_t& texdef) -{ - return fabs(texdef.shift[0]) < (1 << 16) - && fabs(texdef.shift[1]) < (1 << 16); -} - -inline void Winding_DrawWireframe(const Winding& winding) -{ - glVertexPointer(3, GL_FLOAT, sizeof(WindingVertex), &winding.points.data()->vertex); - glDrawArrays(GL_LINE_LOOP, 0, GLsizei(winding.numpoints)); -} - -inline void Winding_Draw(const Winding& winding, const Vector3& normal, RenderStateFlags state) -{ - glVertexPointer(3, GL_FLOAT, sizeof(WindingVertex), &winding.points.data()->vertex); - - if((state & RENDER_BUMP) != 0) - { - Vector3 normals[c_brush_maxFaces]; - typedef Vector3* Vector3Iter; - for(Vector3Iter i = normals, end = normals + winding.numpoints; i != end; ++i) - { - *i = normal; - } - if(GlobalShaderCache().useShaderLanguage()) - { - glNormalPointer(GL_FLOAT, sizeof(Vector3), normals); - glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->texcoord); - glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->tangent); - glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->bitangent); - } - else - { - glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(Vector3), normals); - glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->texcoord); - glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->tangent); - glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(WindingVertex), &winding.points.data()->bitangent); - } - } - else - { - if (state & RENDER_LIGHTING) - { - Vector3 normals[c_brush_maxFaces]; - typedef Vector3* Vector3Iter; - for(Vector3Iter i = normals, last = normals + winding.numpoints; i != last; ++i) - { - *i = normal; - } - glNormalPointer(GL_FLOAT, sizeof(Vector3), normals); - } - - if (state & RENDER_TEXTURE) - { - glTexCoordPointer(2, GL_FLOAT, sizeof(WindingVertex), &winding.points.data()->texcoord); - } - } -#if 0 - if (state & RENDER_FILL) - { - glDrawArrays(GL_TRIANGLE_FAN, 0, GLsizei(winding.numpoints)); - } - else - { - glDrawArrays(GL_LINE_LOOP, 0, GLsizei(winding.numpoints)); - } -#else - glDrawArrays(GL_POLYGON, 0, GLsizei(winding.numpoints)); -#endif - -#if 0 - const Winding& winding = winding; - - if(state & RENDER_FILL) - { - glBegin(GL_POLYGON); - } - else - { - glBegin(GL_LINE_LOOP); - } - - if (state & RENDER_LIGHTING) - glNormal3fv(normal); - - for(int i = 0; i < winding.numpoints; ++i) - { - if (state & RENDER_TEXTURE) - glTexCoord2fv(&winding.points[i][3]); - glVertex3fv(winding.points[i]); - } - glEnd(); -#endif -} - - -#include "shaderlib.h" - -typedef DoubleVector3 PlanePoints[3]; - -inline bool planepts_equal(const PlanePoints planepts, const PlanePoints other) -{ - return planepts[0] == other[0] && planepts[1] == other[1] && planepts[2] == other[2]; -} - -inline void planepts_assign(PlanePoints planepts, const PlanePoints other) -{ - planepts[0] = other[0]; - planepts[1] = other[1]; - planepts[2] = other[2]; -} - -inline void planepts_quantise(PlanePoints planepts, double snap) -{ - vector3_snap(planepts[0], snap); - vector3_snap(planepts[1], snap); - vector3_snap(planepts[2], snap); -} - -inline float vector3_max_component(const Vector3& vec3) -{ - return std::max(fabsf(vec3[0]), std::max(fabsf(vec3[1]), fabsf(vec3[2]))); -} - -inline void edge_snap(Vector3& edge, double snap) -{ - float scale = static_cast(ceil(fabs(snap / vector3_max_component(edge)))); - if(scale > 0.0f) - { - vector3_scale(edge, scale); - } - vector3_snap(edge, snap); -} - -inline void planepts_snap(PlanePoints planepts, double snap) -{ - Vector3 edge01(vector3_subtracted(planepts[1], planepts[0])); - Vector3 edge12(vector3_subtracted(planepts[2], planepts[1])); - Vector3 edge20(vector3_subtracted(planepts[0], planepts[2])); - - double length_squared_01 = vector3_dot(edge01, edge01); - double length_squared_12 = vector3_dot(edge12, edge12); - double length_squared_20 = vector3_dot(edge20, edge20); - - vector3_snap(planepts[0], snap); - - if(length_squared_01 < length_squared_12) - { - if(length_squared_12 < length_squared_20) - { - edge_snap(edge01, snap); - edge_snap(edge12, snap); - planepts[1] = vector3_added(planepts[0], edge01); - planepts[2] = vector3_added(planepts[1], edge12); - } - else - { - edge_snap(edge20, snap); - edge_snap(edge01, snap); - planepts[1] = vector3_added(planepts[0], edge20); - planepts[2] = vector3_added(planepts[1], edge01); - } - } - else - { - if(length_squared_01 < length_squared_20) - { - edge_snap(edge01, snap); - edge_snap(edge12, snap); - planepts[1] = vector3_added(planepts[0], edge01); - planepts[2] = vector3_added(planepts[1], edge12); - } - else - { - edge_snap(edge12, snap); - edge_snap(edge20, snap); - planepts[1] = vector3_added(planepts[0], edge12); - planepts[2] = vector3_added(planepts[1], edge20); - } - } -} - -inline PointVertex pointvertex_for_planept(const DoubleVector3& point, const Colour4b& colour) -{ - return PointVertex( - Vertex3f( - static_cast(point.x()), - static_cast(point.y()), - static_cast(point.z()) - ), - colour - ); -} - -inline PointVertex pointvertex_for_windingpoint(const Vector3& point, const Colour4b& colour) -{ - return PointVertex( - vertex3f_for_vector3(point), - colour - ); -} - -inline bool check_plane_is_integer(const PlanePoints& planePoints) -{ - return !float_is_integer(planePoints[0][0]) - || !float_is_integer(planePoints[0][1]) - || !float_is_integer(planePoints[0][2]) - || !float_is_integer(planePoints[1][0]) - || !float_is_integer(planePoints[1][1]) - || !float_is_integer(planePoints[1][2]) - || !float_is_integer(planePoints[2][0]) - || !float_is_integer(planePoints[2][1]) - || !float_is_integer(planePoints[2][2]); -} - -inline void brush_check_shader(const char* name) -{ - if(!shader_valid(name)) - { - globalErrorStream() << "brush face has invalid texture name: '" << name << "'\n"; - } -} - -class FaceShaderObserver -{ -public: - virtual void realiseShader() = 0; - virtual void unrealiseShader() = 0; -}; - -class FaceShaderObserverRealise -{ -public: - void operator()(FaceShaderObserver& observer) const - { - observer.realiseShader(); - } -}; - -class FaceShaderObserverUnrealise -{ -public: - void operator()(FaceShaderObserver& observer) const - { - observer.unrealiseShader(); - } -}; - -typedef ReferencePair FaceShaderObserverPair; - - -class ContentsFlagsValue -{ -public: - ContentsFlagsValue() - { - } - ContentsFlagsValue(int surfaceFlags, int contentFlags, int value, bool specified) : - m_surfaceFlags(surfaceFlags), - m_contentFlags(contentFlags), - m_value(value), - m_specified(specified) - { - } - int m_surfaceFlags; - int m_contentFlags; - int m_value; - bool m_specified; -}; - -inline void ContentsFlagsValue_assignMasked(ContentsFlagsValue& flags, const ContentsFlagsValue& other) -{ - bool detail = bitfield_enabled(flags.m_contentFlags, BRUSH_DETAIL_MASK); - flags = other; - if(detail) - { - flags.m_contentFlags = bitfield_enable(flags.m_contentFlags, BRUSH_DETAIL_MASK); - } - else - { - flags.m_contentFlags = bitfield_disable(flags.m_contentFlags, BRUSH_DETAIL_MASK); - } -} - - -class FaceShader : public ModuleObserver -{ -public: - class SavedState - { - public: - CopiedString m_shader; - ContentsFlagsValue m_flags; - - SavedState(const FaceShader& faceShader) - { - m_shader = faceShader.getShader(); - m_flags = faceShader.m_flags; - } - - void exportState(FaceShader& faceShader) const - { - faceShader.setShader(m_shader.c_str()); - faceShader.setFlags(m_flags); - } - }; - - CopiedString m_shader; - Shader* m_state; - ContentsFlagsValue m_flags; - FaceShaderObserverPair m_observers; - bool m_instanced; - bool m_realised; - - FaceShader(const char* shader, const ContentsFlagsValue& flags = ContentsFlagsValue(0, 0, 0, false)) : - m_shader(shader), - m_state(0), - m_flags(flags), - m_instanced(false), - m_realised(false) - { - captureShader(); - } - ~FaceShader() - { - releaseShader(); - } - // copy-construction not supported - FaceShader(const FaceShader& other); - - void instanceAttach() - { - m_instanced = true; - m_state->incrementUsed(); - } - void instanceDetach() - { - m_state->decrementUsed(); - m_instanced = false; - } - - void captureShader() - { - ASSERT_MESSAGE(m_state == 0, "shader cannot be captured"); - brush_check_shader(m_shader.c_str()); - m_state = GlobalShaderCache().capture(m_shader.c_str()); - m_state->attach(*this); - } - void releaseShader() - { - ASSERT_MESSAGE(m_state != 0, "shader cannot be released"); - m_state->detach(*this); - GlobalShaderCache().release(m_shader.c_str()); - m_state = 0; - } - - void realise() - { - ASSERT_MESSAGE(!m_realised, "FaceTexdef::realise: already realised"); - m_realised = true; - m_observers.forEach(FaceShaderObserverRealise()); - } - void unrealise() - { - ASSERT_MESSAGE(m_realised, "FaceTexdef::unrealise: already unrealised"); - m_observers.forEach(FaceShaderObserverUnrealise()); - m_realised = false; - } - - void attach(FaceShaderObserver& observer) - { - m_observers.attach(observer); - if(m_realised) - { - observer.realiseShader(); - } - } - - void detach(FaceShaderObserver& observer) - { - if(m_realised) - { - observer.unrealiseShader(); - } - m_observers.detach(observer); - } - - const char* getShader() const - { - return m_shader.c_str(); - } - void setShader(const char* name) - { - if(m_instanced) - { - m_state->decrementUsed(); - } - releaseShader(); - m_shader = name; - captureShader(); - if(m_instanced) - { - m_state->incrementUsed(); - } - } - ContentsFlagsValue getFlags() const - { - ASSERT_MESSAGE(m_realised, "FaceShader::getFlags: flags not valid when unrealised"); - if(!m_flags.m_specified) - { - return ContentsFlagsValue( - m_state->getTexture().surfaceFlags, - m_state->getTexture().contentFlags, - m_state->getTexture().value, - true - ); - } - return m_flags; - } - void setFlags(const ContentsFlagsValue& flags) - { - ASSERT_MESSAGE(m_realised, "FaceShader::setFlags: flags not valid when unrealised"); - ContentsFlagsValue_assignMasked(m_flags, flags); - } - - Shader* state() const - { - return m_state; - } - - std::size_t width() const - { - if(m_realised) - { - return m_state->getTexture().width; - } - return 1; - } - std::size_t height() const - { - if(m_realised) - { - return m_state->getTexture().height; - } - return 1; - } - unsigned int shaderFlags() const - { - if(m_realised) - { - return m_state->getFlags(); - } - return 0; - } -}; - - - - -class FaceTexdef : public FaceShaderObserver -{ - // not copyable - FaceTexdef(const FaceTexdef& other); - // not assignable - FaceTexdef& operator=(const FaceTexdef& other); -public: - class SavedState - { - public: - TextureProjection m_projection; - - SavedState(const FaceTexdef& faceTexdef) - { - m_projection = faceTexdef.m_projection; - } - - void exportState(FaceTexdef& faceTexdef) const - { - Texdef_Assign(faceTexdef.m_projection, m_projection); - } - }; - - FaceShader& m_shader; - TextureProjection m_projection; - bool m_projectionInitialised; - bool m_scaleApplied; - - FaceTexdef( - FaceShader& shader, - const TextureProjection& projection, - bool projectionInitialised = true - ) : - m_shader(shader), - m_projection(projection), - m_projectionInitialised(projectionInitialised), - m_scaleApplied(false) - { - m_shader.attach(*this); - } - ~FaceTexdef() - { - m_shader.detach(*this); - } - - void addScale() - { - ASSERT_MESSAGE(!m_scaleApplied, "texture scale aready added"); - m_scaleApplied = true; - m_projection.m_brushprimit_texdef.addScale(m_shader.width(), m_shader.height()); - } - void removeScale() - { - ASSERT_MESSAGE(m_scaleApplied, "texture scale aready removed"); - m_scaleApplied = false; - m_projection.m_brushprimit_texdef.removeScale(m_shader.width(), m_shader.height()); - } - - void realiseShader() - { - if(m_projectionInitialised && !m_scaleApplied) - { - addScale(); - } - } - void unrealiseShader() - { - if(m_projectionInitialised && m_scaleApplied) - { - removeScale(); - } - } - - void setTexdef(const TextureProjection& projection) - { - removeScale(); - Texdef_Assign(m_projection, projection); - addScale(); - } - - void shift(float s, float t) - { - ASSERT_MESSAGE(texdef_sane(m_projection.m_texdef), "FaceTexdef::shift: bad texdef"); - removeScale(); - Texdef_Shift(m_projection, s, t); - addScale(); - } - - void scale(float s, float t) - { - removeScale(); - Texdef_Scale(m_projection, s, t); - addScale(); - } - - void rotate(float angle) - { - removeScale(); - Texdef_Rotate(m_projection, angle); - addScale(); - } - - void fit(const Vector3& normal, const Winding& winding, float s_repeat, float t_repeat) - { - Texdef_FitTexture(m_projection, m_shader.width(), m_shader.height(), normal, winding, s_repeat, t_repeat); - } - - void emitTextureCoordinates(Winding& winding, const Vector3& normal, const Matrix4& localToWorld) - { - Texdef_EmitTextureCoordinates(m_projection, m_shader.width(), m_shader.height(), winding, normal, localToWorld); - } - - void transform(const Plane3& plane, const Matrix4& matrix) - { - removeScale(); - Texdef_transformLocked(m_projection, m_shader.width(), m_shader.height(), plane, matrix); - addScale(); - } - - TextureProjection normalised() const - { - brushprimit_texdef_t tmp(m_projection.m_brushprimit_texdef); - tmp.removeScale(m_shader.width(), m_shader.height()); - return TextureProjection(m_projection.m_texdef, tmp, m_projection.m_basis_s, m_projection.m_basis_t); - } - void setBasis(const Vector3& normal) - { - Matrix4 basis; - Normal_GetTransform(normal, basis); - m_projection.m_basis_s = Vector3(basis.xx(), basis.yx(), basis.zx()); - m_projection.m_basis_t = Vector3(-basis.xy(), -basis.yy(), -basis.zy()); - } -}; - -inline void planepts_print(const PlanePoints& planePoints, TextOutputStream& ostream) -{ - ostream << "( " << planePoints[0][0] << " " << planePoints[0][1] << " " << planePoints[0][2] << " ) " - << "( " << planePoints[1][0] << " " << planePoints[1][1] << " " << planePoints[1][2] << " ) " - << "( " << planePoints[2][0] << " " << planePoints[2][1] << " " << planePoints[2][2] << " )"; -} - - -inline Plane3 Plane3_applyTranslation(const Plane3& plane, const Vector3& translation) -{ - Plane3 tmp(plane3_translated(Plane3(plane.normal(), -plane.dist()), translation)); - return Plane3(tmp.normal(), -tmp.dist()); -} - -inline Plane3 Plane3_applyTransform(const Plane3& plane, const Matrix4& matrix) -{ - Plane3 tmp(plane3_transformed(Plane3(plane.normal(), -plane.dist()), matrix)); - return Plane3(tmp.normal(), -tmp.dist()); -} - -class FacePlane -{ - PlanePoints m_planepts; - Plane3 m_planeCached; - Plane3 m_plane; -public: - Vector3 m_funcStaticOrigin; - - static EBrushType m_type; - - static bool isDoom3Plane() - { - return FacePlane::m_type == eBrushTypeDoom3 || FacePlane::m_type == eBrushTypeQuake4; - } - - class SavedState - { - public: - PlanePoints m_planepts; - Plane3 m_plane; - - SavedState(const FacePlane& facePlane) - { - if(facePlane.isDoom3Plane()) - { - m_plane = facePlane.m_plane; - } - else - { - planepts_assign(m_planepts, facePlane.planePoints()); - } - } - - void exportState(FacePlane& facePlane) const - { - if(facePlane.isDoom3Plane()) - { - facePlane.m_plane = m_plane; - facePlane.updateTranslated(); - } - else - { - planepts_assign(facePlane.planePoints(), m_planepts); - facePlane.MakePlane(); - } - } - }; - - FacePlane() : m_funcStaticOrigin(0, 0, 0) - { - } - FacePlane(const FacePlane& other) : m_funcStaticOrigin(0, 0, 0) - { - if(!isDoom3Plane()) - { - planepts_assign(m_planepts, other.m_planepts); - MakePlane(); - } - else - { - m_plane = other.m_plane; - updateTranslated(); - } - } - - void MakePlane() - { - if(!isDoom3Plane()) - { -#if 0 - if(check_plane_is_integer(m_planepts)) - { - globalErrorStream() << "non-integer planepts: "; - planepts_print(m_planepts, globalErrorStream()); - globalErrorStream() << "\n"; - } -#endif - m_planeCached = plane3_for_points(m_planepts); - } - } - - void reverse() - { - if(!isDoom3Plane()) - { - vector3_swap(m_planepts[0], m_planepts[2]); - MakePlane(); - } - else - { - m_planeCached = plane3_flipped(m_plane); - updateSource(); - } - } - void transform(const Matrix4& matrix, bool mirror) - { - if(!isDoom3Plane()) - { - -#if 0 - bool off = check_plane_is_integer(planePoints()); -#endif - - matrix4_transform_point(matrix, m_planepts[0]); - matrix4_transform_point(matrix, m_planepts[1]); - matrix4_transform_point(matrix, m_planepts[2]); - - if(mirror) - { - reverse(); - } - -#if 0 - if(check_plane_is_integer(planePoints())) - { - if(!off) - { - globalErrorStream() << "caused by transform\n"; - } - } -#endif - MakePlane(); - } - else - { - m_planeCached = Plane3_applyTransform(m_planeCached, matrix); - updateSource(); - } - } - void offset(float offset) - { - if(!isDoom3Plane()) - { - Vector3 move(vector3_scaled(m_planeCached.normal(), -offset)); - - vector3_subtract(m_planepts[0], move); - vector3_subtract(m_planepts[1], move); - vector3_subtract(m_planepts[2], move); - - MakePlane(); - } - else - { - m_planeCached.d += offset; - updateSource(); - } - } - - void updateTranslated() - { - m_planeCached = Plane3_applyTranslation(m_plane, m_funcStaticOrigin); - } - void updateSource() - { - m_plane = Plane3_applyTranslation(m_planeCached, vector3_negated(m_funcStaticOrigin)); - } - - - PlanePoints& planePoints() - { - return m_planepts; - } - const PlanePoints& planePoints() const - { - return m_planepts; - } - const Plane3& plane3() const - { - return m_planeCached; - } - void setDoom3Plane(const Plane3& plane) - { - m_plane = plane; - updateTranslated(); - } - const Plane3& getDoom3Plane() const - { - return m_plane; - } - - void copy(const FacePlane& other) - { - if(!isDoom3Plane()) - { - planepts_assign(m_planepts, other.m_planepts); - MakePlane(); - } - else - { - m_planeCached = other.m_plane; - updateSource(); - } - } - void copy(const Vector3& p0, const Vector3& p1, const Vector3& p2) - { - if(!isDoom3Plane()) - { - m_planepts[0] = p0; - m_planepts[1] = p1; - m_planepts[2] = p2; - MakePlane(); - } - else - { - m_planeCached = plane3_for_points(p2, p1, p0); - updateSource(); - } - } -}; - -inline void Winding_testSelect(Winding& winding, SelectionTest& test, SelectionIntersection& best) -{ - test.TestPolygon(VertexPointer(reinterpret_cast(&winding.points.data()->vertex), sizeof(WindingVertex)), winding.numpoints, best); -} - -const double GRID_MIN = 0.125; - -inline double quantiseInteger(double f) -{ - return float_to_integer(f); -} - -inline double quantiseFloating(double f) -{ - return float_snapped(f, 1.f / (1 << 16)); -} - -typedef double (*QuantiseFunc)(double f); - -class Face; - -class FaceFilter -{ -public: - virtual bool filter(const Face& face) const = 0; -}; - -bool face_filtered(Face& face); -void add_face_filter(FaceFilter& filter, int mask, bool invert = false); - -void Brush_addTextureChangedCallback(const SignalHandler& callback); -void Brush_textureChanged(); - - -extern bool g_brush_texturelock_enabled; - -class FaceObserver -{ -public: - virtual void planeChanged() = 0; - virtual void connectivityChanged() = 0; - virtual void shaderChanged() = 0; - virtual void evaluateTransform() = 0; -}; - -class Face : -public OpenGLRenderable, -public Filterable, -public Undoable, -public FaceShaderObserver -{ - std::size_t m_refcount; - - class SavedState : public UndoMemento - { - public: - FacePlane::SavedState m_planeState; - FaceTexdef::SavedState m_texdefState; - FaceShader::SavedState m_shaderState; - - SavedState(const Face& face) : m_planeState(face.getPlane()), m_texdefState(face.getTexdef()), m_shaderState(face.getShader()) - { - } - - void exportState(Face& face) const - { - m_planeState.exportState(face.getPlane()); - m_shaderState.exportState(face.getShader()); - m_texdefState.exportState(face.getTexdef()); - } - - void release() - { - delete this; - } - }; - -public: - static QuantiseFunc m_quantise; - static EBrushType m_type; - - PlanePoints m_move_planepts; - PlanePoints m_move_planeptsTransformed; -private: - FacePlane m_plane; - FacePlane m_planeTransformed; - FaceShader m_shader; - FaceTexdef m_texdef; - TextureProjection m_texdefTransformed; - - Winding m_winding; - Vector3 m_centroid; - bool m_filtered; - - FaceObserver* m_observer; - UndoObserver* m_undoable_observer; - MapFile* m_map; - - // assignment not supported - Face& operator=(const Face& other); - // copy-construction not supported - Face(const Face& other); - -public: - - Face(FaceObserver* observer) : - m_refcount(0), - m_shader(texdef_name_default()), - m_texdef(m_shader, TextureProjection(), false), - m_filtered(false), - m_observer(observer), - m_undoable_observer(0), - m_map(0) - { - m_shader.attach(*this); - m_plane.copy(Vector3(0, 0, 0), Vector3(64, 0, 0), Vector3(0, 64, 0)); - m_texdef.setBasis(m_plane.plane3().normal()); - planeChanged(); - } - Face( - const Vector3& p0, - const Vector3& p1, - const Vector3& p2, - const char* shader, - const TextureProjection& projection, - FaceObserver* observer - ) : - m_refcount(0), - m_shader(shader), - m_texdef(m_shader, projection), - m_observer(observer), - m_undoable_observer(0), - m_map(0) - { - m_shader.attach(*this); - m_plane.copy(p0, p1, p2); - m_texdef.setBasis(m_plane.plane3().normal()); - planeChanged(); - updateFiltered(); - } - Face(const Face& other, FaceObserver* observer) : - m_refcount(0), - m_shader(other.m_shader.getShader(), other.m_shader.m_flags), - m_texdef(m_shader, other.getTexdef().normalised()), - m_observer(observer), - m_undoable_observer(0), - m_map(0) - { - m_shader.attach(*this); - m_plane.copy(other.m_plane); - planepts_assign(m_move_planepts, other.m_move_planepts); - m_texdef.setBasis(m_plane.plane3().normal()); - planeChanged(); - updateFiltered(); - } - ~Face() - { - m_shader.detach(*this); - } - - void planeChanged() - { - revertTransform(); - m_observer->planeChanged(); - } - - void realiseShader() - { - m_observer->shaderChanged(); - } - void unrealiseShader() - { - } - - void instanceAttach(MapFile* map) - { - m_shader.instanceAttach(); - m_map = map; - m_undoable_observer = GlobalUndoSystem().observer(this); - GlobalFilterSystem().registerFilterable(*this); - } - void instanceDetach(MapFile* map) - { - GlobalFilterSystem().unregisterFilterable(*this); - m_undoable_observer = 0; - GlobalUndoSystem().release(this); - m_map = 0; - m_shader.instanceDetach(); - } - - void render(RenderStateFlags state) const - { - Winding_Draw(m_winding, m_planeTransformed.plane3().normal(), state); - } - - void updateFiltered() - { - m_filtered = face_filtered(*this); - } - bool isFiltered() const - { - return m_filtered; - } - - void undoSave() - { - if(m_map != 0) - { - m_map->changed(); - } - if(m_undoable_observer != 0) - { - m_undoable_observer->save(this); - } - } - - // undoable - UndoMemento* exportState() const - { - return new SavedState(*this); - } - void importState(const UndoMemento* data) - { - undoSave(); - - static_cast(data)->exportState(*this); - - planeChanged(); - m_observer->connectivityChanged(); - texdefChanged(); - m_observer->shaderChanged(); - updateFiltered(); - } - - void IncRef() - { - ++m_refcount; - } - void DecRef() - { - if(--m_refcount == 0) - delete this; - } - - void flipWinding() - { - m_plane.reverse(); - planeChanged(); - } - - bool intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const - { - return volume.TestPlane(Plane3(plane3().normal(), -plane3().dist()), localToWorld); - } - - void render(Renderer& renderer, const Matrix4& localToWorld) const - { - renderer.SetState(m_shader.state(), Renderer::eFullMaterials); - renderer.addRenderable(*this, localToWorld); - } - - void transform(const Matrix4& matrix, bool mirror) - { - if(g_brush_texturelock_enabled) - { - Texdef_transformLocked(m_texdefTransformed, m_shader.width(), m_shader.height(), m_plane.plane3(), matrix); - } - - m_planeTransformed.transform(matrix, mirror); - -#if 0 - ASSERT_MESSAGE(projectionaxis_for_normal(normal) == projectionaxis_for_normal(plane3().normal()), "bleh"); -#endif - m_observer->planeChanged(); - } - - void assign_planepts(const PlanePoints planepts) - { - m_planeTransformed.copy(planepts[0], planepts[1], planepts[2]); - m_observer->planeChanged(); - } - - /// \brief Reverts the transformable state of the brush to identity. - void revertTransform() - { - m_planeTransformed = m_plane; - planepts_assign(m_move_planeptsTransformed, m_move_planepts); - m_texdefTransformed = m_texdef.m_projection; - } - void freezeTransform() - { - undoSave(); - m_plane = m_planeTransformed; - planepts_assign(m_move_planepts, m_move_planeptsTransformed); - m_texdef.m_projection = m_texdefTransformed; - } - - void update_move_planepts_vertex(std::size_t index, PlanePoints planePoints) - { - std::size_t numpoints = getWinding().numpoints; - ASSERT_MESSAGE(index < numpoints, "update_move_planepts_vertex: invalid index"); - - std::size_t opposite = Winding_Opposite(getWinding(), index); - std::size_t adjacent = Winding_wrap(getWinding(), opposite+numpoints-1); - planePoints[0] = getWinding()[opposite].vertex; - planePoints[1] = getWinding()[index].vertex; - planePoints[2] = getWinding()[adjacent].vertex; - // winding points are very inaccurate, so they must be quantised before using them to generate the face-plane - planepts_quantise(planePoints, GRID_MIN); - } - - void snapto(float snap) - { - if(contributes()) - { -#if 0 - ASSERT_MESSAGE(plane3_valid(m_plane.plane3()), "invalid plane before snap to grid"); - planepts_snap(m_plane.planePoints(), snap); - ASSERT_MESSAGE(plane3_valid(m_plane.plane3()), "invalid plane after snap to grid"); -#else - PlanePoints planePoints; - update_move_planepts_vertex(0, planePoints); - vector3_snap(planePoints[0], snap); - vector3_snap(planePoints[1], snap); - vector3_snap(planePoints[2], snap); - assign_planepts(planePoints); - freezeTransform(); -#endif - SceneChangeNotify(); - if(!plane3_valid(m_plane.plane3())) - { - globalErrorStream() << "WARNING: invalid plane after snap to grid\n"; - } - } - } - - void testSelect(SelectionTest& test, SelectionIntersection& best) - { - Winding_testSelect(m_winding, test, best); - } - - void testSelect_centroid(SelectionTest& test, SelectionIntersection& best) - { - test.TestPoint(m_centroid, best); - } - - void shaderChanged() - { - EmitTextureCoordinates(); - Brush_textureChanged(); - m_observer->shaderChanged(); - updateFiltered(); - planeChanged(); - SceneChangeNotify(); - } - - const char* GetShader() const - { - return m_shader.getShader(); - } - void SetShader(const char* name) - { - undoSave(); - m_shader.setShader(name); - shaderChanged(); - } - - void revertTexdef() - { - m_texdefTransformed = m_texdef.m_projection; - } - void texdefChanged() - { - revertTexdef(); - EmitTextureCoordinates(); - Brush_textureChanged(); - } - - void GetTexdef(TextureProjection& projection) const - { - projection = m_texdef.normalised(); - } - void SetTexdef(const TextureProjection& projection) - { - undoSave(); - m_texdef.setTexdef(projection); - texdefChanged(); - } - - void GetFlags(ContentsFlagsValue& flags) const - { - flags = m_shader.getFlags(); - } - void SetFlags(const ContentsFlagsValue& flags) - { - undoSave(); - m_shader.setFlags(flags); - m_observer->shaderChanged(); - updateFiltered(); - } - - void ShiftTexdef(float s, float t) - { - undoSave(); - m_texdef.shift(s, t); - texdefChanged(); - } - - void ScaleTexdef(float s, float t) - { - undoSave(); - m_texdef.scale(s, t); - texdefChanged(); - } - - void RotateTexdef(float angle) - { - undoSave(); - m_texdef.rotate(angle); - texdefChanged(); - } - - void FitTexture(float s_repeat, float t_repeat) - { - undoSave(); - m_texdef.fit(m_plane.plane3().normal(), m_winding, s_repeat, t_repeat); - texdefChanged(); - } - - void EmitTextureCoordinates() - { - Texdef_EmitTextureCoordinates(m_texdefTransformed, m_shader.width(), m_shader.height(), m_winding, plane3().normal(), g_matrix4_identity); - } - - - const Vector3& centroid() const - { - return m_centroid; - } - - void construct_centroid() - { - Winding_Centroid(m_winding, plane3(), m_centroid); - } - - const Winding& getWinding() const - { - return m_winding; - } - Winding& getWinding() - { - return m_winding; - } - - const Plane3& plane3() const - { - m_observer->evaluateTransform(); - return m_planeTransformed.plane3(); - } - FacePlane& getPlane() - { - return m_plane; - } - const FacePlane& getPlane() const - { - return m_plane; - } - FaceTexdef& getTexdef() - { - return m_texdef; - } - const FaceTexdef& getTexdef() const - { - return m_texdef; - } - FaceShader& getShader() - { - return m_shader; - } - const FaceShader& getShader() const - { - return m_shader; - } - - bool isDetail() const - { - return (m_shader.m_flags.m_contentFlags & BRUSH_DETAIL_MASK) != 0; - } - void setDetail(bool detail) - { - undoSave(); - if(detail && !isDetail()) - { - m_shader.m_flags.m_contentFlags |= BRUSH_DETAIL_MASK; - } - else if(!detail && isDetail()) - { - m_shader.m_flags.m_contentFlags &= ~BRUSH_DETAIL_MASK; - } - m_observer->shaderChanged(); - } - - bool contributes() const - { - return m_winding.numpoints > 2; - } - bool is_bounded() const - { - for(Winding::const_iterator i = m_winding.begin(); i != m_winding.end(); ++i) - { - if((*i).adjacent == c_brush_maxFaces) - { - return false; - } - } - return true; - } -}; - - -class FaceVertexId -{ - std::size_t m_face; - std::size_t m_vertex; - -public: - FaceVertexId(std::size_t face, std::size_t vertex) - : m_face(face), m_vertex(vertex) - { - } - - std::size_t getFace() const - { - return m_face; - } - std::size_t getVertex() const - { - return m_vertex; - } -}; - -typedef std::size_t faceIndex_t; - -struct EdgeRenderIndices -{ - RenderIndex first; - RenderIndex second; - - EdgeRenderIndices() - : first(0), second(0) - { - } - EdgeRenderIndices(const RenderIndex _first, const RenderIndex _second) - : first(_first), second(_second) - { - } -}; - -struct EdgeFaces -{ - faceIndex_t first; - faceIndex_t second; - - EdgeFaces() - : first(c_brush_maxFaces), second(c_brush_maxFaces) - { - } - EdgeFaces(const faceIndex_t _first, const faceIndex_t _second) - : first(_first), second(_second) - { - } -}; - -class RenderableWireframe : public OpenGLRenderable -{ -public: - void render(RenderStateFlags state) const - { -#if 1 - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PointVertex), &m_vertices->colour); - glVertexPointer(3, GL_FLOAT, sizeof(PointVertex), &m_vertices->vertex); - glDrawElements(GL_LINES, GLsizei(m_size<<1), RenderIndexTypeID, m_faceVertex.data()); -#else - glBegin(GL_LINES); - for(std::size_t i = 0; i < m_size; ++i) - { - glVertex3fv(&m_vertices[m_faceVertex[i].first].vertex.x); - glVertex3fv(&m_vertices[m_faceVertex[i].second].vertex.x); - } - glEnd(); -#endif - } - - Array m_faceVertex; - std::size_t m_size; - const PointVertex* m_vertices; -}; - -class Brush; -typedef std::vector brush_vector_t; - -class BrushFilter -{ -public: - virtual bool filter(const Brush& brush) const = 0; -}; - -bool brush_filtered(Brush& brush); -void add_brush_filter(BrushFilter& filter, int mask, bool invert = false); - - -/// \brief Returns true if 'self' takes priority when building brush b-rep. -inline bool plane3_inside(const Plane3& self, const Plane3& other) -{ - if(vector3_equal_epsilon(self.normal(), other.normal(), 0.001)) - { - return self.dist() < other.dist(); - } - return true; -} - -typedef SmartPointer FaceSmartPointer; -typedef std::vector Faces; - -/// \brief Returns the unique-id of the edge adjacent to \p faceVertex in the edge-pair for the set of \p faces. -inline FaceVertexId next_edge(const Faces& faces, FaceVertexId faceVertex) -{ - std::size_t adjacent_face = faces[faceVertex.getFace()]->getWinding()[faceVertex.getVertex()].adjacent; - std::size_t adjacent_vertex = Winding_FindAdjacent(faces[adjacent_face]->getWinding(), faceVertex.getFace()); - - ASSERT_MESSAGE(adjacent_vertex != c_brush_maxFaces, "connectivity data invalid"); - if(adjacent_vertex == c_brush_maxFaces) - { - return faceVertex; - } - - return FaceVertexId(adjacent_face, adjacent_vertex); -} - -/// \brief Returns the unique-id of the vertex adjacent to \p faceVertex in the vertex-ring for the set of \p faces. -inline FaceVertexId next_vertex(const Faces& faces, FaceVertexId faceVertex) -{ - FaceVertexId nextEdge = next_edge(faces, faceVertex); - return FaceVertexId(nextEdge.getFace(), Winding_next(faces[nextEdge.getFace()]->getWinding(), nextEdge.getVertex())); -} - -class SelectableEdge -{ - Vector3 getEdge() const - { - const Winding& winding = getFace().getWinding(); - return vector3_mid(winding[m_faceVertex.getVertex()].vertex, winding[Winding_next(winding, m_faceVertex.getVertex())].vertex); - } - -public: - Faces& m_faces; - FaceVertexId m_faceVertex; - - SelectableEdge(Faces& faces, FaceVertexId faceVertex) - : m_faces(faces), m_faceVertex(faceVertex) - { - } - SelectableEdge& operator=(const SelectableEdge& other) - { - m_faceVertex = other.m_faceVertex; - return *this; - } - - Face& getFace() const - { - return *m_faces[m_faceVertex.getFace()]; - } - - void testSelect(SelectionTest& test, SelectionIntersection& best) - { - test.TestPoint(getEdge(), best); - } -}; - -class SelectableVertex -{ - Vector3 getVertex() const - { - return getFace().getWinding()[m_faceVertex.getVertex()].vertex; - } - -public: - Faces& m_faces; - FaceVertexId m_faceVertex; - - SelectableVertex(Faces& faces, FaceVertexId faceVertex) - : m_faces(faces), m_faceVertex(faceVertex) - { - } - SelectableVertex& operator=(const SelectableVertex& other) - { - m_faceVertex = other.m_faceVertex; - return *this; - } - - Face& getFace() const - { - return *m_faces[m_faceVertex.getFace()]; - } - - void testSelect(SelectionTest& test, SelectionIntersection& best) - { - test.TestPoint(getVertex(), best); - } -}; - -class BrushObserver -{ -public: - virtual void reserve(std::size_t size) = 0; - virtual void clear() = 0; - virtual void push_back(Face& face) = 0; - virtual void pop_back() = 0; - virtual void erase(std::size_t index) = 0; - virtual void connectivityChanged() = 0; - - virtual void edge_clear() = 0; - virtual void edge_push_back(SelectableEdge& edge) = 0; - - virtual void vertex_clear() = 0; - virtual void vertex_push_back(SelectableVertex& vertex) = 0; - - virtual void DEBUG_verify() const = 0; -}; - -class BrushVisitor -{ -public: - virtual void visit(Face& face) const = 0; -}; - -class Brush : - public TransformNode, - public Bounded, - public Cullable, - public Snappable, - public Undoable, - public FaceObserver, - public Filterable, - public Nameable, - public BrushDoom3 -{ -private: - scene::Node* m_node; - typedef UniqueSet Observers; - Observers m_observers; - UndoObserver* m_undoable_observer; - MapFile* m_map; - - // state - Faces m_faces; - // ---- - - // cached data compiled from state - Array m_faceCentroidPoints; - RenderablePointArray m_render_faces; - - Array m_uniqueVertexPoints; - typedef std::vector SelectableVertices; - SelectableVertices m_select_vertices; - RenderablePointArray m_render_vertices; - - Array m_uniqueEdgePoints; - typedef std::vector SelectableEdges; - SelectableEdges m_select_edges; - RenderablePointArray m_render_edges; - - Array m_edge_indices; - Array m_edge_faces; - - AABB m_aabb_local; - // ---- - - Callback m_evaluateTransform; - Callback m_boundsChanged; - - mutable bool m_planeChanged; // b-rep evaluation required - mutable bool m_transformChanged; // transform evaluation required - // ---- - -public: - STRING_CONSTANT(Name, "Brush"); - - Callback m_lightsChanged; - - // static data - static Shader* m_state_point; - // ---- - - static EBrushType m_type; - static double m_maxWorldCoord; - - Brush(scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) : - m_node(&node), - m_undoable_observer(0), - m_map(0), - m_render_faces(m_faceCentroidPoints, GL_POINTS), - m_render_vertices(m_uniqueVertexPoints, GL_POINTS), - m_render_edges(m_uniqueEdgePoints, GL_POINTS), - m_evaluateTransform(evaluateTransform), - m_boundsChanged(boundsChanged), - m_planeChanged(false), - m_transformChanged(false) - { - planeChanged(); - } - Brush(const Brush& other, scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) : - m_node(&node), - m_undoable_observer(0), - m_map(0), - m_render_faces(m_faceCentroidPoints, GL_POINTS), - m_render_vertices(m_uniqueVertexPoints, GL_POINTS), - m_render_edges(m_uniqueEdgePoints, GL_POINTS), - m_evaluateTransform(evaluateTransform), - m_boundsChanged(boundsChanged), - m_planeChanged(false), - m_transformChanged(false) - { - copy(other); - } - Brush(const Brush& other) : - TransformNode(other), - Bounded(other), - Cullable(other), - Snappable(), - Undoable(other), - FaceObserver(other), - Filterable(other), - Nameable(other), - BrushDoom3(other), - m_node(0), - m_undoable_observer(0), - m_map(0), - m_render_faces(m_faceCentroidPoints, GL_POINTS), - m_render_vertices(m_uniqueVertexPoints, GL_POINTS), - m_render_edges(m_uniqueEdgePoints, GL_POINTS), - m_planeChanged(false), - m_transformChanged(false) - { - copy(other); - } - ~Brush() - { - ASSERT_MESSAGE(m_observers.empty(), "Brush::~Brush: observers still attached"); - } - - // assignment not supported - Brush& operator=(const Brush& other); - - void setDoom3GroupOrigin(const Vector3& origin) - { - //globalOutputStream() << "func_static origin before: " << m_funcStaticOrigin << " after: " << origin << "\n"; - for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->getPlane().m_funcStaticOrigin = origin; - (*i)->getPlane().updateTranslated(); - (*i)->planeChanged(); - } - planeChanged(); - } - - void attach(BrushObserver& observer) - { - for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - observer.push_back(*(*i)); - } - - for(SelectableEdges::iterator i = m_select_edges.begin(); i !=m_select_edges.end(); ++i) - { - observer.edge_push_back(*i); - } - - for(SelectableVertices::iterator i = m_select_vertices.begin(); i != m_select_vertices.end(); ++i) - { - observer.vertex_push_back(*i); - } - - m_observers.insert(&observer); - } - void detach(BrushObserver& observer) - { - m_observers.erase(&observer); - } - - void forEachFace(const BrushVisitor& visitor) const - { - for(Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - visitor.visit(*(*i)); - } - } - - void forEachFace_instanceAttach(MapFile* map) const - { - for(Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->instanceAttach(map); - } - } - void forEachFace_instanceDetach(MapFile* map) const - { - for(Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->instanceDetach(map); - } - } - - InstanceCounter m_instanceCounter; - void instanceAttach(const scene::Path& path) - { - if(++m_instanceCounter.m_count == 1) - { - m_map = path_find_mapfile(path.begin(), path.end()); - m_undoable_observer = GlobalUndoSystem().observer(this); - GlobalFilterSystem().registerFilterable(*this); - forEachFace_instanceAttach(m_map); - } - else - { - ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map, "node is instanced across more than one file"); - } - } - void instanceDetach(const scene::Path& path) - { - if(--m_instanceCounter.m_count == 0) - { - forEachFace_instanceDetach(m_map); - GlobalFilterSystem().unregisterFilterable(*this); - m_map = 0; - m_undoable_observer = 0; - GlobalUndoSystem().release(this); - } - } - - // nameable - const char* name() const - { - return "brush"; - } - void attach(const NameCallback& callback) - { - } - void detach(const NameCallback& callback) - { - } - - // filterable - void updateFiltered() - { - if(m_node != 0) - { - if(brush_filtered(*this)) - { - m_node->enable(scene::Node::eFiltered); - } - else - { - m_node->disable(scene::Node::eFiltered); - } - } - } - - // observer - void planeChanged() - { - m_planeChanged = true; - aabbChanged(); - m_lightsChanged(); - } - void shaderChanged() - { - updateFiltered(); - planeChanged(); - } - - void evaluateBRep() const - { - if(m_planeChanged) - { - m_planeChanged = false; - const_cast(this)->buildBRep(); - } - } - - void transformChanged() - { - m_transformChanged = true; - planeChanged(); - } - typedef MemberCaller TransformChangedCaller; - - void evaluateTransform() - { - if(m_transformChanged) - { - m_transformChanged = false; - revertTransform(); - m_evaluateTransform(); - } - } - const Matrix4& localToParent() const - { - return g_matrix4_identity; - } - void aabbChanged() - { - m_boundsChanged(); - } - const AABB& localAABB() const - { - evaluateBRep(); - return m_aabb_local; - } - - VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const - { - return test.TestAABB(m_aabb_local, localToWorld); - } - - void renderComponents(SelectionSystem::EComponentMode mode, Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - switch(mode) - { - case SelectionSystem::eVertex: - renderer.addRenderable(m_render_vertices, localToWorld); - break; - case SelectionSystem::eEdge: - renderer.addRenderable(m_render_edges, localToWorld); - break; - case SelectionSystem::eFace: - renderer.addRenderable(m_render_faces, localToWorld); - break; - default: - break; - } - } - - void transform(const Matrix4& matrix) - { - bool mirror = matrix4_handedness(matrix) == MATRIX4_LEFTHANDED; - - for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->transform(matrix, mirror); - } - } - void snapto(float snap) - { - for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->snapto(snap); - } - } - void revertTransform() - { - for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->revertTransform(); - } - } - void freezeTransform() - { - for(Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i) - { - (*i)->freezeTransform(); - } - } - - /// \brief Returns the absolute index of the \p faceVertex. - std::size_t absoluteIndex(FaceVertexId faceVertex) - { - std::size_t index = 0; - for(std::size_t i = 0; i < faceVertex.getFace(); ++i) - { - index += m_faces[i]->getWinding().numpoints; - } - return index + faceVertex.getVertex(); - } - - void appendFaces(const Faces& other) - { - clear(); - for(Faces::const_iterator i = other.begin(); i != other.end(); ++i) - { - push_back(*i); - } - } - - /// \brief The undo memento for a brush stores only the list of face references - the faces are not copied. - class BrushUndoMemento : public UndoMemento - { - public: - BrushUndoMemento(const Faces& faces) : m_faces(faces) - { - } - void release() - { - delete this; - } - - Faces m_faces; - }; - - void undoSave() - { - if(m_map != 0) - { - m_map->changed(); - } - if(m_undoable_observer != 0) - { - m_undoable_observer->save(this); - } - } - - UndoMemento* exportState() const - { - return new BrushUndoMemento(m_faces); - } - - void importState(const UndoMemento* state) - { - undoSave(); - appendFaces(static_cast(state)->m_faces); - planeChanged(); - - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->DEBUG_verify(); - } - } - - bool isDetail() - { - return !m_faces.empty() && m_faces.front()->isDetail(); - } - - /// \brief Appends a copy of \p face to the end of the face list. - Face* addFace(const Face& face) - { - if(m_faces.size() == c_brush_maxFaces) - { - return 0; - } - undoSave(); - push_back(FaceSmartPointer(new Face(face, this))); - m_faces.back()->setDetail(isDetail()); - planeChanged(); - return m_faces.back(); - } - - /// \brief Appends a new face constructed from the parameters to the end of the face list. - Face* addPlane(const Vector3& p0, const Vector3& p1, const Vector3& p2, const char* shader, const TextureProjection& projection) - { - if(m_faces.size() == c_brush_maxFaces) - { - return 0; - } - undoSave(); - push_back(FaceSmartPointer(new Face(p0, p1, p2, shader, projection, this))); - m_faces.back()->setDetail(isDetail()); - planeChanged(); - return m_faces.back(); - } - - static void constructStatic(EBrushType type) - { - m_type = type; - Face::m_type = type; - FacePlane::m_type = type; - - g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_QUAKE; - if(m_type == eBrushTypeQuake3BP || m_type == eBrushTypeDoom3 || m_type == eBrushTypeQuake4) - { - g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_BRUSHPRIMITIVES; - g_brush_texturelock_enabled = true; - } - else if(m_type == eBrushTypeHalfLife) - { - g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_HALFLIFE; - g_brush_texturelock_enabled = true; - } - - Face::m_quantise = (m_type == eBrushTypeQuake) ? quantiseInteger : quantiseFloating; - - m_state_point = GlobalShaderCache().capture("$POINT"); - } - static void destroyStatic() - { - GlobalShaderCache().release("$POINT"); - } - - std::size_t DEBUG_size() - { - return m_faces.size(); - } - - typedef Faces::const_iterator const_iterator; - - const_iterator begin() const - { - return m_faces.begin(); - } - const_iterator end() const - { - return m_faces.end(); - } - - Face* back() - { - return m_faces.back(); - } - const Face* back() const - { - return m_faces.back(); - } - void reserve(std::size_t count) - { - m_faces.reserve(count); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->reserve(count); - } - } - void push_back(Faces::value_type face) - { - m_faces.push_back(face); - if(m_instanceCounter.m_count != 0) - { - m_faces.back()->instanceAttach(m_map); - } - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->push_back(*face); - (*i)->DEBUG_verify(); - } - } - void pop_back() - { - if(m_instanceCounter.m_count != 0) - { - m_faces.back()->instanceDetach(m_map); - } - m_faces.pop_back(); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->pop_back(); - (*i)->DEBUG_verify(); - } - } - void erase(std::size_t index) - { - if(m_instanceCounter.m_count != 0) - { - m_faces[index]->instanceDetach(m_map); - } - m_faces.erase(m_faces.begin() + index); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->erase(index); - (*i)->DEBUG_verify(); - } - } - void connectivityChanged() - { - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->connectivityChanged(); - } - } - - - void clear() - { - undoSave(); - if(m_instanceCounter.m_count != 0) - { - forEachFace_instanceDetach(m_map); - } - m_faces.clear(); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->clear(); - (*i)->DEBUG_verify(); - } - } - std::size_t size() const - { - return m_faces.size(); - } - bool empty() const - { - return m_faces.empty(); - } - - /// \brief Returns true if any face of the brush contributes to the final B-Rep. - bool hasContributingFaces() const - { - for(const_iterator i = begin(); i != end(); ++i) - { - if((*i)->contributes()) - { - return true; - } - } - return false; - } - - /// \brief Removes faces that do not contribute to the brush. This is useful for cleaning up after CSG operations on the brush. - /// Note: removal of empty faces is not performed during direct brush manipulations, because it would make a manipulation irreversible if it created an empty face. - void removeEmptyFaces() - { - evaluateBRep(); - - { - std::size_t i = 0; - while(i < m_faces.size()) - { - if(!m_faces[i]->contributes()) - { - erase(i); - planeChanged(); - } - else - { - ++i; - } - } - } - } - - /// \brief Constructs \p winding from the intersection of \p plane with the other planes of the brush. - void windingForClipPlane(Winding& winding, const Plane3& plane) const - { - FixedWinding buffer[2]; - bool swap = false; - - // get a poly that covers an effectively infinite area - Winding_createInfinite(buffer[swap], plane, m_maxWorldCoord + 1); - - // chop the poly by all of the other faces - { - for (std::size_t i = 0; i < m_faces.size(); ++i) - { - const Face& clip = *m_faces[i]; - - if(plane3_equal(clip.plane3(), plane) - || !plane3_valid(clip.plane3()) || !plane_unique(i) - || plane3_opposing(plane, clip.plane3())) - { - continue; - } - - buffer[!swap].clear(); - -#if BRUSH_CONNECTIVITY_DEBUG - globalOutputStream() << "clip vs face: " << i << "\n"; -#endif - - { - // flip the plane, because we want to keep the back side - Plane3 clipPlane(vector3_negated(clip.plane3().normal()), -clip.plane3().dist()); - Winding_Clip(buffer[swap], plane, clipPlane, i, buffer[!swap]); - } - -#if BRUSH_CONNECTIVITY_DEBUG - for(FixedWinding::Points::iterator k = buffer[!swap].points.begin(), j = buffer[!swap].points.end() - 1; k != buffer[!swap].points.end(); j = k, ++k) - { - if(vector3_length_squared(vector3_subtracted((*k).vertex, (*j).vertex)) < 1) - { - globalOutputStream() << "v: " << std::distance(buffer[!swap].points.begin(), j) << " tiny edge adjacent to face " << (*j).adjacent << "\n"; - } - } -#endif - - //ASSERT_MESSAGE(buffer[!swap].numpoints != 1, "created single-point winding"); - - swap = !swap; - } - } - - Winding_forFixedWinding(winding, buffer[swap]); - -#if BRUSH_CONNECTIVITY_DEBUG - Winding_printConnectivity(winding); - - for(Winding::iterator i = winding.begin(), j = winding.end() - 1; i != winding.end(); j = i, ++i) - { - if(vector3_length_squared(vector3_subtracted((*i).vertex, (*j).vertex)) < 1) - { - globalOutputStream() << "v: " << std::distance(winding.begin(), j) << " tiny edge adjacent to face " << (*j).adjacent << "\n"; - } - } -#endif - } - - void update_wireframe(RenderableWireframe& wire, const bool* faces_visible) const - { - wire.m_faceVertex.resize(m_edge_indices.size()); - wire.m_vertices = m_uniqueVertexPoints.data(); - wire.m_size = 0; - for(std::size_t i = 0; i < m_edge_faces.size(); ++i) - { - if(faces_visible[m_edge_faces[i].first] - || faces_visible[m_edge_faces[i].second]) - { - wire.m_faceVertex[wire.m_size++] = m_edge_indices[i]; - } - } - } - - - void update_faces_wireframe(Array& wire, const bool* faces_visible) const - { - std::size_t count = 0; - for(std::size_t i = 0; i < m_faceCentroidPoints.size(); ++i) - { - if(faces_visible[i]) - { - ++count; - } - } - - wire.resize(count); - Array::iterator p = wire.begin(); - for(std::size_t i = 0; i < m_faceCentroidPoints.size(); ++i) - { - if(faces_visible[i]) - { - *p++ = m_faceCentroidPoints[i]; - } - } - } - - /// \brief Makes this brush a deep-copy of the \p other. - void copy(const Brush& other) - { - for(Faces::const_iterator i = other.m_faces.begin(); i != other.m_faces.end(); ++i) - { - addFace(*(*i)); - } - planeChanged(); - } - -private: - void edge_push_back(FaceVertexId faceVertex) - { - m_select_edges.push_back(SelectableEdge(m_faces, faceVertex)); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->edge_push_back(m_select_edges.back()); - } - } - void edge_clear() - { - m_select_edges.clear(); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->edge_clear(); - } - } - void vertex_push_back(FaceVertexId faceVertex) - { - m_select_vertices.push_back(SelectableVertex(m_faces, faceVertex)); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->vertex_push_back(m_select_vertices.back()); - } - } - void vertex_clear() - { - m_select_vertices.clear(); - for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i) - { - (*i)->vertex_clear(); - } - } - - /// \brief Returns true if the face identified by \p index is preceded by another plane that takes priority over it. - bool plane_unique(std::size_t index) const - { - // duplicate plane - for(std::size_t i = 0; i < m_faces.size(); ++i) - { - if(index != i && !plane3_inside(m_faces[index]->plane3(), m_faces[i]->plane3())) - { - return false; - } - } - return true; - } - - /// \brief Removes edges that are smaller than the tolerance used when generating brush windings. - void removeDegenerateEdges() - { - for (std::size_t i = 0; i < m_faces.size(); ++i) - { - Winding& winding = m_faces[i]->getWinding(); - for(Winding::iterator j = winding.begin(); j != winding.end();) - { - std::size_t index = std::distance(winding.begin(), j); - std::size_t next = Winding_next(winding, index); - if(Edge_isDegenerate(winding[index].vertex, winding[next].vertex)) - { -#if BRUSH_DEGENERATE_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << i << ": degenerate edge adjacent to " << winding[index].adjacent << "\n"; -#endif - Winding& other = m_faces[winding[index].adjacent]->getWinding(); - std::size_t adjacent = Winding_FindAdjacent(other, i); - if(adjacent != c_brush_maxFaces) - { - other.erase(other.begin() + adjacent); - } - winding.erase(j); - } - else - { - ++j; - } - } - } - } - - /// \brief Invalidates faces that have only two vertices in their winding, while preserving edge-connectivity information. - void removeDegenerateFaces() - { - // save adjacency info for degenerate faces - for (std::size_t i = 0; i < m_faces.size(); ++i) - { - Winding& degen = m_faces[i]->getWinding(); - - if(degen.numpoints == 2) - { -#if BRUSH_DEGENERATE_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << i << ": degenerate winding adjacent to " << degen[0].adjacent << ", " << degen[1].adjacent << "\n"; -#endif - // this is an "edge" face, where the plane touches the edge of the brush - { - Winding& winding = m_faces[degen[0].adjacent]->getWinding(); - std::size_t index = Winding_FindAdjacent(winding, i); - if(index != c_brush_maxFaces) - { -#if BRUSH_DEGENERATE_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << degen[0].adjacent << ": remapping adjacent " << winding[index].adjacent << " to " << degen[1].adjacent << "\n"; -#endif - winding[index].adjacent = degen[1].adjacent; - } - } - - { - Winding& winding = m_faces[degen[1].adjacent]->getWinding(); - std::size_t index = Winding_FindAdjacent(winding, i); - if(index != c_brush_maxFaces) - { -#if BRUSH_DEGENERATE_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << degen[1].adjacent << ": remapping adjacent " << winding[index].adjacent << " to " << degen[0].adjacent << "\n"; -#endif - winding[index].adjacent = degen[0].adjacent; - } - } - - degen.resize(0); - } - } - } - - /// \brief Removes edges that have the same adjacent-face as their immediate neighbour. - void removeDuplicateEdges() - { - // verify face connectivity graph - for(std::size_t i = 0; i < m_faces.size(); ++i) - { - //if(m_faces[i]->contributes()) - { - Winding& winding = m_faces[i]->getWinding(); - for(std::size_t j = 0; j != winding.numpoints;) - { - std::size_t next = Winding_next(winding, j); - if(winding[j].adjacent == winding[next].adjacent) - { -#if BRUSH_DEGENERATE_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << i << ": removed duplicate edge adjacent to face " << winding[j].adjacent << "\n"; -#endif - winding.erase(winding.begin() + next); - } - else - { - ++j; - } - } - } - } - } - - /// \brief Removes edges that do not have a matching pair in their adjacent-face. - void verifyConnectivityGraph() - { - // verify face connectivity graph - for(std::size_t i = 0; i < m_faces.size(); ++i) - { - //if(m_faces[i]->contributes()) - { - Winding& winding = m_faces[i]->getWinding(); - for(Winding::iterator j = winding.begin(); j != winding.end();) - { -#if BRUSH_CONNECTIVITY_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << i << ": adjacent to face " << (*j).adjacent << "\n"; -#endif - // remove unidirectional graph edges - if((*j).adjacent == c_brush_maxFaces - || Winding_FindAdjacent(m_faces[(*j).adjacent]->getWinding(), i) == c_brush_maxFaces) - { -#if BRUSH_CONNECTIVITY_DEBUG - globalOutputStream() << "Brush::buildWindings: face " << i << ": removing unidirectional connectivity graph edge adjacent to face " << (*j).adjacent << "\n"; -#endif - winding.erase(j); - } - else - { - ++j; - } - } - } - } - } - - /// \brief Returns true if the brush is a finite volume. A brush without a finite volume extends past the maximum world bounds and is not valid. - bool isBounded() - { - for(const_iterator i = begin(); i != end(); ++i) - { - if(!(*i)->is_bounded()) - { - return false; - } - } - return true; - } - - /// \brief Constructs the polygon windings for each face of the brush. Also updates the brush bounding-box and face texture-coordinates. - bool buildWindings() - { - - { - m_aabb_local = AABB(); - - for (std::size_t i = 0; i < m_faces.size(); ++i) - { - Face& f = *m_faces[i]; - - if(!plane3_valid(f.plane3()) || !plane_unique(i)) - { - f.getWinding().resize(0); - } - else - { -#if BRUSH_CONNECTIVITY_DEBUG - globalOutputStream() << "face: " << i << "\n"; -#endif - windingForClipPlane(f.getWinding(), f.plane3()); - - // update brush bounds - const Winding& winding = f.getWinding(); - for(Winding::const_iterator i = winding.begin(); i != winding.end(); ++i) - { - aabb_extend_by_point_safe(m_aabb_local, (*i).vertex); - } - - // update texture coordinates - f.EmitTextureCoordinates(); - } - } - } - - bool degenerate = !isBounded(); - - if(!degenerate) - { - // clean up connectivity information. - // these cleanups must be applied in a specific order. - removeDegenerateEdges(); - removeDegenerateFaces(); - removeDuplicateEdges(); - verifyConnectivityGraph(); - } - - return degenerate; - } - - /// \brief Constructs the face windings and updates anything that depends on them. - void buildBRep(); -}; - - - -class FaceInstance; - -class FaceInstanceSet -{ - typedef SelectionList FaceInstances; - FaceInstances m_faceInstances; -public: - void insert(FaceInstance& faceInstance) - { - m_faceInstances.append(faceInstance); - } - void erase(FaceInstance& faceInstance) - { - m_faceInstances.erase(faceInstance); - } - - template - void foreach(Functor functor) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - functor(*(*i)); - } - } - - bool empty() const - { - return m_faceInstances.empty(); - } - FaceInstance& last() const - { - return m_faceInstances.back(); - } -}; - -extern FaceInstanceSet g_SelectedFaceInstances; - -typedef std::list VertexSelection; - -inline VertexSelection::iterator VertexSelection_find(VertexSelection& self, std::size_t value) -{ - return std::find(self.begin(), self.end(), value); -} - -inline VertexSelection::const_iterator VertexSelection_find(const VertexSelection& self, std::size_t value) -{ - return std::find(self.begin(), self.end(), value); -} - -inline VertexSelection::iterator VertexSelection_insert(VertexSelection& self, std::size_t value) -{ - VertexSelection::iterator i = VertexSelection_find(self, value); - if(i == self.end()) - { - self.push_back(value); - return --self.end(); - } - return i; -} -inline void VertexSelection_erase(VertexSelection& self, std::size_t value) -{ - VertexSelection::iterator i = VertexSelection_find(self, value); - if(i != self.end()) - { - self.erase(i); - } -} - -inline bool triangle_reversed(std::size_t x, std::size_t y, std::size_t z) -{ - return !((x < y && y < z) || (z < x && x < y) || (y < z && z < x)); -} -template -inline Vector3 triangle_cross(const BasicVector3& x, const BasicVector3 y, const BasicVector3& z) -{ - return vector3_cross(y - x, z - x); -} -template -inline bool triangles_same_winding(const BasicVector3& x1, const BasicVector3 y1, const BasicVector3& z1, const BasicVector3& x2, const BasicVector3 y2, const BasicVector3& z2) -{ - return vector3_dot(triangle_cross(x1, y1, z1), triangle_cross(x2, y2, z2)) > 0; -} - - -typedef const Plane3* PlanePointer; -typedef PlanePointer* PlanesIterator; - -class VectorLightList : public LightList -{ - typedef std::vector Lights; - Lights m_lights; -public: - void addLight(const RendererLight& light) - { - m_lights.push_back(&light); - } - void clear() - { - m_lights.clear(); - } - void evaluateLights() const - { - } - void lightsChanged() const - { - } - void forEachLight(const RendererLightCallback& callback) const - { - for(Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i) - { - callback(*(*i)); - } - } -}; - -class FaceInstance -{ - Face* m_face; - ObservedSelectable m_selectable; - ObservedSelectable m_selectableVertices; - ObservedSelectable m_selectableEdges; - SelectionChangeCallback m_selectionChanged; - - VertexSelection m_vertexSelection; - VertexSelection m_edgeSelection; - -public: - mutable VectorLightList m_lights; - - FaceInstance(Face& face, const SelectionChangeCallback& observer) : - m_face(&face), - m_selectable(SelectedChangedCaller(*this)), - m_selectableVertices(observer), - m_selectableEdges(observer), - m_selectionChanged(observer) - { - } - FaceInstance(const FaceInstance& other) : - m_face(other.m_face), - m_selectable(SelectedChangedCaller(*this)), - m_selectableVertices(other.m_selectableVertices), - m_selectableEdges(other.m_selectableEdges), - m_selectionChanged(other.m_selectionChanged) - { - } - FaceInstance& operator=(const FaceInstance& other) - { - m_face = other.m_face; - return *this; - } - - Face& getFace() - { - return *m_face; - } - const Face& getFace() const - { - return *m_face; - } - - void selectedChanged(const Selectable& selectable) - { - if(selectable.isSelected()) - { - g_SelectedFaceInstances.insert(*this); - } - else - { - g_SelectedFaceInstances.erase(*this); - } - m_selectionChanged(selectable); - } - typedef MemberCaller1 SelectedChangedCaller; - - bool selectedVertices() const - { - return !m_vertexSelection.empty(); - } - bool selectedEdges() const - { - return !m_edgeSelection.empty(); - } - bool isSelected() const - { - return m_selectable.isSelected(); - } - - bool selectedComponents() const - { - return selectedVertices() || selectedEdges() || isSelected(); - } - bool selectedComponents(SelectionSystem::EComponentMode mode) const - { - switch(mode) - { - case SelectionSystem::eVertex: - return selectedVertices(); - case SelectionSystem::eEdge: - return selectedEdges(); - case SelectionSystem::eFace: - return isSelected(); - default: - return false; - } - } - void setSelected(SelectionSystem::EComponentMode mode, bool select) - { - switch(mode) - { - case SelectionSystem::eFace: - m_selectable.setSelected(select); - break; - case SelectionSystem::eVertex: - ASSERT_MESSAGE(!select, "select-all not supported"); - - m_vertexSelection.clear(); - m_selectableVertices.setSelected(false); - break; - case SelectionSystem::eEdge: - ASSERT_MESSAGE(!select, "select-all not supported"); - - m_edgeSelection.clear(); - m_selectableEdges.setSelected(false); - break; - default: - break; - } - } - - template - void SelectedVertices_foreach(Functor functor) const - { - for(VertexSelection::const_iterator i = m_vertexSelection.begin(); i != m_vertexSelection.end(); ++i) - { - std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *i); - if(index != c_brush_maxFaces) - { - functor(getFace().getWinding()[index].vertex); - } - } - } - template - void SelectedEdges_foreach(Functor functor) const - { - for(VertexSelection::const_iterator i = m_edgeSelection.begin(); i != m_edgeSelection.end(); ++i) - { - std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *i); - if(index != c_brush_maxFaces) - { - const Winding& winding = getFace().getWinding(); - std::size_t adjacent = Winding_next(winding, index); - functor(vector3_mid(winding[index].vertex, winding[adjacent].vertex)); - } - } - } - template - void SelectedFaces_foreach(Functor functor) const - { - if(isSelected()) - { - functor(centroid()); - } - } - - template - void SelectedComponents_foreach(Functor functor) const - { - SelectedVertices_foreach(functor); - SelectedEdges_foreach(functor); - SelectedFaces_foreach(functor); - } - - void iterate_selected(AABB& aabb) const - { - SelectedComponents_foreach(AABBExtendByPoint(aabb)); - } - - class RenderablePointVectorPushBack - { - RenderablePointVector& m_points; - public: - RenderablePointVectorPushBack(RenderablePointVector& points) : m_points(points) - { - } - void operator()(const Vector3& point) const - { - const Colour4b colour_selected(0, 0, 255, 255); - m_points.push_back(pointvertex_for_windingpoint(point, colour_selected)); - } - }; - - void iterate_selected(RenderablePointVector& points) const - { - SelectedComponents_foreach(RenderablePointVectorPushBack(points)); - } - - bool intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const - { - return m_face->intersectVolume(volume, localToWorld); - } - - void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - if(!m_face->isFiltered() && m_face->contributes() && intersectVolume(volume, localToWorld)) - { - renderer.PushState(); - if(selectedComponents()) - { - renderer.Highlight(Renderer::eFace); - } - m_face->render(renderer, localToWorld); - renderer.PopState(); - } - } - - void testSelect(SelectionTest& test, SelectionIntersection& best) - { - if(!m_face->isFiltered()) - { - m_face->testSelect(test, best); - } - } - void testSelect(Selector& selector, SelectionTest& test) - { - SelectionIntersection best; - testSelect(test, best); - if(best.valid()) - { - Selector_add(selector, m_selectable, best); - } - } - void testSelect_centroid(Selector& selector, SelectionTest& test) - { - if(m_face->contributes() && !m_face->isFiltered()) - { - SelectionIntersection best; - m_face->testSelect_centroid(test, best); - if(best.valid()) - { - Selector_add(selector, m_selectable, best); - } - } - } - - void selectPlane(Selector& selector, const Line& line, PlanesIterator first, PlanesIterator last, const PlaneCallback& selectedPlaneCallback) - { - for(Winding::const_iterator i = getFace().getWinding().begin(); i != getFace().getWinding().end(); ++i) - { - Vector3 v(vector3_subtracted(line_closest_point(line, (*i).vertex), (*i).vertex)); - double dot = vector3_dot(getFace().plane3().normal(), v); - if(dot <= 0) - { - return; - } - } - - Selector_add(selector, m_selectable); - - selectedPlaneCallback(getFace().plane3()); - } - void selectReversedPlane(Selector& selector, const SelectedPlanes& selectedPlanes) - { - if(selectedPlanes.contains(plane3_flipped(getFace().plane3()))) - { - Selector_add(selector, m_selectable); - } - } - - void transformComponents(const Matrix4& matrix) - { - if(isSelected()) - { - m_face->transform(matrix, false); - } - if(selectedVertices()) - { - if(m_vertexSelection.size() == 1) - { - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]); - m_face->assign_planepts(m_face->m_move_planeptsTransformed); - } - else if(m_vertexSelection.size() == 2) - { - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]); - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[2]); - m_face->assign_planepts(m_face->m_move_planeptsTransformed); - } - else if(m_vertexSelection.size() >= 3) - { - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[0]); - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]); - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[2]); - m_face->assign_planepts(m_face->m_move_planeptsTransformed); - } - } - if(selectedEdges()) - { - if(m_edgeSelection.size() == 1) - { - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[0]); - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]); - m_face->assign_planepts(m_face->m_move_planeptsTransformed); - } - else if(m_edgeSelection.size() >= 2) - { - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[0]); - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[1]); - matrix4_transform_point(matrix, m_face->m_move_planeptsTransformed[2]); - m_face->assign_planepts(m_face->m_move_planeptsTransformed); - } - } - } - - void snapto(float snap) - { - m_face->snapto(snap); - } - - void snapComponents(float snap) - { - if(isSelected()) - { - snapto(snap); - } - if(selectedVertices()) - { - vector3_snap(m_face->m_move_planepts[0], snap); - vector3_snap(m_face->m_move_planepts[1], snap); - vector3_snap(m_face->m_move_planepts[2], snap); - m_face->assign_planepts(m_face->m_move_planepts); - planepts_assign(m_face->m_move_planeptsTransformed, m_face->m_move_planepts); - m_face->freezeTransform(); - } - if(selectedEdges()) - { - vector3_snap(m_face->m_move_planepts[0], snap); - vector3_snap(m_face->m_move_planepts[1], snap); - vector3_snap(m_face->m_move_planepts[2], snap); - m_face->assign_planepts(m_face->m_move_planepts); - planepts_assign(m_face->m_move_planeptsTransformed, m_face->m_move_planepts); - m_face->freezeTransform(); - } - } - void update_move_planepts_vertex(std::size_t index) - { - m_face->update_move_planepts_vertex(index, m_face->m_move_planepts); - } - void update_move_planepts_vertex2(std::size_t index, std::size_t other) - { - const std::size_t numpoints = m_face->getWinding().numpoints; - ASSERT_MESSAGE(index < numpoints, "select_vertex: invalid index"); - - const std::size_t opposite = Winding_Opposite(m_face->getWinding(), index, other); - - if(triangle_reversed(index, other, opposite)) - { - std::swap(index, other); - } - - ASSERT_MESSAGE( - triangles_same_winding( - m_face->getWinding()[opposite].vertex, - m_face->getWinding()[index].vertex, - m_face->getWinding()[other].vertex, - m_face->getWinding()[0].vertex, - m_face->getWinding()[1].vertex, - m_face->getWinding()[2].vertex - ), - "update_move_planepts_vertex2: error" - ); - - m_face->m_move_planepts[0] = m_face->getWinding()[opposite].vertex; - m_face->m_move_planepts[1] = m_face->getWinding()[index].vertex; - m_face->m_move_planepts[2] = m_face->getWinding()[other].vertex; - planepts_quantise(m_face->m_move_planepts, GRID_MIN); // winding points are very inaccurate - } - void update_selection_vertex() - { - if(m_vertexSelection.size() == 0) - { - m_selectableVertices.setSelected(false); - } - else - { - m_selectableVertices.setSelected(true); - - if(m_vertexSelection.size() == 1) - { - std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *m_vertexSelection.begin()); - - if(index != c_brush_maxFaces) - { - update_move_planepts_vertex(index); - } - } - else if(m_vertexSelection.size() == 2) - { - std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *m_vertexSelection.begin()); - std::size_t other = Winding_FindAdjacent(getFace().getWinding(), *(++m_vertexSelection.begin())); - - if(index != c_brush_maxFaces - && other != c_brush_maxFaces) - { - update_move_planepts_vertex2(index, other); - } - } - } - } - void select_vertex(std::size_t index, bool select) - { - if(select) - { - VertexSelection_insert(m_vertexSelection, getFace().getWinding()[index].adjacent); - } - else - { - VertexSelection_erase(m_vertexSelection, getFace().getWinding()[index].adjacent); - } - - SceneChangeNotify(); - update_selection_vertex(); - } - - bool selected_vertex(std::size_t index) const - { - return VertexSelection_find(m_vertexSelection, getFace().getWinding()[index].adjacent) != m_vertexSelection.end(); - } - - void update_move_planepts_edge(std::size_t index) - { - std::size_t numpoints = m_face->getWinding().numpoints; - ASSERT_MESSAGE(index < numpoints, "select_edge: invalid index"); - - std::size_t adjacent = Winding_next(m_face->getWinding(), index); - std::size_t opposite = Winding_Opposite(m_face->getWinding(), index); - m_face->m_move_planepts[0] = m_face->getWinding()[index].vertex; - m_face->m_move_planepts[1] = m_face->getWinding()[adjacent].vertex; - m_face->m_move_planepts[2] = m_face->getWinding()[opposite].vertex; - planepts_quantise(m_face->m_move_planepts, GRID_MIN); // winding points are very inaccurate - } - void update_selection_edge() - { - if(m_edgeSelection.size() == 0) - { - m_selectableEdges.setSelected(false); - } - else - { - m_selectableEdges.setSelected(true); - - if(m_edgeSelection.size() == 1) - { - std::size_t index = Winding_FindAdjacent(getFace().getWinding(), *m_edgeSelection.begin()); - - if(index != c_brush_maxFaces) - { - update_move_planepts_edge(index); - } - } - } - } - void select_edge(std::size_t index, bool select) - { - if(select) - { - VertexSelection_insert(m_edgeSelection, getFace().getWinding()[index].adjacent); - } - else - { - VertexSelection_erase(m_edgeSelection, getFace().getWinding()[index].adjacent); - } - - SceneChangeNotify(); - update_selection_edge(); - } - - bool selected_edge(std::size_t index) const - { - return VertexSelection_find(m_edgeSelection, getFace().getWinding()[index].adjacent) != m_edgeSelection.end(); - } - - const Vector3& centroid() const - { - return m_face->centroid(); - } - - void connectivityChanged() - { - // This occurs when a face is added or removed. - // The current vertex and edge selections no longer valid and must be cleared. - m_vertexSelection.clear(); - m_selectableVertices.setSelected(false); - m_edgeSelection.clear(); - m_selectableEdges.setSelected(false); - } -}; - -class BrushClipPlane : public OpenGLRenderable -{ - Plane3 m_plane; - Winding m_winding; - static Shader* m_state; -public: - static void constructStatic() - { - m_state = GlobalShaderCache().capture("$CLIPPER_OVERLAY"); - } - static void destroyStatic() - { - GlobalShaderCache().release("$CLIPPER_OVERLAY"); - } - - void setPlane(const Brush& brush, const Plane3& plane) - { - m_plane = plane; - if(plane3_valid(m_plane)) - { - brush.windingForClipPlane(m_winding, m_plane); - } - else - { - m_winding.resize(0); - } - } - - void render(RenderStateFlags state) const - { - if((state & RENDER_FILL) != 0) - { - Winding_Draw(m_winding, m_plane.normal(), state); - } - else - { - Winding_DrawWireframe(m_winding); - } - } - - void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - renderer.SetState(m_state, Renderer::eWireframeOnly); - renderer.SetState(m_state, Renderer::eFullMaterials); - renderer.addRenderable(*this, localToWorld); - } -}; - -inline void Face_addLight(const FaceInstance& face, const Matrix4& localToWorld, const RendererLight& light) -{ - const Plane3& facePlane = face.getFace().plane3(); - const Vector3& origin = light.aabb().origin; - Plane3 tmp(plane3_transformed(Plane3(facePlane.normal(), -facePlane.dist()), localToWorld)); - if(!plane3_test_point(tmp, origin) - || !plane3_test_point(tmp, vector3_added(origin, light.offset()))) - { - face.m_lights.addLight(light); - } -} - - - -typedef std::vector FaceInstances; - -class EdgeInstance : public Selectable -{ - FaceInstances& m_faceInstances; - SelectableEdge* m_edge; - - void select_edge(bool select) - { - FaceVertexId faceVertex = m_edge->m_faceVertex; - m_faceInstances[faceVertex.getFace()].select_edge(faceVertex.getVertex(), select); - faceVertex = next_edge(m_edge->m_faces, faceVertex); - m_faceInstances[faceVertex.getFace()].select_edge(faceVertex.getVertex(), select); - } - bool selected_edge() const - { - FaceVertexId faceVertex = m_edge->m_faceVertex; - if(!m_faceInstances[faceVertex.getFace()].selected_edge(faceVertex.getVertex())) - { - return false; - } - faceVertex = next_edge(m_edge->m_faces, faceVertex); - if(!m_faceInstances[faceVertex.getFace()].selected_edge(faceVertex.getVertex())) - { - return false; - } - - return true; - } - -public: - EdgeInstance(FaceInstances& faceInstances, SelectableEdge& edge) - : m_faceInstances(faceInstances), m_edge(&edge) - { - } - EdgeInstance& operator=(const EdgeInstance& other) - { - m_edge = other.m_edge; - return *this; - } - - void setSelected(bool select) - { - select_edge(select); - } - bool isSelected() const - { - return selected_edge(); - } - - - void testSelect(Selector& selector, SelectionTest& test) - { - SelectionIntersection best; - m_edge->testSelect(test, best); - if(best.valid()) - { - Selector_add(selector, *this, best); - } - } -}; - -class VertexInstance : public Selectable -{ - FaceInstances& m_faceInstances; - SelectableVertex* m_vertex; - - void select_vertex(bool select) - { - FaceVertexId faceVertex = m_vertex->m_faceVertex; - do - { - m_faceInstances[faceVertex.getFace()].select_vertex(faceVertex.getVertex(), select); - faceVertex = next_vertex(m_vertex->m_faces, faceVertex); - } - while(faceVertex.getFace() != m_vertex->m_faceVertex.getFace()); - } - bool selected_vertex() const - { - FaceVertexId faceVertex = m_vertex->m_faceVertex; - do - { - if(!m_faceInstances[faceVertex.getFace()].selected_vertex(faceVertex.getVertex())) - { - return false; - } - faceVertex = next_vertex(m_vertex->m_faces, faceVertex); - } - while(faceVertex.getFace() != m_vertex->m_faceVertex.getFace()); - return true; - } - -public: - VertexInstance(FaceInstances& faceInstances, SelectableVertex& vertex) - : m_faceInstances(faceInstances), m_vertex(&vertex) - { - } - VertexInstance& operator=(const VertexInstance& other) - { - m_vertex = other.m_vertex; - return *this; - } - - void setSelected(bool select) - { - select_vertex(select); - } - bool isSelected() const - { - return selected_vertex(); - } - - void testSelect(Selector& selector, SelectionTest& test) - { - SelectionIntersection best; - m_vertex->testSelect(test, best); - if(best.valid()) - { - Selector_add(selector, *this, best); - } - } -}; - -class BrushInstanceVisitor -{ -public: - virtual void visit(FaceInstance& face) const = 0; -}; - -class BrushInstance : -public BrushObserver, -public scene::Instance, -public Selectable, -public Renderable, -public SelectionTestable, -public ComponentSelectionTestable, -public ComponentEditable, -public ComponentSnappable, -public PlaneSelectable, -public LightCullable -{ - class TypeCasts - { - InstanceTypeCastTable m_casts; - public: - TypeCasts() - { - InstanceStaticCast::install(m_casts); - InstanceContainedCast::install(m_casts); - InstanceContainedCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceStaticCast::install(m_casts); - InstanceIdentityCast::install(m_casts); - InstanceContainedCast::install(m_casts); - } - InstanceTypeCastTable& get() - { - return m_casts; - } - }; - - - Brush& m_brush; - - FaceInstances m_faceInstances; - - typedef std::vector EdgeInstances; - EdgeInstances m_edgeInstances; - typedef std::vector VertexInstances; - VertexInstances m_vertexInstances; - - ObservedSelectable m_selectable; - - mutable RenderableWireframe m_render_wireframe; - mutable RenderablePointVector m_render_selected; - mutable AABB m_aabb_component; - mutable Array m_faceCentroidPointsCulled; - RenderablePointArray m_render_faces_wireframe; - mutable bool m_viewChanged; // requires re-evaluation of view-dependent cached data - - BrushClipPlane m_clipPlane; - - static Shader* m_state_selpoint; - - const LightList* m_lightList; - - TransformModifier m_transform; - - BrushInstance(const BrushInstance& other); // NOT COPYABLE - BrushInstance& operator=(const BrushInstance& other); // NOT ASSIGNABLE -public: - static Counter* m_counter; - - typedef LazyStatic StaticTypeCasts; - - void lightsChanged() - { - m_lightList->lightsChanged(); - } - typedef MemberCaller LightsChangedCaller; - - STRING_CONSTANT(Name, "BrushInstance"); - - BrushInstance(const scene::Path& path, scene::Instance* parent, Brush& brush) : - Instance(path, parent, this, StaticTypeCasts::instance().get()), - m_brush(brush), - m_selectable(SelectedChangedCaller(*this)), - m_render_selected(GL_POINTS), - m_render_faces_wireframe(m_faceCentroidPointsCulled, GL_POINTS), - m_viewChanged(false), - m_transform(Brush::TransformChangedCaller(m_brush), ApplyTransformCaller(*this)) - { - m_brush.instanceAttach(Instance::path()); - m_brush.attach(*this); - m_counter->increment(); - - m_lightList = &GlobalShaderCache().attach(*this); - m_brush.m_lightsChanged = LightsChangedCaller(*this); ///\todo Make this work with instancing. - - Instance::setTransformChangedCallback(LightsChangedCaller(*this)); - } - ~BrushInstance() - { - Instance::setTransformChangedCallback(Callback()); - - m_brush.m_lightsChanged = Callback(); - GlobalShaderCache().detach(*this); - - m_counter->decrement(); - m_brush.detach(*this); - m_brush.instanceDetach(Instance::path()); - } - - Brush& getBrush() - { - return m_brush; - } - const Brush& getBrush() const - { - return m_brush; - } - - Bounded& get(NullType) - { - return m_brush; - } - Cullable& get(NullType) - { - return m_brush; - } - Transformable& get(NullType) - { - return m_transform; - } - - void selectedChanged(const Selectable& selectable) - { - GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable); - GlobalSelectionSystem().onSelectedChanged(*this, selectable); - - Instance::selectedChanged(); - } - typedef MemberCaller1 SelectedChangedCaller; - - void selectedChangedComponent(const Selectable& selectable) - { - GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable); - GlobalSelectionSystem().onComponentSelection(*this, selectable); - } - typedef MemberCaller1 SelectedChangedComponentCaller; - - const BrushInstanceVisitor& forEachFaceInstance(const BrushInstanceVisitor& visitor) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - visitor.visit(*i); - } - return visitor; - } - - static void constructStatic() - { - m_state_selpoint = GlobalShaderCache().capture("$SELPOINT"); - } - static void destroyStatic() - { - GlobalShaderCache().release("$SELPOINT"); - } - - void clear() - { - m_faceInstances.clear(); - } - void reserve(std::size_t size) - { - m_faceInstances.reserve(size); - } - - void push_back(Face& face) - { - m_faceInstances.push_back(FaceInstance(face, SelectedChangedComponentCaller(*this))); - } - void pop_back() - { - ASSERT_MESSAGE(!m_faceInstances.empty(), "erasing invalid element"); - m_faceInstances.pop_back(); - } - void erase(std::size_t index) - { - ASSERT_MESSAGE(index < m_faceInstances.size(), "erasing invalid element"); - m_faceInstances.erase(m_faceInstances.begin() + index); - } - void connectivityChanged() - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).connectivityChanged(); - } - } - - void edge_clear() - { - m_edgeInstances.clear(); - } - void edge_push_back(SelectableEdge& edge) - { - m_edgeInstances.push_back(EdgeInstance(m_faceInstances, edge)); - } - - void vertex_clear() - { - m_vertexInstances.clear(); - } - void vertex_push_back(SelectableVertex& vertex) - { - m_vertexInstances.push_back(VertexInstance(m_faceInstances, vertex)); - } - - void DEBUG_verify() const - { - ASSERT_MESSAGE(m_faceInstances.size() == m_brush.DEBUG_size(), "FATAL: mismatch"); - } - - bool isSelected() const - { - return m_selectable.isSelected(); - } - void setSelected(bool select) - { - m_selectable.setSelected(select); - } - - void update_selected() const - { - m_render_selected.clear(); - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - if((*i).getFace().contributes()) - { - (*i).iterate_selected(m_render_selected); - } - } - } - - void evaluateViewDependent(const VolumeTest& volume, const Matrix4& localToWorld) const - { - if(m_viewChanged) - { - m_viewChanged = false; - - bool faces_visible[c_brush_maxFaces]; - { - bool* j = faces_visible; - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i, ++j) - { - *j = (*i).intersectVolume(volume, localToWorld); - } - } - - m_brush.update_wireframe(m_render_wireframe, faces_visible); - m_brush.update_faces_wireframe(m_faceCentroidPointsCulled, faces_visible); - } - } - - void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - m_brush.evaluateBRep(); - - update_selected(); - if(!m_render_selected.empty()) - { - renderer.Highlight(Renderer::ePrimitive, false); - renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly); - renderer.SetState(m_state_selpoint, Renderer::eFullMaterials); - renderer.addRenderable(m_render_selected, localToWorld); - } - } - - void renderComponents(Renderer& renderer, const VolumeTest& volume) const - { - m_brush.evaluateBRep(); - - const Matrix4& localToWorld = Instance::localToWorld(); - - renderer.SetState(m_brush.m_state_point, Renderer::eWireframeOnly); - renderer.SetState(m_brush.m_state_point, Renderer::eFullMaterials); - - if(volume.fill() && GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace) - { - evaluateViewDependent(volume, localToWorld); - renderer.addRenderable(m_render_faces_wireframe, localToWorld); - } - else - { - m_brush.renderComponents(GlobalSelectionSystem().ComponentMode(), renderer, volume, localToWorld); - } - } - - void renderClipPlane(Renderer& renderer, const VolumeTest& volume) const - { - if(GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip && isSelected()) - { - m_clipPlane.render(renderer, volume, localToWorld()); - } - } - - void renderCommon(Renderer& renderer, const VolumeTest& volume) const - { - bool componentMode = GlobalSelectionSystem().Mode() == SelectionSystem::eComponent; - - if(componentMode && isSelected()) - { - renderComponents(renderer, volume); - } - - if(parentSelected()) - { - if(!componentMode) - { - renderer.Highlight(Renderer::eFace); - } - renderer.Highlight(Renderer::ePrimitive); - } - } - - void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - //renderCommon(renderer, volume); - - m_lightList->evaluateLights(); - - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - renderer.setLights((*i).m_lights); - (*i).render(renderer, volume, localToWorld); - } - - renderComponentsSelected(renderer, volume, localToWorld); - } - - void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const - { - //renderCommon(renderer, volume); - - evaluateViewDependent(volume, localToWorld); - - if(m_render_wireframe.m_size != 0) - { - renderer.addRenderable(m_render_wireframe, localToWorld); - } - - renderComponentsSelected(renderer, volume, localToWorld); - } - - void renderSolid(Renderer& renderer, const VolumeTest& volume) const - { - m_brush.evaluateBRep(); - - renderClipPlane(renderer, volume); - - renderSolid(renderer, volume, localToWorld()); - } - - void renderWireframe(Renderer& renderer, const VolumeTest& volume) const - { - m_brush.evaluateBRep(); - - renderClipPlane(renderer, volume); - - renderWireframe(renderer, volume, localToWorld()); - } - - void viewChanged() const - { - m_viewChanged = true; - } - - void testSelect(Selector& selector, SelectionTest& test) - { - test.BeginMesh(localToWorld()); - - SelectionIntersection best; - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).testSelect(test, best); - } - if(best.valid()) - { - selector.addIntersection(best); - } - } - - bool isSelectedComponents() const - { - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - if((*i).selectedComponents()) - { - return true; - } - } - return false; - } - void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).setSelected(mode, select); - } - } - void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode) - { - test.BeginMesh(localToWorld()); - - switch(mode) - { - case SelectionSystem::eVertex: - { - for(VertexInstances::iterator i = m_vertexInstances.begin(); i != m_vertexInstances.end(); ++i) - { - (*i).testSelect(selector, test); - } - } - break; - case SelectionSystem::eEdge: - { - for(EdgeInstances::iterator i = m_edgeInstances.begin(); i != m_edgeInstances.end(); ++i) - { - (*i).testSelect(selector, test); - } - } - break; - case SelectionSystem::eFace: - { - if(test.getVolume().fill()) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).testSelect(selector, test); - } - } - else - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).testSelect_centroid(selector, test); - } - } - } - break; - default: - break; - } - } - - void selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback) - { - test.BeginMesh(localToWorld()); - - PlanePointer brushPlanes[c_brush_maxFaces]; - PlanesIterator j = brushPlanes; - - for(Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i) - { - *j++ = &(*i)->plane3(); - } - - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).selectPlane(selector, Line(test.getNear(), test.getFar()), brushPlanes, j, selectedPlaneCallback); - } - } - void selectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).selectReversedPlane(selector, selectedPlanes); - } - } - - - void transformComponents(const Matrix4& matrix) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).transformComponents(matrix); - } - } - const AABB& getSelectedComponentsBounds() const - { - m_aabb_component = AABB(); - - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).iterate_selected(m_aabb_component); - } - - return m_aabb_component; - } - - void snapComponents(float snap) - { - for(FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).snapComponents(snap); - } - } - void evaluateTransform() - { - Matrix4 matrix(m_transform.calculateTransform()); - //globalOutputStream() << "matrix: " << matrix << "\n"; - - if(m_transform.getType() == TRANSFORM_PRIMITIVE) - { - m_brush.transform(matrix); - } - else - { - transformComponents(matrix); - } - } - void applyTransform() - { - m_brush.revertTransform(); - evaluateTransform(); - m_brush.freezeTransform(); - } - typedef MemberCaller ApplyTransformCaller; - - void setClipPlane(const Plane3& plane) - { - m_clipPlane.setPlane(m_brush, plane); - } - - bool testLight(const RendererLight& light) const - { - return light.testAABB(worldAABB()); - } - void insertLight(const RendererLight& light) - { - const Matrix4& localToWorld = Instance::localToWorld(); - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - Face_addLight(*i, localToWorld, light); - } - } - void clearLights() - { - for(FaceInstances::const_iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i) - { - (*i).m_lights.clear(); - } - } -}; - -inline BrushInstance* Instance_getBrush(scene::Instance& instance) -{ - return InstanceTypeCast::cast(instance); -} - - -template -class BrushSelectedVisitor : public SelectionSystem::Visitor -{ - const Functor& m_functor; -public: - BrushSelectedVisitor(const Functor& functor) : m_functor(functor) - { - } - void visit(scene::Instance& instance) const - { - BrushInstance* brush = Instance_getBrush(instance); - if(brush != 0) - { - m_functor(*brush); - } - } -}; - -template -inline const Functor& Scene_forEachSelectedBrush(const Functor& functor) -{ - GlobalSelectionSystem().foreachSelected(BrushSelectedVisitor(functor)); - return functor; -} - -template -class BrushVisibleSelectedVisitor : public SelectionSystem::Visitor -{ - const Functor& m_functor; -public: - BrushVisibleSelectedVisitor(const Functor& functor) : m_functor(functor) - { - } - void visit(scene::Instance& instance) const - { - BrushInstance* brush = Instance_getBrush(instance); - if(brush != 0 - && instance.path().top().get().visible()) - { - m_functor(*brush); - } - } -}; - -template -inline const Functor& Scene_forEachVisibleSelectedBrush(const Functor& functor) -{ - GlobalSelectionSystem().foreachSelected(BrushVisibleSelectedVisitor(functor)); - return functor; -} - -class BrushForEachFace -{ - const BrushInstanceVisitor& m_visitor; -public: - BrushForEachFace(const BrushInstanceVisitor& visitor) : m_visitor(visitor) - { - } - void operator()(BrushInstance& brush) const - { - brush.forEachFaceInstance(m_visitor); - } -}; - -template -class FaceInstanceVisitFace : public BrushInstanceVisitor -{ - const Functor& functor; -public: - FaceInstanceVisitFace(const Functor& functor) - : functor(functor) - { - } - void visit(FaceInstance& face) const - { - functor(face.getFace()); - } -}; - -template -inline const Functor& Brush_forEachFace(BrushInstance& brush, const Functor& functor) -{ - brush.forEachFaceInstance(FaceInstanceVisitFace(functor)); - return functor; -} - -template -class FaceVisitAll : public BrushVisitor -{ - const Functor& functor; -public: - FaceVisitAll(const Functor& functor) - : functor(functor) - { - } - void visit(Face& face) const - { - functor(face); - } -}; - -template -inline const Functor& Brush_forEachFace(const Brush& brush, const Functor& functor) -{ - brush.forEachFace(FaceVisitAll(functor)); - return functor; -} - -template -inline const Functor& Brush_forEachFace(Brush& brush, const Functor& functor) -{ - brush.forEachFace(FaceVisitAll(functor)); - return functor; -} - -template -class FaceInstanceVisitAll : public BrushInstanceVisitor -{ - const Functor& functor; -public: - FaceInstanceVisitAll(const Functor& functor) - : functor(functor) - { - } - void visit(FaceInstance& face) const - { - functor(face); - } -}; - -template -inline const Functor& Brush_ForEachFaceInstance(BrushInstance& brush, const Functor& functor) -{ - brush.forEachFaceInstance(FaceInstanceVisitAll(functor)); - return functor; -} - -template -inline const Functor& Scene_forEachBrush(scene::Graph& graph, const Functor& functor) -{ - graph.traverse(InstanceWalker< InstanceApply >(functor)); - return functor; -} - -template -class InstanceIfVisible : public Functor -{ -public: - InstanceIfVisible(const Functor& functor) : Functor(functor) - { - } - void operator()(scene::Instance& instance) - { - if(instance.path().top().get().visible()) - { - Functor::operator()(instance); - } - } -}; - -template -class BrushVisibleWalker : public scene::Graph::Walker -{ - const Functor& m_functor; -public: - BrushVisibleWalker(const Functor& functor) : m_functor(functor) - { - } - bool pre(const scene::Path& path, scene::Instance& instance) const - { - if(path.top().get().visible()) - { - BrushInstance* brush = Instance_getBrush(instance); - if(brush != 0) - { - m_functor(*brush); - } - } - return true; - } -}; - -template -inline const Functor& Scene_forEachVisibleBrush(scene::Graph& graph, const Functor& functor) -{ - graph.traverse(BrushVisibleWalker(functor)); - return functor; -} - -template -inline const Functor& Scene_ForEachBrush_ForEachFace(scene::Graph& graph, const Functor& functor) -{ - Scene_forEachBrush(graph, BrushForEachFace(FaceInstanceVisitFace(functor))); - return functor; -} - -// d1223m -template -inline const Functor& Scene_ForEachBrush_ForEachFaceInstance(scene::Graph& graph, const Functor& functor) -{ - Scene_forEachBrush(graph, BrushForEachFace(FaceInstanceVisitAll(functor))); - return functor; -} - -template -inline const Functor& Scene_ForEachSelectedBrush_ForEachFace(scene::Graph& graph, const Functor& functor) -{ - Scene_forEachSelectedBrush(BrushForEachFace(FaceInstanceVisitFace(functor))); - return functor; -} - -template -inline const Functor& Scene_ForEachSelectedBrush_ForEachFaceInstance(scene::Graph& graph, const Functor& functor) -{ - Scene_forEachSelectedBrush(BrushForEachFace(FaceInstanceVisitAll(functor))); - return functor; -} - -template -class FaceVisitorWrapper -{ - const Functor& functor; -public: - FaceVisitorWrapper(const Functor& functor) : functor(functor) - { - } - - void operator()(FaceInstance& faceInstance) const - { - functor(faceInstance.getFace()); - } -}; - -template -inline const Functor& Scene_ForEachSelectedBrushFace(scene::Graph& graph, const Functor& functor) -{ - g_SelectedFaceInstances.foreach(FaceVisitorWrapper(functor)); - return functor; -} - - -#endif + Copyright (C) 1999-2007 id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. + + This file is part of GtkRadiant. + + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +// brush.h + +// some usefull flags to control the behaviour of Brush_Build +extern bool g_bBuildWindingsNoTexBuild; + +void Brush_AddToList( brush_t *b, brush_t *lst ); +void Brush_Build( brush_t *b, bool bSnap = true, bool bMarkMap = true, bool bConvert = false, bool bFilterTest = true ); +void Brush_SetBuildWindingsNoTexBuild( bool bBuild ); +void Brush_BuildWindings( brush_t *b, bool bSnap = true ); +brush_t* Brush_Clone( brush_t *b ); +brush_t* Brush_FullClone( brush_t *b ); +brush_t* Brush_Create( vec3_t mins, vec3_t maxs, texdef_t *texdef ); +void Brush_Resize( brush_t *b, vec3_t vMin, vec3_t vMax ); +void Brush_FaceDraw( face_t *face, int nGLState ); +void Brush_Draw( brush_t *b ); +void Brush_DrawXY( brush_t *b, int nViewType ); +// set bRemoveNode to false to avoid trying to delete the item in group view tree control +void Brush_Free( brush_t *b, bool bRemoveNode = true ); +int Brush_MemorySize( brush_t *b ); +void Brush_MakeSided( int sides ); +void Brush_MakeSidedCone( int sides ); +void Brush_Move( brush_t *b, const vec3_t move, bool bSnap = true ); +int Brush_MoveVertex( brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap = true ); +void Brush_ResetFaceOriginals( brush_t *b ); +face_t* Brush_Ray( vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags = 0 ); +void Brush_RemoveFromList( brush_t *b ); +// bCaulk means the faces created during the operation will be caulked, this is used in conjunction with g_PrefsDlg.m_bClipCaulk +void Brush_SplitBrushByFace( brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk = false ); +void Brush_SelectFaceForDragging( brush_t *b, face_t *f, qboolean shear ); +void Brush_SetTexture( brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, IPluginTexdef* pPlugTexdef = (IPluginTexdef*)NULL ); +void Brush_SideSelect( brush_t *b, vec3_t origin, vec3_t dir, qboolean shear ); +void Brush_SnapToGrid( brush_t *pb ); +void Brush_Rotate( brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild = true ); +void Brush_MakeSidedSphere( int sides ); +//void Brush_Write (brush_t *b, FILE *f); +//void Brush_Write (brush_t *b, MemStream* pMemFile); +void Brush_RemoveEmptyFaces( brush_t *b ); +winding_t* Brush_MakeFaceWinding( brush_t *b, face_t *face ); + +void Brush_RefreshShader( brush_t *b ); + +int AddPlanept( float *f ); +float SetShadeForPlane( plane_t *p ); + +face_t* Face_Alloc( void ); +void Face_Free( face_t *f ); +face_t* Face_Clone( face_t *f ); +void Face_SetShader( face_t *face, const char *name ); +/*! + faster version if you know the IShader already + (instead of hash table lookup by name) + */ +void Face_SetShader( face_t *face, IShader *shader ); +void Face_MakePlane( face_t *f ); +void Face_Draw( face_t *face ); +void Face_TextureVectors( face_t * f, float STfromXYZ[2][4] ); +void SetFaceTexdef( face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale = false, IPluginTexdef* pPlugTexdef = NULL ); + +void Face_FitTexture( face_t * face, int nHeight, int nWidth ); +void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ); +//void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue); +//const char* Brush_GetKeyValue(brush_t *b, const char *pKey); +brush_t *Brush_Alloc(); +const char* Brush_Name( brush_t *b ); + +//eclass_t* HasModel(brush_t *b); +void aabb_draw( const aabb_t *aabb, int mode );