2020-11-17 03:16:16 -08:00
/*
2021-08-04 13:23:18 -07:00
Copyright ( C ) 1999 - 2006 Id Software , Inc . and contributors .
For a list of contributors , see the accompanying CONTRIBUTORS file .
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
This file is part of GtkRadiant .
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 .
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 .
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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
*/
2020-11-17 03:16:16 -08:00
# 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 <set>
# include "mathlib.h"
# 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 ) ;
# define BRUSH_CONNECTIVITY_DEBUG 0
# define BRUSH_DEGENERATE_DEBUG 0
template < typename TextOuputStreamType >
inline TextOuputStreamType & ostream_write ( TextOuputStreamType & ostream , const Matrix4 & m )
{
return ostream < < " ( " < < m [ 0 ] < < " " < < m [ 1 ] < < " " < < m [ 2 ] < < " " < < m [ 3 ] < < " , "
2021-08-04 13:23:18 -07:00
< < m [ 4 ] < < " " < < m [ 5 ] < < " " < < m [ 6 ] < < " " < < m [ 7 ] < < " , "
< < m [ 8 ] < < " " < < m [ 9 ] < < " " < < m [ 10 ] < < " " < < m [ 11 ] < < " , "
< < m [ 12 ] < < " " < < m [ 13 ] < < " " < < m [ 14 ] < < " " < < m [ 15 ] < < " ) " ;
2020-11-17 03:16:16 -08:00
}
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 ( ) < < " ) "
2021-08-04 13:23:18 -07:00
< < " ( " < < m . yx ( ) < < " " < < m . yy ( ) < < " " < < m . yz ( ) < < " ) "
< < " ( " < < m . zx ( ) < < " " < < m . zy ( ) < < " " < < m . zz ( ) < < " ) \n " ;
2020-11-17 03:16:16 -08:00
}
inline bool texdef_sane ( const texdef_t & texdef )
{
return fabs ( texdef . shift [ 0 ] ) < ( 1 < < 16 )
2021-08-04 13:23:18 -07:00
& & fabs ( texdef . shift [ 1 ] ) < ( 1 < < 16 ) ;
2020-11-17 03:16:16 -08:00
}
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 ) ,
2021-08-04 13:23:18 -07:00
& winding . points . data ( ) - > texcoord ) ;
2020-11-17 03:16:16 -08:00
glVertexAttribPointerARB ( c_attr_Tangent , 3 , GL_FLOAT , 0 , sizeof ( WindingVertex ) ,
2021-08-04 13:23:18 -07:00
& winding . points . data ( ) - > tangent ) ;
2020-11-17 03:16:16 -08:00
glVertexAttribPointerARB ( c_attr_Binormal , 3 , GL_FLOAT , 0 , sizeof ( WindingVertex ) ,
2021-08-04 13:23:18 -07:00
& winding . points . data ( ) - > bitangent ) ;
2020-11-17 03:16:16 -08:00
} 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
2021-08-04 13:23:18 -07:00
if ( state & RENDER_FILL ) {
2020-11-17 03:16:16 -08:00
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
2021-08-04 13:23:18 -07:00
const Winding & winding = winding ;
2020-11-17 03:16:16 -08:00
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 < float > ( 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 (
2021-08-04 13:23:18 -07:00
Vertex3f (
static_cast < float > ( point . x ( ) ) ,
static_cast < float > ( point . y ( ) ) ,
static_cast < float > ( point . z ( ) )
2020-11-17 03:16:16 -08:00
) ,
2021-08-04 13:23:18 -07:00
colour
) ;
2020-11-17 03:16:16 -08:00
}
inline PointVertex pointvertex_for_windingpoint ( const Vector3 & point , const Colour4b & colour )
{
return PointVertex (
2021-08-04 13:23:18 -07:00
vertex3f_for_vector3 ( point ) ,
colour
) ;
2020-11-17 03:16:16 -08:00
}
inline bool check_plane_is_integer ( const PlanePoints & planePoints )
{
return ! float_is_integer ( planePoints [ 0 ] [ 0 ] )
2021-08-04 13:23:18 -07:00
| | ! 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 ] ) ;
2020-11-17 03:16:16 -08:00
}
inline void brush_check_shader ( const char * name )
{
if ( ! shader_valid ( name ) ) {
globalErrorStream ( ) < < " brush face has invalid texture name: ' " < < name < < " ' \n " ;
}
}
class FaceShaderObserver {
public :
2021-08-04 13:23:18 -07:00
virtual void realiseShader ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void unrealiseShader ( ) = 0 ;
2020-11-17 03:16:16 -08:00
} ;
typedef ReferencePair < FaceShaderObserver > FaceShaderObserverPair ;
class ContentsFlagsValue {
public :
2021-08-04 13:23:18 -07:00
ContentsFlagsValue ( )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
ContentsFlagsValue ( int surfaceFlags , int contentFlags , int value , bool specified ) :
m_surfaceFlags ( surfaceFlags ) ,
m_contentFlags ( contentFlags ) ,
m_value ( value ) ,
m_specified ( specified )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
int m_surfaceFlags ;
int m_contentFlags ;
int m_value ;
bool m_specified ;
2020-11-17 03:16:16 -08:00
} ;
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 :
2021-08-04 13:23:18 -07:00
class SavedState {
public :
CopiedString m_shader ;
ContentsFlagsValue m_flags ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SavedState ( const FaceShader & faceShader )
{
m_shader = faceShader . getShader ( ) ;
m_flags = faceShader . m_flags ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void exportState ( FaceShader & faceShader ) const
{
faceShader . setShader ( m_shader . c_str ( ) ) ;
faceShader . setFlags ( m_flags ) ;
}
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
}
2020-11-17 03:16:16 -08:00
// copy-construction not supported
2021-08-04 13:23:18 -07:00
FaceShader ( const FaceShader & other ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void instanceAttach ( )
{
m_instanced = true ;
m_state - > incrementUsed ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void instanceDetach ( )
{
m_state - > decrementUsed ( ) ;
m_instanced = false ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void releaseShader ( )
{
ASSERT_MESSAGE ( m_state ! = 0 , " shader cannot be released " ) ;
m_state - > detach ( * this ) ;
GlobalShaderCache ( ) . release ( m_shader . c_str ( ) ) ;
m_state = 0 ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void realise ( )
{
ASSERT_MESSAGE ( ! m_realised , " FaceTexdef::realise: already realised " ) ;
m_realised = true ;
m_observers . forEach ( [ ] ( FaceShaderObserver & observer ) {
2020-11-17 03:16:16 -08:00
observer . realiseShader ( ) ;
} ) ;
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void unrealise ( )
{
ASSERT_MESSAGE ( m_realised , " FaceTexdef::unrealise: already unrealised " ) ;
m_observers . forEach ( [ ] ( FaceShaderObserver & observer ) {
2020-11-17 03:16:16 -08:00
observer . unrealiseShader ( ) ;
} ) ;
2021-08-04 13:23:18 -07:00
m_realised = false ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void attach ( FaceShaderObserver & observer )
{
m_observers . attach ( observer ) ;
if ( m_realised ) {
observer . realiseShader ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void detach ( FaceShaderObserver & observer )
{
if ( m_realised ) {
observer . unrealiseShader ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
m_observers . detach ( observer ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const char * getShader ( ) const
{
return m_shader . c_str ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setShader ( const char * name )
{
if ( m_instanced ) {
m_state - > decrementUsed ( ) ;
}
releaseShader ( ) ;
m_shader = name ;
captureShader ( ) ;
if ( m_instanced ) {
m_state - > incrementUsed ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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
2020-11-17 03:16:16 -08:00
) ;
}
2021-08-04 13:23:18 -07:00
return m_flags ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setFlags ( const ContentsFlagsValue & flags )
{
ASSERT_MESSAGE ( m_realised , " FaceShader::setFlags: flags not valid when unrealised " ) ;
ContentsFlagsValue_assignMasked ( m_flags , flags ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Shader * state ( ) const
{
return m_state ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t width ( ) const
{
if ( m_realised ) {
return m_state - > getTexture ( ) . width ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return 1 ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t height ( ) const
{
if ( m_realised ) {
return m_state - > getTexture ( ) . height ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return 1 ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
unsigned int shaderFlags ( ) const
{
if ( m_realised ) {
return m_state - > getFlags ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return 0 ;
}
2020-11-17 03:16:16 -08:00
} ;
class FaceTexdef : public FaceShaderObserver {
// not copyable
2021-08-04 13:23:18 -07:00
FaceTexdef ( const FaceTexdef & other ) ;
2020-11-17 03:16:16 -08:00
// not assignable
2021-08-04 13:23:18 -07:00
FaceTexdef & operator = ( const FaceTexdef & other ) ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
class SavedState {
public :
TextureProjection m_projection ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SavedState ( const FaceTexdef & faceTexdef )
{
m_projection = faceTexdef . m_projection ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void exportState ( FaceTexdef & faceTexdef ) const
{
Texdef_Assign ( faceTexdef . m_projection , m_projection ) ;
}
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceShader & m_shader ;
TextureProjection m_projection ;
bool m_projectionInitialised ;
bool m_scaleApplied ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceTexdef (
FaceShader & shader ,
const TextureProjection & projection ,
bool projectionInitialised = true
2020-11-17 03:16:16 -08:00
) :
2021-08-04 13:23:18 -07:00
m_shader ( shader ) ,
m_projection ( projection ) ,
m_projectionInitialised ( projectionInitialised ) ,
m_scaleApplied ( false )
{
m_shader . attach ( * this ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
~ FaceTexdef ( )
{
m_shader . detach ( * this ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void realiseShader ( )
{
if ( m_projectionInitialised & & ! m_scaleApplied ) {
2020-11-17 03:16:16 -08:00
addScale ( ) ;
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void unrealiseShader ( )
{
if ( m_projectionInitialised & & m_scaleApplied ) {
2020-11-17 03:16:16 -08:00
removeScale ( ) ;
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setTexdef ( const TextureProjection & projection )
{
removeScale ( ) ;
Texdef_Assign ( m_projection , projection ) ;
addScale ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void scale ( float s , float t )
{
removeScale ( ) ;
Texdef_Scale ( m_projection , s , t ) ;
addScale ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void rotate ( float angle )
{
removeScale ( ) ;
Texdef_Rotate ( m_projection , angle ) ;
addScale ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2021-10-29 16:51:34 -07:00
void align ( const Plane3 & plane , const Vector3 & normal , const Winding & winding , int alignment )
{
Texdef_AlignTexture ( m_projection , plane , normal , winding , m_shader . width ( ) , m_shader . height ( ) , alignment ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void emitTextureCoordinates ( Winding & winding , const Vector3 & normal , const Matrix4 & localToWorld )
{
Texdef_EmitTextureCoordinates ( m_projection , m_shader . width ( ) , m_shader . height ( ) , winding , normal , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
if ( g_bp_globals . m_texdefTypeId = = TEXDEFTYPEID_HALFLIFE ) {
Vector3 s = m_projection . m_basis_s , t = m_projection . m_basis_t ;
RotatePointAroundVector ( m_projection . m_basis_s . data ( ) , normal . data ( ) , s . data ( ) , m_projection . m_texdef . rotate ) ;
RotatePointAroundVector ( m_projection . m_basis_t . data ( ) , normal . data ( ) , t . data ( ) , m_projection . m_texdef . rotate ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
inline void planepts_print ( const PlanePoints & planePoints , TextOutputStream & ostream )
{
ostream < < " ( " < < planePoints [ 0 ] [ 0 ] < < " " < < planePoints [ 0 ] [ 1 ] < < " " < < planePoints [ 0 ] [ 2 ] < < " ) "
2021-08-04 13:23:18 -07:00
< < " ( " < < planePoints [ 1 ] [ 0 ] < < " " < < planePoints [ 1 ] [ 1 ] < < " " < < planePoints [ 1 ] [ 2 ] < < " ) "
< < " ( " < < planePoints [ 2 ] [ 0 ] < < " " < < planePoints [ 2 ] [ 1 ] < < " " < < planePoints [ 2 ] [ 2 ] < < " ) " ;
2020-11-17 03:16:16 -08:00
}
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 {
2021-08-04 13:23:18 -07:00
PlanePoints m_planepts ;
Plane3 m_planeCached ;
Plane3 m_plane ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
Vector3 m_funcStaticOrigin ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static EBrushType m_type ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static bool isDoom3Plane ( )
{
return FacePlane : : m_type = = eBrushTypeDoom3 | | FacePlane : : m_type = = eBrushTypeQuake4 ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
class SavedState {
public :
PlanePoints m_planepts ;
Plane3 m_plane ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SavedState ( const FacePlane & facePlane )
{
if ( facePlane . isDoom3Plane ( ) ) {
m_plane = facePlane . m_plane ;
} else {
planepts_assign ( m_planepts , facePlane . planePoints ( ) ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void exportState ( FacePlane & facePlane ) const
{
if ( facePlane . isDoom3Plane ( ) ) {
facePlane . m_plane = m_plane ;
facePlane . updateTranslated ( ) ;
} else {
planepts_assign ( facePlane . planePoints ( ) , m_planepts ) ;
facePlane . MakePlane ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void MakePlane ( )
{
if ( ! isDoom3Plane ( ) ) {
2020-11-17 03:16:16 -08:00
#if 0
2021-08-04 13:23:18 -07:00
if ( check_plane_is_integer ( m_planepts ) ) {
2020-11-17 03:16:16 -08:00
globalErrorStream ( ) < < " non-integer planepts: " ;
planepts_print ( m_planepts , globalErrorStream ( ) ) ;
globalErrorStream ( ) < < " \n " ;
}
# endif
2021-08-04 13:23:18 -07:00
m_planeCached = plane3_for_points ( m_planepts ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void reverse ( )
{
if ( ! isDoom3Plane ( ) ) {
vector3_swap ( m_planepts [ 0 ] , m_planepts [ 2 ] ) ;
MakePlane ( ) ;
} else {
m_planeCached = plane3_flipped ( m_plane ) ;
updateSource ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void transform ( const Matrix4 & matrix , bool mirror )
{
if ( ! isDoom3Plane ( ) ) {
2020-11-17 03:16:16 -08:00
#if 0
2021-08-04 13:23:18 -07:00
bool off = check_plane_is_integer ( planePoints ( ) ) ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
matrix4_transform_point ( matrix , m_planepts [ 0 ] ) ;
matrix4_transform_point ( matrix , m_planepts [ 1 ] ) ;
matrix4_transform_point ( matrix , m_planepts [ 2 ] ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( mirror ) {
reverse ( ) ;
}
2020-11-17 03:16:16 -08:00
#if 0
2021-08-04 13:23:18 -07:00
if ( check_plane_is_integer ( planePoints ( ) ) ) {
2020-11-17 03:16:16 -08:00
if ( ! off ) {
globalErrorStream ( ) < < " caused by transform \n " ;
}
}
# endif
2021-08-04 13:23:18 -07:00
MakePlane ( ) ;
} else {
m_planeCached = Plane3_applyTransform ( m_planeCached , matrix ) ;
updateSource ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void offset ( float offset )
{
if ( ! isDoom3Plane ( ) ) {
Vector3 move ( vector3_scaled ( m_planeCached . normal ( ) , - offset ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
vector3_subtract ( m_planepts [ 0 ] , move ) ;
vector3_subtract ( m_planepts [ 1 ] , move ) ;
vector3_subtract ( m_planepts [ 2 ] , move ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
MakePlane ( ) ;
} else {
m_planeCached . d + = offset ;
updateSource ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void updateTranslated ( )
{
m_planeCached = Plane3_applyTranslation ( m_plane , m_funcStaticOrigin ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void updateSource ( )
{
m_plane = Plane3_applyTranslation ( m_planeCached , vector3_negated ( m_funcStaticOrigin ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
PlanePoints & planePoints ( )
{
return m_planepts ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const PlanePoints & planePoints ( ) const
{
return m_planepts ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Plane3 & plane3 ( ) const
{
return m_planeCached ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setDoom3Plane ( const Plane3 & plane )
{
m_plane = plane ;
updateTranslated ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Plane3 & getDoom3Plane ( ) const
{
return m_plane ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void copy ( const FacePlane & other )
{
if ( ! isDoom3Plane ( ) ) {
planepts_assign ( m_planepts , other . m_planepts ) ;
MakePlane ( ) ;
} else {
m_planeCached = other . m_plane ;
updateSource ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
inline void Winding_testSelect ( Winding & winding , SelectionTest & test , SelectionIntersection & best )
{
test . TestPolygon ( VertexPointer ( reinterpret_cast < VertexPointer : : pointer > ( & winding . points . data ( ) - > vertex ) ,
2021-08-04 13:23:18 -07:00
sizeof ( WindingVertex ) ) , winding . numpoints , best ) ;
2020-11-17 03:16:16 -08:00
}
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 :
2021-08-04 13:23:18 -07:00
virtual bool filter ( const Face & face ) const = 0 ;
2020-11-17 03:16:16 -08:00
} ;
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 :
2021-08-04 13:23:18 -07:00
virtual void planeChanged ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void connectivityChanged ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void shaderChanged ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void evaluateTransform ( ) = 0 ;
2020-11-17 03:16:16 -08:00
} ;
class Face :
2021-08-04 13:23:18 -07:00
public OpenGLRenderable ,
public Filterable ,
public Undoable ,
public FaceShaderObserver {
std : : size_t m_refcount ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
class SavedState : public UndoMemento {
public :
FacePlane : : SavedState m_planeState ;
FaceTexdef : : SavedState m_texdefState ;
FaceShader : : SavedState m_shaderState ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
}
} ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
static QuantiseFunc m_quantise ;
static EBrushType m_type ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
PlanePoints m_move_planepts ;
PlanePoints m_move_planeptsTransformed ;
2020-11-17 03:16:16 -08:00
private :
2021-08-04 13:23:18 -07:00
FacePlane m_plane ;
FacePlane m_planeTransformed ;
FaceShader m_shader ;
FaceTexdef m_texdef ;
TextureProjection m_texdefTransformed ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Winding m_winding ;
Vector3 m_centroid ;
bool m_filtered ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceObserver * m_observer ;
UndoObserver * m_undoable_observer ;
MapFile * m_map ;
2020-11-17 03:16:16 -08:00
// assignment not supported
2021-08-04 13:23:18 -07:00
Face & operator = ( const Face & other ) ;
2020-11-17 03:16:16 -08:00
// copy-construction not supported
2021-08-04 13:23:18 -07:00
Face ( const Face & other ) ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
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 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Face (
const Vector3 & p0 ,
const Vector3 & p1 ,
const Vector3 & p2 ,
const char * shader ,
const TextureProjection & projection ,
FaceObserver * observer
2020-11-17 03:16:16 -08:00
) :
2021-08-04 13:23:18 -07:00
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 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
// if (g_bp_globals.m_texdefTypeId != TEXDEFTYPEID_HALFLIFE) {
// m_texdef.setBasis(m_plane.plane3().normal());
// }
2021-08-04 13:23:18 -07:00
planeChanged ( ) ;
updateFiltered ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
~ Face ( )
{
m_shader . detach ( * this ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void planeChanged ( )
{
revertTransform ( ) ;
m_observer - > planeChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void realiseShader ( )
{
m_observer - > shaderChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void unrealiseShader ( )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void instanceAttach ( MapFile * map )
{
m_shader . instanceAttach ( ) ;
m_map = map ;
m_undoable_observer = GlobalUndoSystem ( ) . observer ( this ) ;
GlobalFilterSystem ( ) . registerFilterable ( * this ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void instanceDetach ( MapFile * map )
{
GlobalFilterSystem ( ) . unregisterFilterable ( * this ) ;
m_undoable_observer = 0 ;
GlobalUndoSystem ( ) . release ( this ) ;
m_map = 0 ;
m_shader . instanceDetach ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void render ( RenderStateFlags state ) const
{
Winding_Draw ( m_winding , m_planeTransformed . plane3 ( ) . normal ( ) , state ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void updateFiltered ( )
{
m_filtered = face_filtered ( * this ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isFiltered ( ) const
{
return m_filtered ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void undoSave ( )
{
if ( m_map ! = 0 ) {
m_map - > changed ( ) ;
}
if ( m_undoable_observer ! = 0 ) {
m_undoable_observer - > save ( this ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
// undoable
2021-08-04 13:23:18 -07:00
UndoMemento * exportState ( ) const
{
return new SavedState ( * this ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void importState ( const UndoMemento * data )
{
undoSave ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static_cast < const SavedState * > ( data ) - > exportState ( * this ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
planeChanged ( ) ;
m_observer - > connectivityChanged ( ) ;
texdefChanged ( ) ;
m_observer - > shaderChanged ( ) ;
updateFiltered ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void IncRef ( )
{
+ + m_refcount ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void DecRef ( )
{
if ( - - m_refcount = = 0 ) {
delete this ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void flipWinding ( )
{
m_plane . reverse ( ) ;
planeChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool intersectVolume ( const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
return volume . TestPlane ( Plane3 ( plane3 ( ) . normal ( ) , - plane3 ( ) . dist ( ) ) , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void render ( Renderer & renderer , const Matrix4 & localToWorld ) const
{
renderer . SetState ( m_shader . state ( ) , Renderer : : eFullMaterials ) ;
renderer . addRenderable ( * this , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_planeTransformed . transform ( matrix , mirror ) ;
2020-11-17 03:16:16 -08:00
#if 0
2021-08-04 13:23:18 -07:00
ASSERT_MESSAGE ( projectionaxis_for_normal ( normal ) = = projectionaxis_for_normal ( plane3 ( ) . normal ( ) ) , " bleh " ) ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
m_observer - > planeChanged ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( g_brush_texturelock_enabled ) {
Brush_textureChanged ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void assign_planepts ( const PlanePoints planepts )
{
m_planeTransformed . copy ( planepts [ 0 ] , planepts [ 1 ] , planepts [ 2 ] ) ;
m_observer - > planeChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
/// \brief Reverts the transformable state of the brush to identity.
2021-08-04 13:23:18 -07:00
void revertTransform ( )
{
m_planeTransformed = m_plane ;
planepts_assign ( m_move_planeptsTransformed , m_move_planepts ) ;
m_texdefTransformed = m_texdef . m_projection ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void freezeTransform ( )
{
undoSave ( ) ;
m_plane = m_planeTransformed ;
planepts_assign ( m_move_planepts , m_move_planeptsTransformed ) ;
m_texdef . m_projection = m_texdefTransformed ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void snapto ( float snap )
{
if ( contributes ( ) ) {
2020-11-17 03:16:16 -08:00
#if 0
2021-08-04 13:23:18 -07:00
ASSERT_MESSAGE ( plane3_valid ( m_plane . plane3 ( ) ) , " invalid plane before snap to grid " ) ;
2020-11-17 03:16:16 -08:00
planepts_snap ( m_plane . planePoints ( ) , snap ) ;
ASSERT_MESSAGE ( plane3_valid ( m_plane . plane3 ( ) ) , " invalid plane after snap to grid " ) ;
# else
2021-08-04 13:23:18 -07:00
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 ( ) ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
SceneChangeNotify ( ) ;
if ( ! plane3_valid ( m_plane . plane3 ( ) ) ) {
globalErrorStream ( ) < < " WARNING: invalid plane after snap to grid \n " ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect ( SelectionTest & test , SelectionIntersection & best )
{
Winding_testSelect ( m_winding , test , best ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect_centroid ( SelectionTest & test , SelectionIntersection & best )
{
test . TestPoint ( m_centroid , best ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void shaderChanged ( )
{
EmitTextureCoordinates ( ) ;
Brush_textureChanged ( ) ;
m_observer - > shaderChanged ( ) ;
updateFiltered ( ) ;
planeChanged ( ) ;
SceneChangeNotify ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const char * GetShader ( ) const
{
return m_shader . getShader ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void SetShader ( const char * name )
{
undoSave ( ) ;
m_shader . setShader ( name ) ;
shaderChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void revertTexdef ( )
{
m_texdefTransformed = m_texdef . m_projection ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void texdefChanged ( )
{
revertTexdef ( ) ;
EmitTextureCoordinates ( ) ;
Brush_textureChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void GetTexdef ( TextureProjection & projection ) const
{
projection = m_texdef . normalised ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void SetTexdef ( const TextureProjection & projection , bool ignorebasis )
{
undoSave ( ) ;
m_texdef . setTexdef ( projection ) ;
if ( ignorebasis )
m_texdef . setBasis ( m_plane . plane3 ( ) . normal ( ) ) ;
texdefChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void GetFlags ( ContentsFlagsValue & flags ) const
{
flags = m_shader . getFlags ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void SetFlags ( const ContentsFlagsValue & flags )
{
undoSave ( ) ;
m_shader . setFlags ( flags ) ;
m_observer - > shaderChanged ( ) ;
updateFiltered ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void ShiftTexdef ( float s , float t )
{
undoSave ( ) ;
m_texdef . shift ( s , t ) ;
texdefChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void ScaleTexdef ( float s , float t )
{
undoSave ( ) ;
m_texdef . scale ( s , t ) ;
texdefChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void RotateTexdef ( float angle )
{
undoSave ( ) ;
m_texdef . rotate ( angle ) ;
texdefChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void FitTexture ( float s_repeat , float t_repeat )
{
undoSave ( ) ;
m_texdef . fit ( m_plane . plane3 ( ) . normal ( ) , m_winding , s_repeat , t_repeat ) ;
texdefChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-10-29 16:51:34 -07:00
void AlignTexture ( int alignment )
{
undoSave ( ) ;
m_texdef . align ( m_plane . plane3 ( ) , m_plane . plane3 ( ) . normal ( ) , m_winding , alignment ) ;
texdefChanged ( ) ;
}
2021-08-04 13:23:18 -07:00
void EmitTextureCoordinates ( )
{
Texdef_EmitTextureCoordinates ( m_texdefTransformed , m_shader . width ( ) , m_shader . height ( ) , m_winding ,
plane3 ( ) . normal ( ) , g_matrix4_identity ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Vector3 & centroid ( ) const
{
return m_centroid ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void construct_centroid ( )
{
Winding_Centroid ( m_winding , plane3 ( ) , m_centroid ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Winding & getWinding ( ) const
{
return m_winding ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Winding & getWinding ( )
{
return m_winding ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Plane3 & plane3 ( ) const
{
m_observer - > evaluateTransform ( ) ;
return m_planeTransformed . plane3 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FacePlane & getPlane ( )
{
return m_plane ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const FacePlane & getPlane ( ) const
{
return m_plane ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceTexdef & getTexdef ( )
{
return m_texdef ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const FaceTexdef & getTexdef ( ) const
{
return m_texdef ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceShader & getShader ( )
{
return m_shader ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const FaceShader & getShader ( ) const
{
return m_shader ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isDetail ( ) const
{
return ( m_shader . m_flags . m_contentFlags & BRUSH_DETAIL_MASK ) ! = 0 ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
m_observer - > shaderChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool contributes ( ) const
{
return m_winding . numpoints > 2 ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
return true ;
}
2020-11-17 03:16:16 -08:00
} ;
class FaceVertexId {
2021-08-04 13:23:18 -07:00
std : : size_t m_face ;
std : : size_t m_vertex ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
FaceVertexId ( std : : size_t face , std : : size_t vertex )
: m_face ( face ) , m_vertex ( vertex )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t getFace ( ) const
{
return m_face ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t getVertex ( ) const
{
return m_vertex ;
}
2020-11-17 03:16:16 -08:00
} ;
typedef std : : size_t faceIndex_t ;
struct EdgeRenderIndices {
RenderIndex first ;
RenderIndex second ;
EdgeRenderIndices ( )
2021-08-04 13:23:18 -07:00
: first ( 0 ) , second ( 0 )
2020-11-17 03:16:16 -08:00
{
}
EdgeRenderIndices ( const RenderIndex _first , const RenderIndex _second )
2021-08-04 13:23:18 -07:00
: first ( _first ) , second ( _second )
2020-11-17 03:16:16 -08:00
{
}
} ;
struct EdgeFaces {
faceIndex_t first ;
faceIndex_t second ;
EdgeFaces ( )
2021-08-04 13:23:18 -07:00
: first ( c_brush_maxFaces ) , second ( c_brush_maxFaces )
2020-11-17 03:16:16 -08:00
{
}
EdgeFaces ( const faceIndex_t _first , const faceIndex_t _second )
2021-08-04 13:23:18 -07:00
: first ( _first ) , second ( _second )
2020-11-17 03:16:16 -08:00
{
}
} ;
class RenderableWireframe : public OpenGLRenderable {
public :
2021-08-04 13:23:18 -07:00
void render ( RenderStateFlags state ) const
{
2020-11-17 03:16:16 -08:00
# if 1
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
2020-11-17 03:16:16 -08:00
# else
2021-08-04 13:23:18 -07:00
glBegin ( GL_LINES ) ;
2020-11-17 03:16:16 -08:00
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
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Array < EdgeRenderIndices > m_faceVertex ;
std : : size_t m_size ;
const PointVertex * m_vertices ;
2020-11-17 03:16:16 -08:00
} ;
class Brush ;
typedef std : : vector < Brush * > brush_vector_t ;
class BrushFilter {
public :
2021-08-04 13:23:18 -07:00
virtual bool filter ( const Brush & brush ) const = 0 ;
2020-11-17 03:16:16 -08:00
} ;
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 , bool selfIsLater )
{
if ( vector3_equal_epsilon ( self . normal ( ) , other . normal ( ) , 0.001 ) ) {
// same plane? prefer the one with smaller index
if ( self . dist ( ) = = other . dist ( ) ) {
return selfIsLater ;
}
return self . dist ( ) < other . dist ( ) ;
}
return true ;
}
typedef SmartPointer < Face > FaceSmartPointer ;
typedef std : : vector < FaceSmartPointer > 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 ( ) ,
2021-08-04 13:23:18 -07:00
Winding_next ( faces [ nextEdge . getFace ( ) ] - > getWinding ( ) , nextEdge . getVertex ( ) ) ) ;
2020-11-17 03:16:16 -08:00
}
class SelectableEdge {
2021-08-04 13:23:18 -07:00
Vector3 getEdge ( ) const
{
const Winding & winding = getFace ( ) . getWinding ( ) ;
return vector3_mid ( winding [ m_faceVertex . getVertex ( ) ] . vertex ,
winding [ Winding_next ( winding , m_faceVertex . getVertex ( ) ) ] . vertex ) ;
}
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
Faces & m_faces ;
FaceVertexId m_faceVertex ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SelectableEdge ( Faces & faces , FaceVertexId faceVertex )
: m_faces ( faces ) , m_faceVertex ( faceVertex )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SelectableEdge & operator = ( const SelectableEdge & other )
{
m_faceVertex = other . m_faceVertex ;
return * this ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Face & getFace ( ) const
{
return * m_faces [ m_faceVertex . getFace ( ) ] ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect ( SelectionTest & test , SelectionIntersection & best )
{
test . TestPoint ( getEdge ( ) , best ) ;
}
2020-11-17 03:16:16 -08:00
} ;
class SelectableVertex {
2021-08-04 13:23:18 -07:00
Vector3 getVertex ( ) const
{
return getFace ( ) . getWinding ( ) [ m_faceVertex . getVertex ( ) ] . vertex ;
}
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
Faces & m_faces ;
FaceVertexId m_faceVertex ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SelectableVertex ( Faces & faces , FaceVertexId faceVertex )
: m_faces ( faces ) , m_faceVertex ( faceVertex )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
SelectableVertex & operator = ( const SelectableVertex & other )
{
m_faceVertex = other . m_faceVertex ;
return * this ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Face & getFace ( ) const
{
return * m_faces [ m_faceVertex . getFace ( ) ] ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect ( SelectionTest & test , SelectionIntersection & best )
{
test . TestPoint ( getVertex ( ) , best ) ;
}
2020-11-17 03:16:16 -08:00
} ;
class BrushObserver {
public :
2021-08-04 13:23:18 -07:00
virtual void reserve ( std : : size_t size ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void clear ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void push_back ( Face & face ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void pop_back ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void erase ( std : : size_t index ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void connectivityChanged ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void edge_clear ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void edge_push_back ( SelectableEdge & edge ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void vertex_clear ( ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void vertex_push_back ( SelectableVertex & vertex ) = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
virtual void DEBUG_verify ( ) const = 0 ;
2020-11-17 03:16:16 -08:00
} ;
class BrushVisitor {
public :
2021-08-04 13:23:18 -07:00
virtual void visit ( Face & face ) const = 0 ;
2020-11-17 03:16:16 -08:00
} ;
class Brush :
2021-08-04 13:23:18 -07:00
public TransformNode ,
public Bounded ,
public Cullable ,
public Snappable ,
public Undoable ,
public FaceObserver ,
public Filterable ,
public Nameable ,
public BrushDoom3 {
2020-11-17 03:16:16 -08:00
private :
2021-08-04 13:23:18 -07:00
scene : : Node * m_node ;
typedef UniqueSet < BrushObserver * > Observers ;
Observers m_observers ;
UndoObserver * m_undoable_observer ;
MapFile * m_map ;
2020-11-17 03:16:16 -08:00
// state
2021-08-04 13:23:18 -07:00
Faces m_faces ;
2020-11-17 03:16:16 -08:00
// ----
// cached data compiled from state
2021-08-04 13:23:18 -07:00
Array < PointVertex > m_faceCentroidPoints ;
RenderablePointArray m_render_faces ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Array < PointVertex > m_uniqueVertexPoints ;
typedef std : : vector < SelectableVertex > SelectableVertices ;
SelectableVertices m_select_vertices ;
RenderablePointArray m_render_vertices ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Array < PointVertex > m_uniqueEdgePoints ;
typedef std : : vector < SelectableEdge > SelectableEdges ;
SelectableEdges m_select_edges ;
RenderablePointArray m_render_edges ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Array < EdgeRenderIndices > m_edge_indices ;
Array < EdgeFaces > m_edge_faces ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
AABB m_aabb_local ;
2020-11-17 03:16:16 -08:00
// ----
2021-08-04 13:23:18 -07:00
Callback < void ( ) > m_evaluateTransform ;
Callback < void ( ) > m_boundsChanged ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
mutable bool m_planeChanged ; // b-rep evaluation required
mutable bool m_transformChanged ; // transform evaluation required
2020-11-17 03:16:16 -08:00
// ----
public :
2021-08-04 13:23:18 -07:00
STRING_CONSTANT ( Name , " Brush " ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Callback < void ( ) > m_lightsChanged ;
2020-11-17 03:16:16 -08:00
// static data
2021-08-04 13:23:18 -07:00
static Shader * m_state_point ;
2020-11-17 03:16:16 -08:00
// ----
2021-08-04 13:23:18 -07:00
static EBrushType m_type ;
static double m_maxWorldCoord ;
Brush ( scene : : Node & node , const Callback < void ( ) > & evaluateTransform , const Callback < void ( ) > & 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 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Brush ( const Brush & other , scene : : Node & node , const Callback < void ( ) > & evaluateTransform ,
const Callback < void ( ) > & 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 ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
~ Brush ( )
{
ASSERT_MESSAGE ( m_observers . empty ( ) , " Brush::~Brush: observers still attached " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
// assignment not supported
Brush & operator = ( const Brush & other ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void attach ( BrushObserver & observer )
{
for ( Faces : : iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
observer . push_back ( * ( * i ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( SelectableEdges : : iterator i = m_select_edges . begin ( ) ; i ! = m_select_edges . end ( ) ; + + i ) {
observer . edge_push_back ( * i ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
for ( SelectableVertices : : iterator i = m_select_vertices . begin ( ) ; i ! = m_select_vertices . end ( ) ; + + i ) {
observer . vertex_push_back ( * i ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
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 ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void forEachFace_instanceAttach ( MapFile * map ) const
{
for ( Faces : : const_iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
( * i ) - > instanceAttach ( map ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void forEachFace_instanceDetach ( MapFile * map ) const
{
for ( Faces : : const_iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
( * i ) - > instanceDetach ( map ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
InstanceCounter m_instanceCounter ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 " ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
// nameable
2021-08-04 13:23:18 -07:00
const char * name ( ) const
{
return " brush " ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void attach ( const NameCallback & callback )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void detach ( const NameCallback & callback )
{
}
2020-11-17 03:16:16 -08:00
// filterable
2021-08-04 13:23:18 -07:00
void updateFiltered ( )
{
if ( m_node ! = 0 ) {
if ( brush_filtered ( * this ) ) {
m_node - > enable ( scene : : Node : : eFiltered ) ;
} else {
m_node - > disable ( scene : : Node : : eFiltered ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
// observer
2021-08-04 13:23:18 -07:00
void planeChanged ( )
{
m_planeChanged = true ;
aabbChanged ( ) ;
m_lightsChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void shaderChanged ( )
{
updateFiltered ( ) ;
planeChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void evaluateBRep ( ) const
{
if ( m_planeChanged ) {
m_planeChanged = false ;
const_cast < Brush * > ( this ) - > buildBRep ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void transformChanged ( )
{
m_transformChanged = true ;
planeChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef MemberCaller < Brush , void ( ) , & Brush : : transformChanged > TransformChangedCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void evaluateTransform ( )
{
if ( m_transformChanged ) {
m_transformChanged = false ;
revertTransform ( ) ;
m_evaluateTransform ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Matrix4 & localToParent ( ) const
{
return g_matrix4_identity ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void aabbChanged ( )
{
m_boundsChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const AABB & localAABB ( ) const
{
evaluateBRep ( ) ;
return m_aabb_local ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
VolumeIntersectionValue intersectVolume ( const VolumeTest & test , const Matrix4 & localToWorld ) const
{
return test . TestAABB ( m_aabb_local , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void transform ( const Matrix4 & matrix )
{
bool mirror = matrix4_handedness ( matrix ) = = MATRIX4_LEFTHANDED ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( Faces : : iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
( * i ) - > transform ( matrix , mirror ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void snapto ( float snap )
{
for ( Faces : : iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
( * i ) - > snapto ( snap ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void revertTransform ( )
{
for ( Faces : : iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
( * i ) - > revertTransform ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void freezeTransform ( )
{
for ( Faces : : iterator i = m_faces . begin ( ) ; i ! = m_faces . end ( ) ; + + i ) {
( * i ) - > freezeTransform ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Returns the absolute index of the \p faceVertex.
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return index + faceVertex . getVertex ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void appendFaces ( const Faces & other )
{
clear ( ) ;
for ( Faces : : const_iterator i = other . begin ( ) ; i ! = other . end ( ) ; + + i ) {
push_back ( * i ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief The undo memento for a brush stores only the list of face references - the faces are not copied.
2021-08-04 13:23:18 -07:00
class BrushUndoMemento : public UndoMemento {
public :
BrushUndoMemento ( const Faces & faces ) : m_faces ( faces )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void release ( )
{
delete this ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Faces m_faces ;
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void undoSave ( )
{
if ( m_map ! = 0 ) {
m_map - > changed ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
if ( m_undoable_observer ! = 0 ) {
m_undoable_observer - > save ( this ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
UndoMemento * exportState ( ) const
{
return new BrushUndoMemento ( m_faces ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void importState ( const UndoMemento * state )
{
undoSave ( ) ;
appendFaces ( static_cast < const BrushUndoMemento * > ( state ) - > m_faces ) ;
planeChanged ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > DEBUG_verify ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
bool isDetail ( )
{
return ! m_faces . empty ( ) & & m_faces . front ( ) - > isDetail ( ) ;
}
2020-11-17 03:16:16 -08:00
/// \brief Appends a copy of \p face to the end of the face list.
2021-08-04 13:23:18 -07:00
Face * addFace ( const Face & face )
{
if ( m_faces . size ( ) = = c_brush_maxFaces ) {
return 0 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
undoSave ( ) ;
push_back ( FaceSmartPointer ( new Face ( face , this ) ) ) ;
m_faces . back ( ) - > setDetail ( isDetail ( ) ) ;
planeChanged ( ) ;
return m_faces . back ( ) ;
}
2020-11-17 03:16:16 -08:00
/// \brief Appends a new face constructed from the parameters to the end of the face list.
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
undoSave ( ) ;
push_back ( FaceSmartPointer ( new Face ( p0 , p1 , p2 , shader , projection , this ) ) ) ;
m_faces . back ( ) - > setDetail ( isDetail ( ) ) ;
planeChanged ( ) ;
return m_faces . back ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static void constructStatic ( EBrushType type )
{
m_type = type ;
Face : : m_type = type ;
FacePlane : : m_type = type ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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; // bad idea, this overrides user setting
} else if ( m_type = = eBrushTypeHalfLife | | m_type = = eBrushTypeQuake3Valve ) {
g_bp_globals . m_texdefTypeId = TEXDEFTYPEID_HALFLIFE ;
// g_brush_texturelock_enabled = true; // bad idea, this overrides user setting
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
Face : : m_quantise = ( m_type = = eBrushTypeQuake ) ? quantiseInteger : quantiseFloating ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_state_point = GlobalShaderCache ( ) . capture ( " $POINT " ) ;
}
static void destroyStatic ( )
{
GlobalShaderCache ( ) . release ( " $POINT " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t DEBUG_size ( )
{
return m_faces . size ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef Faces : : const_iterator const_iterator ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const_iterator begin ( ) const
{
return m_faces . begin ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const_iterator end ( ) const
{
return m_faces . end ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Face * back ( )
{
return m_faces . back ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void push_back ( Faces : : value_type face )
{
m_faces . push_back ( face ) ;
if ( m_instanceCounter . m_count ! = 0 ) {
m_faces . back ( ) - > instanceAttach ( m_map ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > push_back ( * face ) ;
( * i ) - > DEBUG_verify ( ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void pop_back ( )
{
if ( m_instanceCounter . m_count ! = 0 ) {
m_faces . back ( ) - > instanceDetach ( m_map ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
m_faces . pop_back ( ) ;
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > pop_back ( ) ;
( * i ) - > DEBUG_verify ( ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void erase ( std : : size_t index )
{
if ( m_instanceCounter . m_count ! = 0 ) {
m_faces [ index ] - > instanceDetach ( m_map ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
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 ( ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void connectivityChanged ( )
{
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > connectivityChanged ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void clear ( )
{
undoSave ( ) ;
if ( m_instanceCounter . m_count ! = 0 ) {
forEachFace_instanceDetach ( m_map ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
m_faces . clear ( ) ;
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > clear ( ) ;
( * i ) - > DEBUG_verify ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t size ( ) const
{
return m_faces . size ( ) ;
}
bool empty ( ) const
{
return m_faces . empty ( ) ;
}
2020-11-17 03:16:16 -08:00
/// \brief Returns true if any face of the brush contributes to the final B-Rep.
2021-08-04 13:23:18 -07:00
bool hasContributingFaces ( ) const
{
for ( const_iterator i = begin ( ) ; i ! = end ( ) ; + + i ) {
if ( ( * i ) - > contributes ( ) ) {
return true ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
return false ;
}
2020-11-17 03:16:16 -08:00
/// \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.
2021-08-04 13:23:18 -07:00
void removeEmptyFaces ( )
{
evaluateBRep ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
{
std : : size_t i = 0 ;
while ( i < m_faces . size ( ) ) {
if ( ! m_faces [ i ] - > contributes ( ) ) {
erase ( i ) ;
planeChanged ( ) ;
} else {
+ + i ;
2020-11-17 03:16:16 -08:00
}
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Constructs \p winding from the intersection of \p plane with the other planes of the brush.
2021-08-04 13:23:18 -07:00
void windingForClipPlane ( Winding & winding , const Plane3 & plane ) const
{
FixedWinding buffer [ 2 ] ;
bool swap = false ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
// get a poly that covers an effectively infinite area
Winding_createInfinite ( buffer [ swap ] , plane , m_maxWorldCoord + 1 ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
// 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 ] ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( plane3_equal ( clip . plane3 ( ) , plane )
| | ! plane3_valid ( clip . plane3 ( ) ) | | ! plane_unique ( i )
| | plane3_opposing ( plane , clip . plane3 ( ) ) ) {
continue ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
buffer [ ! swap ] . clear ( ) ;
2020-11-17 03:16:16 -08:00
# if BRUSH_CONNECTIVITY_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " clip vs face: " < < i < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
{
// 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 ] ) ;
}
2020-11-17 03:16:16 -08:00
# if BRUSH_CONNECTIVITY_DEBUG
2021-08-04 13:23:18 -07:00
for ( FixedWinding : : Points : : iterator k = buffer [ ! swap ] . points . begin ( ) , j = buffer [ ! swap ] . points . end ( ) - 1 ; k ! = buffer [ ! swap ] . points . end ( ) ; j = k , + + k )
2020-11-17 03:16:16 -08:00
{
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
2021-08-04 13:23:18 -07:00
//ASSERT_MESSAGE(buffer[!swap].numpoints != 1, "created single-point winding");
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
swap = ! swap ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Winding_forFixedWinding ( winding , buffer [ swap ] ) ;
2020-11-17 03:16:16 -08:00
# if BRUSH_CONNECTIVITY_DEBUG
2021-08-04 13:23:18 -07:00
Winding_printConnectivity ( winding ) ;
2020-11-17 03:16:16 -08:00
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
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ] ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void update_faces_wireframe ( Array < PointVertex > & 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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
wire . resize ( count ) ;
Array < PointVertex > : : iterator p = wire . begin ( ) ;
for ( std : : size_t i = 0 ; i < m_faceCentroidPoints . size ( ) ; + + i ) {
if ( faces_visible [ i ] ) {
* p + + = m_faceCentroidPoints [ i ] ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Makes this brush a deep-copy of the \p other.
2021-08-04 13:23:18 -07:00
void copy ( const Brush & other )
{
for ( Faces : : const_iterator i = other . m_faces . begin ( ) ; i ! = other . m_faces . end ( ) ; + + i ) {
addFace ( * ( * i ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
planeChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
private :
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void edge_clear ( )
{
m_select_edges . clear ( ) ;
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > edge_clear ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void vertex_clear ( )
{
m_select_vertices . clear ( ) ;
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > vertex_clear ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Returns true if the face identified by \p index is preceded by another plane that takes priority over it.
2021-08-04 13:23:18 -07:00
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 ( ) , index < i ) ) {
return false ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
return true ;
}
2020-11-17 03:16:16 -08:00
/// \brief Removes edges that are smaller than the tolerance used when generating brush windings.
2021-08-04 13:23:18 -07:00
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 ) ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_DEGENERATE_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < i < < " : degenerate edge adjacent to " < < winding [ index ] . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
winding . erase ( j ) ;
} else {
+ + j ;
2020-11-17 03:16:16 -08:00
}
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Invalidates faces that have only two vertices in their winding, while preserving edge-connectivity information.
2021-08-04 13:23:18 -07:00
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 ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( degen . numpoints = = 2 ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_DEGENERATE_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < i < < " : degenerate winding adjacent to " < < degen [ 0 ] . adjacent < < " , " < < degen [ 1 ] . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
// 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 ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_DEGENERATE_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < degen [ 0 ] . adjacent < < " : remapping adjacent " < < winding [ index ] . adjacent < < " to " < < degen [ 1 ] . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
winding [ index ] . adjacent = degen [ 1 ] . adjacent ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
{
Winding & winding = m_faces [ degen [ 1 ] . adjacent ] - > getWinding ( ) ;
std : : size_t index = Winding_FindAdjacent ( winding , i ) ;
if ( index ! = c_brush_maxFaces ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_DEGENERATE_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < degen [ 1 ] . adjacent < < " : remapping adjacent " < < winding [ index ] . adjacent < < " to " < < degen [ 0 ] . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
winding [ index ] . adjacent = degen [ 0 ] . adjacent ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
degen . resize ( 0 ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Removes edges that have the same adjacent-face as their immediate neighbour.
2021-08-04 13:23:18 -07:00
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 ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_DEGENERATE_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < i < < " : removed duplicate edge adjacent to face " < < winding [ j ] . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
winding . erase ( winding . begin ( ) + next ) ;
} else {
+ + j ;
2020-11-17 03:16:16 -08:00
}
}
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \brief Removes edges that do not have a matching pair in their adjacent-face.
2021-08-04 13:23:18 -07:00
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 ( ) ; ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_CONNECTIVITY_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < i < < " : adjacent to face " < < ( * j ) . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
// remove unidirectional graph edges
if ( ( * j ) . adjacent = = c_brush_maxFaces
| | Winding_FindAdjacent ( m_faces [ ( * j ) . adjacent ] - > getWinding ( ) , i ) = = c_brush_maxFaces ) {
2020-11-17 03:16:16 -08:00
# if BRUSH_CONNECTIVITY_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " Brush::buildWindings: face " < < i < < " : removing unidirectional connectivity graph edge adjacent to face " < < ( * j ) . adjacent < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
winding . erase ( j ) ;
} else {
+ + j ;
2020-11-17 03:16:16 -08:00
}
}
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
/// \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.
2021-08-04 13:23:18 -07:00
bool isBounded ( )
{
for ( const_iterator i = begin ( ) ; i ! = end ( ) ; + + i ) {
if ( ! ( * i ) - > is_bounded ( ) ) {
return false ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
return true ;
}
2020-11-17 03:16:16 -08:00
/// \brief Constructs the polygon windings for each face of the brush. Also updates the brush bounding-box and face texture-coordinates.
2021-08-04 13:23:18 -07:00
bool buildWindings ( )
{
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
{
m_aabb_local = AABB ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( std : : size_t i = 0 ; i < m_faces . size ( ) ; + + i ) {
Face & f = * m_faces [ i ] ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( ! plane3_valid ( f . plane3 ( ) ) | | ! plane_unique ( i ) ) {
f . getWinding ( ) . resize ( 0 ) ;
} else {
2020-11-17 03:16:16 -08:00
# if BRUSH_CONNECTIVITY_DEBUG
2021-08-04 13:23:18 -07:00
globalOutputStream ( ) < < " face: " < < i < < " \n " ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
windingForClipPlane ( f . getWinding ( ) , f . plane3 ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
// 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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
// update texture coordinates
f . EmitTextureCoordinates ( ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool degenerate = ! isBounded ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( ! degenerate ) {
// clean up connectivity information.
// these cleanups must be applied in a specific order.
removeDegenerateEdges ( ) ;
removeDegenerateFaces ( ) ;
removeDuplicateEdges ( ) ;
verifyConnectivityGraph ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return degenerate ;
}
2020-11-17 03:16:16 -08:00
/// \brief Constructs the face windings and updates anything that depends on them.
2021-08-04 13:23:18 -07:00
void buildBRep ( ) ;
2020-11-17 03:16:16 -08:00
} ;
class FaceInstance ;
class FaceInstanceSet {
2021-08-04 13:23:18 -07:00
typedef SelectionList < FaceInstance > FaceInstances ;
FaceInstances m_faceInstances ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
void insert ( FaceInstance & faceInstance )
{
m_faceInstances . append ( faceInstance ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void erase ( FaceInstance & faceInstance )
{
m_faceInstances . erase ( faceInstance ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
template < typename Functor >
void foreach ( Functor functor )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
functor ( * ( * i ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool empty ( ) const
{
return m_faceInstances . empty ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceInstance & last ( ) const
{
return m_faceInstances . back ( ) ;
}
2020-11-17 03:16:16 -08:00
} ;
extern FaceInstanceSet g_SelectedFaceInstances ;
typedef std : : list < std : : size_t > 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 < typename Element >
inline Vector3
triangle_cross ( const BasicVector3 < Element > & x , const BasicVector3 < Element > y , const BasicVector3 < Element > & z )
{
return vector3_cross ( y - x , z - x ) ;
}
template < typename Element >
inline bool
triangles_same_winding ( const BasicVector3 < Element > & x1 , const BasicVector3 < Element > y1 , const BasicVector3 < Element > & z1 ,
2021-08-04 13:23:18 -07:00
const BasicVector3 < Element > & x2 , const BasicVector3 < Element > y2 , const BasicVector3 < Element > & z2 )
2020-11-17 03:16:16 -08:00
{
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 {
2021-08-04 13:23:18 -07:00
typedef std : : vector < const RendererLight * > Lights ;
Lights m_lights ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
void addLight ( const RendererLight & light )
{
m_lights . push_back ( & light ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void clear ( )
{
m_lights . clear ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void evaluateLights ( ) const
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void lightsChanged ( ) const
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void forEachLight ( const RendererLightCallback & callback ) const
{
for ( Lights : : const_iterator i = m_lights . begin ( ) ; i ! = m_lights . end ( ) ; + + i ) {
callback ( * ( * i ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
class FaceInstance {
2021-08-04 13:23:18 -07:00
Face * m_face ;
ObservedSelectable m_selectable ;
ObservedSelectable m_selectableVertices ;
ObservedSelectable m_selectableEdges ;
SelectionChangeCallback m_selectionChanged ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
VertexSelection m_vertexSelection ;
VertexSelection m_edgeSelection ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
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 )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceInstance & operator = ( const FaceInstance & other )
{
m_face = other . m_face ;
return * this ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Face & getFace ( )
{
return * m_face ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Face & getFace ( ) const
{
return * m_face ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void selectedChanged ( const Selectable & selectable )
{
if ( selectable . isSelected ( ) ) {
g_SelectedFaceInstances . insert ( * this ) ;
} else {
g_SelectedFaceInstances . erase ( * this ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
m_selectionChanged ( selectable ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef MemberCaller < FaceInstance , void ( const Selectable & ) , & FaceInstance : : selectedChanged > SelectedChangedCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool selectedVertices ( ) const
{
return ! m_vertexSelection . empty ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool selectedEdges ( ) const
{
return ! m_edgeSelection . empty ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isSelected ( ) const
{
return m_selectable . isSelected ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool selectedComponents ( ) const
{
return selectedVertices ( ) | | selectedEdges ( ) | | isSelected ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 " ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
template < typename Functor >
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 ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
template < typename Functor >
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 ) ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
template < typename Functor >
void SelectedFaces_foreach ( Functor functor ) const
{
if ( isSelected ( ) ) {
functor ( centroid ( ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
template < typename Functor >
void SelectedComponents_foreach ( Functor functor ) const
{
SelectedVertices_foreach ( functor ) ;
SelectedEdges_foreach ( functor ) ;
SelectedFaces_foreach ( functor ) ;
}
void iterate_selected ( AABB & aabb ) const
{
SelectedComponents_foreach ( [ & ] ( const Vector3 & point ) {
2020-11-17 03:16:16 -08:00
aabb_extend_by_point_safe ( aabb , point ) ;
} ) ;
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void iterate_selected ( RenderablePointVector & points ) const
{
SelectedComponents_foreach ( [ & ] ( const Vector3 & point ) {
2020-11-17 03:16:16 -08:00
const Colour4b colour_selected ( 0 , 0 , 255 , 255 ) ;
points . push_back ( pointvertex_for_windingpoint ( point , colour_selected ) ) ;
} ) ;
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool intersectVolume ( const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
return m_face - > intersectVolume ( volume , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
m_face - > render ( renderer , localToWorld ) ;
renderer . PopState ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect ( SelectionTest & test , SelectionIntersection & best )
{
if ( ! m_face - > isFiltered ( ) ) {
m_face - > testSelect ( test , best ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) {
2020-11-17 03:16:16 -08:00
SelectionIntersection best ;
2021-08-04 13:23:18 -07:00
m_face - > testSelect_centroid ( test , best ) ;
2020-11-17 03:16:16 -08:00
if ( best . valid ( ) ) {
Selector_add ( selector , m_selectable , best ) ;
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
Selector_add ( selector , m_selectable ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
selectedPlaneCallback ( getFace ( ) . plane3 ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void selectReversedPlane ( Selector & selector , const SelectedPlanes & selectedPlanes )
{
if ( selectedPlanes . contains ( plane3_flipped ( getFace ( ) . plane3 ( ) ) ) ) {
Selector_add ( selector , m_selectable ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void snapto ( float snap )
{
m_face - > snapto ( snap ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void update_move_planepts_vertex ( std : : size_t index )
{
m_face - > update_move_planepts_vertex ( index , m_face - > m_move_planepts ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 " ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const std : : size_t opposite = Winding_Opposite ( m_face - > getWinding ( ) , index , other ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( triangle_reversed ( index , other , opposite ) ) {
std : : swap ( index , other ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 "
2020-11-17 03:16:16 -08:00
) ;
2021-08-04 13:23:18 -07:00
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
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void update_selection_vertex ( )
{
if ( m_vertexSelection . size ( ) = = 0 ) {
m_selectableVertices . setSelected ( false ) ;
} else {
m_selectableVertices . setSelected ( true ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( m_vertexSelection . size ( ) = = 1 ) {
std : : size_t index = Winding_FindAdjacent ( getFace ( ) . getWinding ( ) , * m_vertexSelection . begin ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( index ! = c_brush_maxFaces
& & other ! = c_brush_maxFaces ) {
update_move_planepts_vertex2 ( index , other ) ;
2020-11-17 03:16:16 -08:00
}
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
SceneChangeNotify ( ) ;
update_selection_vertex ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool selected_vertex ( std : : size_t index ) const
{
return VertexSelection_find ( m_vertexSelection , getFace ( ) . getWinding ( ) [ index ] . adjacent ) ! =
m_vertexSelection . end ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void update_selection_edge ( )
{
if ( m_edgeSelection . size ( ) = = 0 ) {
m_selectableEdges . setSelected ( false ) ;
} else {
m_selectableEdges . setSelected ( true ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( m_edgeSelection . size ( ) = = 1 ) {
std : : size_t index = Winding_FindAdjacent ( getFace ( ) . getWinding ( ) , * m_edgeSelection . begin ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( index ! = c_brush_maxFaces ) {
update_move_planepts_edge ( index ) ;
2020-11-17 03:16:16 -08:00
}
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
SceneChangeNotify ( ) ;
update_selection_edge ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool selected_edge ( std : : size_t index ) const
{
return VertexSelection_find ( m_edgeSelection , getFace ( ) . getWinding ( ) [ index ] . adjacent ) ! = m_edgeSelection . end ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
} ;
class BrushClipPlane : public OpenGLRenderable {
2021-08-04 13:23:18 -07:00
Plane3 m_plane ;
Winding m_winding ;
static Shader * m_state ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
static void constructStatic ( )
{
m_state = GlobalShaderCache ( ) . capture ( " $CLIPPER_OVERLAY " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static void destroyStatic ( )
{
GlobalShaderCache ( ) . release ( " $CLIPPER_OVERLAY " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void render ( RenderStateFlags state ) const
{
if ( ( state & RENDER_FILL ) ! = 0 ) {
Winding_Draw ( m_winding , m_plane . normal ( ) , state ) ;
} else {
Winding_DrawWireframe ( m_winding ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
// also draw a line indicating the direction of the cut
Vector3 lineverts [ 2 ] ;
Winding_Centroid ( m_winding , m_plane , lineverts [ 0 ] ) ;
lineverts [ 1 ] = vector3_added ( lineverts [ 0 ] , vector3_scaled ( m_plane . normal ( ) , Brush : : m_maxWorldCoord * 4 ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
glVertexPointer ( 3 , GL_FLOAT , sizeof ( Vector3 ) , & lineverts [ 0 ] ) ;
glDrawArrays ( GL_LINES , 0 , GLsizei ( 2 ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
} ;
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 )
2021-08-04 13:23:18 -07:00
| | ! plane3_test_point ( tmp , vector3_added ( origin , light . offset ( ) ) ) ) {
2020-11-17 03:16:16 -08:00
face . m_lights . addLight ( light ) ;
}
}
typedef std : : vector < FaceInstance > FaceInstances ;
class EdgeInstance : public Selectable {
2021-08-04 13:23:18 -07:00
FaceInstances & m_faceInstances ;
SelectableEdge * m_edge ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool selected_edge ( ) const
{
FaceVertexId faceVertex = m_edge - > m_faceVertex ;
if ( ! m_faceInstances [ faceVertex . getFace ( ) ] . selected_edge ( faceVertex . getVertex ( ) ) ) {
return false ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
faceVertex = next_edge ( m_edge - > m_faces , faceVertex ) ;
if ( ! m_faceInstances [ faceVertex . getFace ( ) ] . selected_edge ( faceVertex . getVertex ( ) ) ) {
return false ;
}
return true ;
}
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
EdgeInstance ( FaceInstances & faceInstances , SelectableEdge & edge )
: m_faceInstances ( faceInstances ) , m_edge ( & edge )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
EdgeInstance & operator = ( const EdgeInstance & other )
{
m_edge = other . m_edge ;
return * this ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setSelected ( bool select )
{
select_edge ( select ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isSelected ( ) const
{
return selected_edge ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect ( Selector & selector , SelectionTest & test )
{
SelectionIntersection best ;
m_edge - > testSelect ( test , best ) ;
if ( best . valid ( ) ) {
Selector_add ( selector , * this , best ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
class VertexInstance : public Selectable {
2021-08-04 13:23:18 -07:00
FaceInstances & m_faceInstances ;
SelectableVertex * m_vertex ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ;
}
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
VertexInstance ( FaceInstances & faceInstances , SelectableVertex & vertex )
: m_faceInstances ( faceInstances ) , m_vertex ( & vertex )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
VertexInstance & operator = ( const VertexInstance & other )
{
m_vertex = other . m_vertex ;
return * this ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setSelected ( bool select )
{
select_vertex ( select ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isSelected ( ) const
{
return selected_vertex ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelect ( Selector & selector , SelectionTest & test )
{
SelectionIntersection best ;
m_vertex - > testSelect ( test , best ) ;
if ( best . valid ( ) ) {
Selector_add ( selector , * this , best ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
class BrushInstanceVisitor {
public :
2021-08-04 13:23:18 -07:00
virtual void visit ( FaceInstance & face ) const = 0 ;
2020-11-17 03:16:16 -08:00
} ;
class BrushInstance :
2021-08-04 13:23:18 -07:00
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 < BrushInstance , Selectable > : : install ( m_casts ) ;
InstanceContainedCast < BrushInstance , Bounded > : : install ( m_casts ) ;
InstanceContainedCast < BrushInstance , Cullable > : : install ( m_casts ) ;
InstanceStaticCast < BrushInstance , Renderable > : : install ( m_casts ) ;
InstanceStaticCast < BrushInstance , SelectionTestable > : : install ( m_casts ) ;
InstanceStaticCast < BrushInstance , ComponentSelectionTestable > : : install ( m_casts ) ;
InstanceStaticCast < BrushInstance , ComponentEditable > : : install ( m_casts ) ;
InstanceStaticCast < BrushInstance , ComponentSnappable > : : install ( m_casts ) ;
InstanceStaticCast < BrushInstance , PlaneSelectable > : : install ( m_casts ) ;
InstanceIdentityCast < BrushInstance > : : install ( m_casts ) ;
InstanceContainedCast < BrushInstance , Transformable > : : install ( m_casts ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
InstanceTypeCastTable & get ( )
{
return m_casts ;
}
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Brush & m_brush ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
FaceInstances m_faceInstances ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef std : : vector < EdgeInstance > EdgeInstances ;
EdgeInstances m_edgeInstances ;
typedef std : : vector < VertexInstance > VertexInstances ;
VertexInstances m_vertexInstances ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
ObservedSelectable m_selectable ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
mutable RenderableWireframe m_render_wireframe ;
mutable RenderablePointVector m_render_selected ;
mutable AABB m_aabb_component ;
mutable Array < PointVertex > m_faceCentroidPointsCulled ;
RenderablePointArray m_render_faces_wireframe ;
mutable bool m_viewChanged ; // requires re-evaluation of view-dependent cached data
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
BrushClipPlane m_clipPlane ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static Shader * m_state_selpoint ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const LightList * m_lightList ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
TransformModifier m_transform ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
BrushInstance ( const BrushInstance & other ) ; // NOT COPYABLE
BrushInstance & operator = ( const BrushInstance & other ) ; // NOT ASSIGNABLE
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
static Counter * m_counter ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef LazyStatic < TypeCasts > StaticTypeCasts ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void lightsChanged ( )
{
m_lightList - > lightsChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef MemberCaller < BrushInstance , void ( ) , & BrushInstance : : lightsChanged > LightsChangedCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
STRING_CONSTANT ( Name , " BrushInstance " ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_lightList = & GlobalShaderCache ( ) . attach ( * this ) ;
m_brush . m_lightsChanged = LightsChangedCaller ( * this ) ; ///\todo Make this work with instancing.
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Instance : : setTransformChangedCallback ( LightsChangedCaller ( * this ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
~ BrushInstance ( )
{
Instance : : setTransformChangedCallback ( Callback < void ( ) > ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_brush . m_lightsChanged = Callback < void ( ) > ( ) ;
GlobalShaderCache ( ) . detach ( * this ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_counter - > decrement ( ) ;
m_brush . detach ( * this ) ;
m_brush . instanceDetach ( Instance : : path ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Brush & getBrush ( )
{
return m_brush ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Brush & getBrush ( ) const
{
return m_brush ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Bounded & get ( NullType < Bounded > )
{
return m_brush ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Cullable & get ( NullType < Cullable > )
{
return m_brush ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Transformable & get ( NullType < Transformable > )
{
return m_transform ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void selectedChanged ( const Selectable & selectable )
{
GlobalSelectionSystem ( ) . getObserver ( SelectionSystem : : ePrimitive ) ( selectable ) ;
GlobalSelectionSystem ( ) . onSelectedChanged ( * this , selectable ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Instance : : selectedChanged ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef MemberCaller < BrushInstance , void (
const Selectable & ) , & BrushInstance : : selectedChanged > SelectedChangedCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void selectedChangedComponent ( const Selectable & selectable )
{
GlobalSelectionSystem ( ) . getObserver ( SelectionSystem : : eComponent ) ( selectable ) ;
GlobalSelectionSystem ( ) . onComponentSelection ( * this , selectable ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef MemberCaller < BrushInstance , void (
const Selectable & ) , & BrushInstance : : selectedChangedComponent > SelectedChangedComponentCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const BrushInstanceVisitor & forEachFaceInstance ( const BrushInstanceVisitor & visitor )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
visitor . visit ( * i ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return visitor ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static void constructStatic ( )
{
m_state_selpoint = GlobalShaderCache ( ) . capture ( " $SELPOINT " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static void destroyStatic ( )
{
GlobalShaderCache ( ) . release ( " $SELPOINT " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void clear ( )
{
m_faceInstances . clear ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void reserve ( std : : size_t size )
{
m_faceInstances . reserve ( size ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void push_back ( Face & face )
{
m_faceInstances . push_back ( FaceInstance ( face , SelectedChangedComponentCaller ( * this ) ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void pop_back ( )
{
ASSERT_MESSAGE ( ! m_faceInstances . empty ( ) , " erasing invalid element " ) ;
m_faceInstances . pop_back ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void erase ( std : : size_t index )
{
ASSERT_MESSAGE ( index < m_faceInstances . size ( ) , " erasing invalid element " ) ;
m_faceInstances . erase ( m_faceInstances . begin ( ) + index ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void connectivityChanged ( )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . connectivityChanged ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void edge_clear ( )
{
m_edgeInstances . clear ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void edge_push_back ( SelectableEdge & edge )
{
m_edgeInstances . push_back ( EdgeInstance ( m_faceInstances , edge ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void vertex_clear ( )
{
m_vertexInstances . clear ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void vertex_push_back ( SelectableVertex & vertex )
{
m_vertexInstances . push_back ( VertexInstance ( m_faceInstances , vertex ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void DEBUG_verify ( ) const
{
ASSERT_MESSAGE ( m_faceInstances . size ( ) = = m_brush . DEBUG_size ( ) , " FATAL: mismatch " ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isSelected ( ) const
{
return m_selectable . isSelected ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setSelected ( bool select )
{
m_selectable . setSelected ( select ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void evaluateViewDependent ( const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
if ( m_viewChanged ) {
m_viewChanged = false ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
m_brush . update_wireframe ( m_render_wireframe , faces_visible ) ;
m_brush . update_faces_wireframe ( m_faceCentroidPointsCulled , faces_visible ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderComponents ( Renderer & renderer , const VolumeTest & volume ) const
{
m_brush . evaluateBRep ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const Matrix4 & localToWorld = Instance : : localToWorld ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderer . SetState ( m_brush . m_state_point , Renderer : : eWireframeOnly ) ;
renderer . SetState ( m_brush . m_state_point , Renderer : : eFullMaterials ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderClipPlane ( Renderer & renderer , const VolumeTest & volume ) const
{
if ( GlobalSelectionSystem ( ) . ManipulatorMode ( ) = = SelectionSystem : : eClip & & isSelected ( ) ) {
m_clipPlane . render ( renderer , volume , localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderCommon ( Renderer & renderer , const VolumeTest & volume ) const
{
bool componentMode = GlobalSelectionSystem ( ) . Mode ( ) = = SelectionSystem : : eComponent ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( componentMode & & isSelected ( ) ) {
renderComponents ( renderer , volume ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( parentSelected ( ) ) {
if ( ! componentMode ) {
renderer . Highlight ( Renderer : : eFace ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
renderer . Highlight ( Renderer : : ePrimitive ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderSolid ( Renderer & renderer , const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
//renderCommon(renderer, volume);
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_lightList - > evaluateLights ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( FaceInstances : : const_iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
renderer . setLights ( ( * i ) . m_lights ) ;
( * i ) . render ( renderer , volume , localToWorld ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
renderComponentsSelected ( renderer , volume , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderWireframe ( Renderer & renderer , const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
//renderCommon(renderer, volume);
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
evaluateViewDependent ( volume , localToWorld ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( m_render_wireframe . m_size ! = 0 ) {
renderer . addRenderable ( m_render_wireframe , localToWorld ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
renderComponentsSelected ( renderer , volume , localToWorld ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderSolid ( Renderer & renderer , const VolumeTest & volume ) const
{
m_brush . evaluateBRep ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderClipPlane ( renderer , volume ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderSolid ( renderer , volume , localToWorld ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderWireframe ( Renderer & renderer , const VolumeTest & volume ) const
{
m_brush . evaluateBRep ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderClipPlane ( renderer , volume ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderWireframe ( renderer , volume , localToWorld ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void viewChanged ( ) const
{
m_viewChanged = true ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
if ( best . valid ( ) ) {
selector . addIntersection ( best ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isSelectedComponents ( ) const
{
for ( FaceInstances : : const_iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
if ( ( * i ) . selectedComponents ( ) ) {
return true ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
return false ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setSelectedComponents ( bool select , SelectionSystem : : EComponentMode mode )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . setSelected ( mode , select ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void testSelectComponents ( Selector & selector , SelectionTest & test , SelectionSystem : : EComponentMode mode )
{
test . BeginMesh ( localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
} else {
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . testSelect_centroid ( selector , test ) ;
2020-11-17 03:16:16 -08:00
}
}
}
2021-08-04 13:23:18 -07:00
break ;
default :
break ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void selectPlanes ( Selector & selector , SelectionTest & test , const PlaneCallback & selectedPlaneCallback )
{
test . BeginMesh ( localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
PlanePointer brushPlanes [ c_brush_maxFaces ] ;
PlanesIterator j = brushPlanes ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( Brush : : const_iterator i = m_brush . begin ( ) ; i ! = m_brush . end ( ) ; + + i ) {
* j + + = & ( * i ) - > plane3 ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . selectPlane ( selector , Line ( test . getNear ( ) , test . getFar ( ) ) , brushPlanes , j , selectedPlaneCallback ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void selectReversedPlanes ( Selector & selector , const SelectedPlanes & selectedPlanes )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . selectReversedPlane ( selector , selectedPlanes ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void transformComponents ( const Matrix4 & matrix )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . transformComponents ( matrix ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
const AABB & getSelectedComponentsBounds ( ) const
{
m_aabb_component = AABB ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
for ( FaceInstances : : const_iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . iterate_selected ( m_aabb_component ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
return m_aabb_component ;
}
void snapComponents ( float snap )
{
for ( FaceInstances : : iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . snapComponents ( snap ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void evaluateTransform ( )
{
Matrix4 matrix ( m_transform . calculateTransform ( ) ) ;
//globalOutputStream() << "matrix: " << matrix << "\n";
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( m_transform . getType ( ) = = TRANSFORM_PRIMITIVE ) {
m_brush . transform ( matrix ) ;
} else {
transformComponents ( matrix ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void applyTransform ( )
{
m_brush . revertTransform ( ) ;
evaluateTransform ( ) ;
m_brush . freezeTransform ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
typedef MemberCaller < BrushInstance , void ( ) , & BrushInstance : : applyTransform > ApplyTransformCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void setClipPlane ( const Plane3 & plane )
{
m_clipPlane . setPlane ( m_brush , plane ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool testLight ( const RendererLight & light ) const
{
return light . testAABB ( worldAABB ( ) ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void clearLights ( )
{
for ( FaceInstances : : const_iterator i = m_faceInstances . begin ( ) ; i ! = m_faceInstances . end ( ) ; + + i ) {
( * i ) . m_lights . clear ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
inline BrushInstance * Instance_getBrush ( scene : : Instance & instance )
{
return InstanceTypeCast < BrushInstance > : : cast ( instance ) ;
}
template < typename Functor >
class BrushSelectedVisitor : public SelectionSystem : : Visitor {
2021-08-04 13:23:18 -07:00
const Functor & m_functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
BrushSelectedVisitor ( const Functor & functor ) : m_functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void visit ( scene : : Instance & instance ) const
{
BrushInstance * brush = Instance_getBrush ( instance ) ;
if ( brush ! = 0 ) {
m_functor ( * brush ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Scene_forEachSelectedBrush ( const Functor & functor )
{
GlobalSelectionSystem ( ) . foreachSelected ( BrushSelectedVisitor < Functor > ( functor ) ) ;
return functor ;
}
template < typename Functor >
class BrushVisibleSelectedVisitor : public SelectionSystem : : Visitor {
2021-08-04 13:23:18 -07:00
const Functor & m_functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
BrushVisibleSelectedVisitor ( const Functor & functor ) : m_functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void visit ( scene : : Instance & instance ) const
{
BrushInstance * brush = Instance_getBrush ( instance ) ;
if ( brush ! = 0
& & instance . path ( ) . top ( ) . get ( ) . visible ( ) ) {
m_functor ( * brush ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Scene_forEachVisibleSelectedBrush ( const Functor & functor )
{
GlobalSelectionSystem ( ) . foreachSelected ( BrushVisibleSelectedVisitor < Functor > ( functor ) ) ;
return functor ;
}
class BrushForEachFace {
2021-08-04 13:23:18 -07:00
const BrushInstanceVisitor & m_visitor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
BrushForEachFace ( const BrushInstanceVisitor & visitor ) : m_visitor ( visitor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void operator ( ) ( BrushInstance & brush ) const
{
brush . forEachFaceInstance ( m_visitor ) ;
}
2020-11-17 03:16:16 -08:00
} ;
template < class Functor >
class FaceInstanceVisitFace : public BrushInstanceVisitor {
2021-08-04 13:23:18 -07:00
const Functor & functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
FaceInstanceVisitFace ( const Functor & functor )
: functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void visit ( FaceInstance & face ) const
{
functor ( face . getFace ( ) ) ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Brush_forEachFace ( BrushInstance & brush , const Functor & functor )
{
brush . forEachFaceInstance ( FaceInstanceVisitFace < Functor > ( functor ) ) ;
return functor ;
}
template < class Functor >
class FaceVisitAll : public BrushVisitor {
2021-08-04 13:23:18 -07:00
const Functor & functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
FaceVisitAll ( const Functor & functor )
: functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void visit ( Face & face ) const
{
functor ( face ) ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Brush_forEachFace ( const Brush & brush , const Functor & functor )
{
brush . forEachFace ( FaceVisitAll < Functor > ( functor ) ) ;
return functor ;
}
template < typename Functor >
inline const Functor & Brush_forEachFace ( Brush & brush , const Functor & functor )
{
brush . forEachFace ( FaceVisitAll < Functor > ( functor ) ) ;
return functor ;
}
template < class Functor >
class FaceInstanceVisitAll : public BrushInstanceVisitor {
2021-08-04 13:23:18 -07:00
const Functor & functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
FaceInstanceVisitAll ( const Functor & functor )
: functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void visit ( FaceInstance & face ) const
{
functor ( face ) ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Brush_ForEachFaceInstance ( BrushInstance & brush , const Functor & functor )
{
brush . forEachFaceInstance ( FaceInstanceVisitAll < Functor > ( functor ) ) ;
return functor ;
}
template < typename Functor >
inline const Functor & Scene_forEachBrush ( scene : : Graph & graph , const Functor & functor )
{
graph . traverse ( InstanceWalker < InstanceApply < BrushInstance , Functor > > ( functor ) ) ;
return functor ;
}
template < typename Type , typename Functor >
class InstanceIfVisible : public Functor {
public :
2021-08-04 13:23:18 -07:00
InstanceIfVisible ( const Functor & functor ) : Functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void operator ( ) ( scene : : Instance & instance )
{
if ( instance . path ( ) . top ( ) . get ( ) . visible ( ) ) {
Functor : : operator ( ) ( instance ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
class BrushVisibleWalker : public scene : : Graph : : Walker {
2021-08-04 13:23:18 -07:00
const Functor & m_functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
BrushVisibleWalker ( const Functor & functor ) : m_functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
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 ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
return true ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Scene_forEachVisibleBrush ( scene : : Graph & graph , const Functor & functor )
{
graph . traverse ( BrushVisibleWalker < Functor > ( functor ) ) ;
return functor ;
}
template < typename Functor >
inline const Functor & Scene_ForEachBrush_ForEachFace ( scene : : Graph & graph , const Functor & functor )
{
Scene_forEachBrush ( graph , BrushForEachFace ( FaceInstanceVisitFace < Functor > ( functor ) ) ) ;
return functor ;
}
// d1223m
template < typename Functor >
inline const Functor & Scene_ForEachBrush_ForEachFaceInstance ( scene : : Graph & graph , const Functor & functor )
{
Scene_forEachBrush ( graph , BrushForEachFace ( FaceInstanceVisitAll < Functor > ( functor ) ) ) ;
return functor ;
}
template < typename Functor >
inline const Functor & Scene_ForEachSelectedBrush_ForEachFace ( scene : : Graph & graph , const Functor & functor )
{
Scene_forEachSelectedBrush ( BrushForEachFace ( FaceInstanceVisitFace < Functor > ( functor ) ) ) ;
return functor ;
}
template < typename Functor >
inline const Functor & Scene_ForEachSelectedBrush_ForEachFaceInstance ( scene : : Graph & graph , const Functor & functor )
{
Scene_forEachSelectedBrush ( BrushForEachFace ( FaceInstanceVisitAll < Functor > ( functor ) ) ) ;
return functor ;
}
template < typename Functor >
class FaceVisitorWrapper {
2021-08-04 13:23:18 -07:00
const Functor & functor ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
FaceVisitorWrapper ( const Functor & functor ) : functor ( functor )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void operator ( ) ( FaceInstance & faceInstance ) const
{
functor ( faceInstance . getFace ( ) ) ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline const Functor & Scene_ForEachSelectedBrushFace ( scene : : Graph & graph , const Functor & functor )
{
g_SelectedFaceInstances . foreach ( FaceVisitorWrapper < Functor > ( functor ) ) ;
return functor ;
}
# endif