2020-11-17 03:16:16 -08:00
/*
Copyright ( C ) 2001 - 2006 , William Joseph .
All Rights Reserved .
This file is part of GtkRadiant .
GtkRadiant is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
GtkRadiant is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with GtkRadiant ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# if !defined( INCLUDED_PATCH_H )
# define INCLUDED_PATCH_H
/// \file
/// \brief The patch primitive.
///
/// A 2-dimensional matrix of vertices that define a quadratic bezier surface.
/// The Boundary-Representation of this primitive is a triangle mesh.
/// The surface is recursively tesselated until the angle between each triangle
/// edge is smaller than a specified tolerance.
# include "globaldefs.h"
# include "nameable.h"
# include "ifilter.h"
# include "imap.h"
# include "ipatch.h"
# include "cullable.h"
# include "renderable.h"
# include "editable.h"
# include "selectable.h"
# include "debugging/debugging.h"
# include <set>
# include <limits>
# include "math/frustum.h"
# include "string/string.h"
# include "stream/stringstream.h"
# include "stream/textstream.h"
# include "xml/xmlelement.h"
# include "scenelib.h"
# include "transformlib.h"
# include "instancelib.h"
# include "selectionlib.h"
# include "traverselib.h"
# include "render.h"
# include "stringio.h"
# include "shaderlib.h"
# include "generic/callback.h"
# include "signal/signalfwd.h"
# include "texturelib.h"
# include "xml/ixml.h"
# include "dragplanes.h"
enum EPatchType {
2021-08-04 13:23:18 -07:00
ePatchTypeQuake3 ,
ePatchTypeDoom3 ,
2020-11-17 03:16:16 -08:00
} ;
extern int g_PatchSubdivideThreshold ;
# define MIN_PATCH_WIDTH 3
# define MIN_PATCH_HEIGHT 3
extern std : : size_t MAX_PATCH_WIDTH ;
extern std : : size_t MAX_PATCH_HEIGHT ;
# define MAX_PATCH_ROWCTRL ( ( ( MAX_PATCH_WIDTH - 1 ) - 1 ) / 2 )
# define MAX_PATCH_COLCTRL ( ( ( MAX_PATCH_HEIGHT - 1 ) - 1 ) / 2 )
enum EPatchCap {
2021-08-04 13:23:18 -07:00
eCapBevel ,
eCapEndCap ,
eCapIBevel ,
eCapIEndCap ,
eCapCylinder ,
2020-11-17 03:16:16 -08:00
} ;
enum EPatchPrefab {
2021-08-04 13:23:18 -07:00
ePlane ,
eBevel ,
eEndCap ,
eCylinder ,
eDenseCylinder ,
eVeryDenseCylinder ,
eSqCylinder ,
eCone ,
eSphere ,
eXactCylinder ,
eXactSphere ,
eXactCone ,
2020-11-17 03:16:16 -08:00
} ;
enum EMatrixMajor {
2021-08-04 13:23:18 -07:00
ROW , COL ,
2020-11-17 03:16:16 -08:00
} ;
struct BezierCurve {
2021-08-04 13:23:18 -07:00
Vector3 crd ;
Vector3 left ;
Vector3 right ;
2020-11-17 03:16:16 -08:00
} ;
const std : : size_t BEZIERCURVETREE_MAX_INDEX = std : : size_t ( 1 ) < < ( std : : numeric_limits < std : : size_t > : : digits - 1 ) ;
struct BezierCurveTree {
2021-08-04 13:23:18 -07:00
std : : size_t index ;
BezierCurveTree * left ;
BezierCurveTree * right ;
2020-11-17 03:16:16 -08:00
} ;
inline bool BezierCurveTree_isLeaf ( const BezierCurveTree * node )
{
2021-08-04 13:23:18 -07:00
return node - > left = = 0 & & node - > right = = 0 ;
2020-11-17 03:16:16 -08:00
}
void BezierCurveTree_Delete ( BezierCurveTree * pCurve ) ;
inline VertexPointer vertexpointer_arbitrarymeshvertex ( const ArbitraryMeshVertex * array )
{
2021-08-04 13:23:18 -07:00
return VertexPointer ( VertexPointer : : pointer ( & array - > vertex ) , sizeof ( ArbitraryMeshVertex ) ) ;
2020-11-17 03:16:16 -08:00
}
typedef PatchControl * PatchControlIter ;
typedef const PatchControl * PatchControlConstIter ;
inline void copy_ctrl ( PatchControlIter ctrl , PatchControlConstIter begin , PatchControlConstIter end )
{
2021-08-04 13:23:18 -07:00
std : : copy ( begin , end , ctrl ) ;
2020-11-17 03:16:16 -08:00
}
const Colour4b colour_corner ( 0 , 255 , 0 , 255 ) ;
const Colour4b colour_inside ( 255 , 0 , 255 , 255 ) ;
class Patch ;
class PatchFilter {
public :
2021-08-04 13:23:18 -07:00
virtual bool filter ( const Patch & patch ) const = 0 ;
2020-11-17 03:16:16 -08:00
} ;
bool patch_filtered ( Patch & patch ) ;
void add_patch_filter ( PatchFilter & filter , int mask , bool invert = false ) ;
void Patch_addTextureChangedCallback ( const SignalHandler & handler ) ;
void Patch_textureChanged ( ) ;
inline void BezierCurveTreeArray_deleteAll ( Array < BezierCurveTree * > & curveTrees )
{
2021-08-04 13:23:18 -07:00
for ( Array < BezierCurveTree * > : : iterator i = curveTrees . begin ( ) ; i ! = curveTrees . end ( ) ; + + i ) {
BezierCurveTree_Delete ( * i ) ;
}
2020-11-17 03:16:16 -08:00
}
inline void PatchControlArray_invert ( Array < PatchControl > & ctrl , std : : size_t width , std : : size_t height )
{
2021-08-04 13:23:18 -07:00
Array < PatchControl > tmp ( width ) ;
PatchControlIter from = ctrl . data ( ) + ( width * ( height - 1 ) ) ;
PatchControlIter to = ctrl . data ( ) ;
for ( std : : size_t h = 0 ; h ! = ( ( height - 1 ) > > 1 ) ; + + h , to + = width , from - = width ) {
copy_ctrl ( tmp . data ( ) , to , to + width ) ;
copy_ctrl ( to , from , from + width ) ;
copy_ctrl ( from , tmp . data ( ) , tmp . data ( ) + width ) ;
}
2020-11-17 03:16:16 -08:00
}
class PatchTesselation {
public :
2021-08-04 13:23:18 -07:00
PatchTesselation ( )
: m_numStrips ( 0 ) , m_lenStrips ( 0 ) , m_nArrayWidth ( 0 ) , m_nArrayHeight ( 0 )
{
}
Array < ArbitraryMeshVertex > m_vertices ;
Array < RenderIndex > m_indices ;
std : : size_t m_numStrips ;
std : : size_t m_lenStrips ;
Array < std : : size_t > m_arrayWidth ;
std : : size_t m_nArrayWidth ;
Array < std : : size_t > m_arrayHeight ;
std : : size_t m_nArrayHeight ;
Array < BezierCurveTree * > m_curveTreeU ;
Array < BezierCurveTree * > m_curveTreeV ;
2020-11-17 03:16:16 -08:00
} ;
class RenderablePatchWireframe : public OpenGLRenderable {
2021-08-04 13:23:18 -07:00
PatchTesselation & m_tess ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
RenderablePatchWireframe ( PatchTesselation & tess ) : m_tess ( tess )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void render ( RenderStateFlags state ) const
{
{
2020-11-17 03:16:16 -08:00
# if NV_DRIVER_BUG
2021-08-04 13:23:18 -07:00
glVertexPointer ( 3 , GL_FLOAT , 0 , 0 ) ;
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 0 ) ;
2020-11-17 03:16:16 -08:00
# endif
2021-08-04 13:23:18 -07:00
std : : size_t n = 0 ;
glVertexPointer ( 3 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > vertex ) ;
for ( std : : size_t i = 0 ; i < = m_tess . m_curveTreeV . size ( ) ; + + i ) {
glDrawArrays ( GL_LINE_STRIP , GLint ( n ) , GLsizei ( m_tess . m_nArrayWidth ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( i = = m_tess . m_curveTreeV . size ( ) ) {
break ;
}
if ( ! BezierCurveTree_isLeaf ( m_tess . m_curveTreeV [ i ] ) ) {
glDrawArrays ( GL_LINE_STRIP , GLint ( m_tess . m_curveTreeV [ i ] - > index ) , GLsizei ( m_tess . m_nArrayWidth ) ) ;
}
n + = ( m_tess . m_arrayHeight [ i ] * m_tess . m_nArrayWidth ) ;
}
2020-11-17 03:16:16 -08:00
}
{
2021-08-04 13:23:18 -07:00
const ArbitraryMeshVertex * p = m_tess . m_vertices . data ( ) ;
std : : size_t n = m_tess . m_nArrayWidth * sizeof ( ArbitraryMeshVertex ) ;
for ( std : : size_t i = 0 ; i < = m_tess . m_curveTreeU . size ( ) ; + + i ) {
glVertexPointer ( 3 , GL_FLOAT , GLsizei ( n ) , & p - > vertex ) ;
glDrawArrays ( GL_LINE_STRIP , 0 , GLsizei ( m_tess . m_nArrayHeight ) ) ;
if ( i = = m_tess . m_curveTreeU . size ( ) ) {
break ;
}
if ( ! BezierCurveTree_isLeaf ( m_tess . m_curveTreeU [ i ] ) ) {
glVertexPointer ( 3 , GL_FLOAT , GLsizei ( n ) ,
& ( m_tess . m_vertices . data ( ) + ( m_tess . m_curveTreeU [ i ] - > index ) ) - > vertex ) ;
glDrawArrays ( GL_LINE_STRIP , 0 , GLsizei ( m_tess . m_nArrayHeight ) ) ;
}
p + = m_tess . m_arrayWidth [ i ] ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
}
} ;
class RenderablePatchFixedWireframe : public OpenGLRenderable {
PatchTesselation & m_tess ;
public :
RenderablePatchFixedWireframe ( PatchTesselation & tess ) : m_tess ( tess )
{
}
void render ( RenderStateFlags state ) const
{
glVertexPointer ( 3 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > vertex ) ;
const RenderIndex * strip_indices = m_tess . m_indices . data ( ) ;
for ( std : : size_t i = 0 ; i < m_tess . m_numStrips ; i + + , strip_indices + = m_tess . m_lenStrips ) {
glDrawElements ( GL_QUAD_STRIP , GLsizei ( m_tess . m_lenStrips ) , RenderIndexTypeID , strip_indices ) ;
}
}
2020-11-17 03:16:16 -08:00
} ;
class RenderablePatchFixedSolid : public OpenGLRenderable {
2021-08-04 13:23:18 -07:00
PatchTesselation & m_tess ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
RenderablePatchFixedSolid ( PatchTesselation & tess ) : m_tess ( tess )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void RenderNormals ( ) const ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void render ( RenderStateFlags state ) const
{
glNormalPointer ( GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > normal ) ;
glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > texcoord ) ;
glShadeModel ( GL_SMOOTH ) ;
glColorPointer ( 4 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > colour ) ;
glVertexPointer ( 3 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > vertex ) ;
const RenderIndex * strip_indices = m_tess . m_indices . data ( ) ;
for ( std : : size_t i = 0 ; i < m_tess . m_numStrips ; i + + , strip_indices + = m_tess . m_lenStrips ) {
glDrawElements ( GL_QUAD_STRIP , GLsizei ( m_tess . m_lenStrips ) , RenderIndexTypeID , strip_indices ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
glShadeModel ( GL_FLAT ) ;
RenderNormals ( ) ;
}
2020-11-17 03:16:16 -08:00
} ;
class RenderablePatchSolid : public OpenGLRenderable {
2021-08-04 13:23:18 -07:00
PatchTesselation & m_tess ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
RenderablePatchSolid ( PatchTesselation & tess ) : m_tess ( tess )
{
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void RenderNormals ( ) const ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void render ( RenderStateFlags state ) const
{
glNormalPointer ( GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > normal ) ;
glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > texcoord ) ;
glShadeModel ( GL_SMOOTH ) ;
glColorPointer ( 4 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > colour ) ;
glVertexPointer ( 3 , GL_FLOAT , sizeof ( ArbitraryMeshVertex ) , & m_tess . m_vertices . data ( ) - > vertex ) ;
const RenderIndex * strip_indices = m_tess . m_indices . data ( ) ;
for ( std : : size_t i = 0 ; i < m_tess . m_numStrips ; i + + , strip_indices + = m_tess . m_lenStrips ) {
glDrawElements ( GL_QUAD_STRIP , GLsizei ( m_tess . m_lenStrips ) , RenderIndexTypeID , strip_indices ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
glShadeModel ( GL_FLAT ) ;
}
2020-11-17 03:16:16 -08:00
} ;
// parametric surface defined by quadratic bezier control curves
class Patch :
2021-08-04 13:23:18 -07:00
public XMLImporter ,
public XMLExporter ,
public TransformNode ,
public Bounded ,
public Cullable ,
public Snappable ,
public Undoable ,
public Filterable ,
public Nameable {
class xml_state_t {
public :
enum EState {
eDefault ,
ePatch ,
eMatrix ,
eShader ,
} ;
xml_state_t ( EState state )
: m_state ( state )
{
}
EState state ( ) const
{
return m_state ;
}
const char * content ( ) const
{
return m_content . c_str ( ) ;
}
std : : size_t write ( const char * buffer , std : : size_t length )
{
return m_content . write ( buffer , length ) ;
}
private :
EState m_state ;
StringOutputStream m_content ;
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : vector < xml_state_t > m_xml_state ;
typedef Array < PatchControl > PatchControlArray ;
class SavedState : public UndoMemento {
public :
SavedState (
std : : size_t width ,
std : : size_t height ,
const PatchControlArray & ctrl ,
const char * shader ,
bool patchDef3 ,
bool patchDefWS ,
std : : size_t subdivisions_x ,
std : : size_t subdivisions_y
) :
m_width ( width ) ,
m_height ( height ) ,
m_shader ( shader ) ,
m_ctrl ( ctrl ) ,
m_patchDef3 ( patchDef3 ) ,
m_patchDefWS ( patchDefWS ) ,
m_subdivisions_x ( subdivisions_x ) ,
m_subdivisions_y ( subdivisions_y )
{
}
void release ( )
{
delete this ;
}
std : : size_t m_width , m_height ;
CopiedString m_shader ;
PatchControlArray m_ctrl ;
bool m_patchDef3 ;
bool m_patchDefWS ;
std : : size_t m_subdivisions_x ;
std : : size_t m_subdivisions_y ;
} ;
public :
class Observer {
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
virtual void allocate ( std : : size_t size ) = 0 ;
} ;
2020-11-17 03:16:16 -08:00
private :
2021-08-04 13:23:18 -07:00
typedef UniqueSet < Observer * > Observers ;
Observers m_observers ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
scene : : Node * m_node ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
AABB m_aabb_local ; // local bbox
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
CopiedString m_shader ;
Shader * m_state ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
std : : size_t m_width ;
std : : size_t m_height ;
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
bool m_patchDef3 ;
bool m_patchDefWS ;
std : : size_t m_subdivisions_x ;
std : : size_t m_subdivisions_y ;
PatchTesselation m_tess ;
2020-11-17 03:16:16 -08:00
private :
2021-08-04 13:23:18 -07:00
UndoObserver * m_undoable_observer ;
MapFile * m_map ;
2020-11-17 03:16:16 -08:00
// dynamically allocated array of control points, size is m_width*m_height
2021-08-04 13:23:18 -07:00
PatchControlArray m_ctrl ;
PatchControlArray m_ctrlTransformed ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
RenderablePatchSolid m_render_solid ;
RenderablePatchFixedSolid m_render_solid_fixed ;
RenderablePatchWireframe m_render_wireframe ;
RenderablePatchFixedWireframe m_render_wireframe_fixed ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
static Shader * m_state_ctrl ;
static Shader * m_state_lattice ;
VertexBuffer < PointVertex > m_ctrl_vertices ;
RenderableVertexBuffer m_render_ctrl ;
IndexBuffer m_lattice_indices ;
RenderableIndexBuffer m_render_lattice ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool m_bOverlay ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool m_transformChanged ;
Callback < void ( ) > m_evaluateTransform ;
Callback < void ( ) > m_boundsChanged ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void construct ( )
{
m_bOverlay = false ;
m_width = m_height = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_patchDef3 = false ;
m_patchDefWS = false ;
m_subdivisions_x = 0 ;
m_subdivisions_y = 0 ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
check_shader ( ) ;
captureShader ( ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_xml_state . push_back ( xml_state_t : : eDefault ) ;
}
2020-11-17 03:16:16 -08:00
public :
2021-08-04 13:23:18 -07:00
Callback < void ( ) > m_lightsChanged ;
static int m_CycleCapIndex ; // = 0;
static EPatchType m_type ;
STRING_CONSTANT ( Name , " Patch " ) ;
Patch ( scene : : Node & node , const Callback < void ( ) > & evaluateTransform , const Callback < void ( ) > & boundsChanged ) :
m_node ( & node ) ,
m_shader ( texdef_name_default ( ) ) ,
m_state ( 0 ) ,
m_undoable_observer ( 0 ) ,
m_map ( 0 ) ,
m_render_solid ( m_tess ) ,
m_render_solid_fixed ( m_tess ) ,
m_render_wireframe ( m_tess ) ,
m_render_wireframe_fixed ( m_tess ) ,
m_render_ctrl ( GL_POINTS , m_ctrl_vertices ) ,
m_render_lattice ( GL_LINES , m_lattice_indices , m_ctrl_vertices ) ,
m_transformChanged ( false ) ,
m_evaluateTransform ( evaluateTransform ) ,
m_boundsChanged ( boundsChanged )
{
construct ( ) ;
}
Patch ( const Patch & other , scene : : Node & node , const Callback < void ( ) > & evaluateTransform ,
const Callback < void ( ) > & boundsChanged ) :
m_node ( & node ) ,
m_shader ( texdef_name_default ( ) ) ,
m_state ( 0 ) ,
m_undoable_observer ( 0 ) ,
m_map ( 0 ) ,
m_render_solid ( m_tess ) ,
m_render_solid_fixed ( m_tess ) ,
m_render_wireframe ( m_tess ) ,
m_render_wireframe_fixed ( m_tess ) ,
m_render_ctrl ( GL_POINTS , m_ctrl_vertices ) ,
m_render_lattice ( GL_LINES , m_lattice_indices , m_ctrl_vertices ) ,
m_transformChanged ( false ) ,
m_evaluateTransform ( evaluateTransform ) ,
m_boundsChanged ( boundsChanged )
{
construct ( ) ;
m_patchDef3 = other . m_patchDef3 ;
m_patchDefWS = other . m_patchDefWS ;
m_subdivisions_x = other . m_subdivisions_x ;
m_subdivisions_y = other . m_subdivisions_y ;
setDims ( other . m_width , other . m_height ) ;
copy_ctrl ( m_ctrl . data ( ) , other . m_ctrl . data ( ) , other . m_ctrl . data ( ) + ( m_width * m_height ) ) ;
SetShader ( other . m_shader . c_str ( ) ) ;
controlPointsChanged ( ) ;
}
Patch ( const Patch & other ) :
XMLImporter ( other ) ,
XMLExporter ( other ) ,
TransformNode ( other ) ,
Bounded ( other ) ,
Cullable ( other ) ,
Snappable ( ) ,
Undoable ( other ) ,
Filterable ( other ) ,
Nameable ( other ) ,
m_state ( 0 ) ,
m_undoable_observer ( 0 ) ,
m_map ( 0 ) ,
m_render_solid ( m_tess ) ,
m_render_solid_fixed ( m_tess ) ,
m_render_wireframe ( m_tess ) ,
m_render_wireframe_fixed ( m_tess ) ,
m_render_ctrl ( GL_POINTS , m_ctrl_vertices ) ,
m_render_lattice ( GL_LINES , m_lattice_indices , m_ctrl_vertices ) ,
m_transformChanged ( false ) ,
m_evaluateTransform ( other . m_evaluateTransform ) ,
m_boundsChanged ( other . m_boundsChanged )
{
m_bOverlay = false ;
m_patchDef3 = other . m_patchDef3 ;
m_patchDefWS = other . m_patchDefWS ;
m_subdivisions_x = other . m_subdivisions_x ;
m_subdivisions_y = other . m_subdivisions_y ;
setDims ( other . m_width , other . m_height ) ;
copy_ctrl ( m_ctrl . data ( ) , other . m_ctrl . data ( ) , other . m_ctrl . data ( ) + ( m_width * m_height ) ) ;
SetShader ( other . m_shader . c_str ( ) ) ;
controlPointsChanged ( ) ;
}
~ Patch ( )
{
BezierCurveTreeArray_deleteAll ( m_tess . m_curveTreeU ) ;
BezierCurveTreeArray_deleteAll ( m_tess . m_curveTreeV ) ;
releaseShader ( ) ;
ASSERT_MESSAGE ( m_observers . empty ( ) , " Patch::~Patch: observers still attached " ) ;
}
InstanceCounter m_instanceCounter ;
void instanceAttach ( const scene : : Path & path )
{
if ( + + m_instanceCounter . m_count = = 1 ) {
m_state - > incrementUsed ( ) ;
m_map = path_find_mapfile ( path . begin ( ) , path . end ( ) ) ;
m_undoable_observer = GlobalUndoSystem ( ) . observer ( this ) ;
GlobalFilterSystem ( ) . registerFilterable ( * this ) ;
} else {
ASSERT_MESSAGE ( path_find_mapfile ( path . begin ( ) , path . end ( ) ) = = m_map ,
" node is instanced across more than one file " ) ;
}
}
void instanceDetach ( const scene : : Path & path )
{
if ( - - m_instanceCounter . m_count = = 0 ) {
m_map = 0 ;
m_undoable_observer = 0 ;
GlobalUndoSystem ( ) . release ( this ) ;
GlobalFilterSystem ( ) . unregisterFilterable ( * this ) ;
m_state - > decrementUsed ( ) ;
}
}
const char * name ( ) const
{
return " patch " ;
}
void attach ( const NameCallback & callback )
{
}
void detach ( const NameCallback & callback )
{
}
void attach ( Observer * observer )
{
observer - > allocate ( m_width * m_height ) ;
m_observers . insert ( observer ) ;
}
void detach ( Observer * observer )
{
m_observers . erase ( observer ) ;
}
void updateFiltered ( )
{
if ( m_node ! = 0 ) {
if ( patch_filtered ( * this ) ) {
m_node - > enable ( scene : : Node : : eFiltered ) ;
} else {
m_node - > disable ( scene : : Node : : eFiltered ) ;
}
}
}
void onAllocate ( std : : size_t size )
{
for ( Observers : : iterator i = m_observers . begin ( ) ; i ! = m_observers . end ( ) ; + + i ) {
( * i ) - > allocate ( size ) ;
}
}
const Matrix4 & localToParent ( ) const
{
return g_matrix4_identity ;
}
const AABB & localAABB ( ) const
{
return m_aabb_local ;
}
VolumeIntersectionValue intersectVolume ( const VolumeTest & test , const Matrix4 & localToWorld ) const
{
return test . TestAABB ( m_aabb_local , localToWorld ) ;
}
void render_solid ( Renderer & renderer , const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
renderer . SetState ( m_state , Renderer : : eFullMaterials ) ;
if ( m_patchDef3 ) {
2020-11-17 03:16:16 -08:00
renderer . addRenderable ( m_render_solid_fixed , localToWorld ) ;
} else {
renderer . addRenderable ( m_render_solid , localToWorld ) ;
}
2021-08-04 13:23:18 -07:00
}
void render_wireframe ( Renderer & renderer , const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
renderer . SetState ( m_state , Renderer : : eFullMaterials ) ;
if ( m_patchDef3 ) {
renderer . addRenderable ( m_render_wireframe_fixed , localToWorld ) ;
} else {
renderer . addRenderable ( m_render_wireframe , localToWorld ) ;
}
}
void render_component ( Renderer & renderer , const VolumeTest & volume , const Matrix4 & localToWorld ) const
{
renderer . SetState ( m_state_lattice , Renderer : : eWireframeOnly ) ;
renderer . SetState ( m_state_lattice , Renderer : : eFullMaterials ) ;
renderer . addRenderable ( m_render_lattice , localToWorld ) ;
renderer . SetState ( m_state_ctrl , Renderer : : eWireframeOnly ) ;
renderer . SetState ( m_state_ctrl , Renderer : : eFullMaterials ) ;
renderer . addRenderable ( m_render_ctrl , localToWorld ) ;
}
void testSelect ( Selector & selector , SelectionTest & test )
{
SelectionIntersection best ;
IndexPointer : : index_type * pIndex = m_tess . m_indices . data ( ) ;
for ( std : : size_t s = 0 ; s < m_tess . m_numStrips ; s + + ) {
test . TestQuadStrip ( vertexpointer_arbitrarymeshvertex ( m_tess . m_vertices . data ( ) ) ,
IndexPointer ( pIndex , m_tess . m_lenStrips ) , best ) ;
pIndex + = m_tess . m_lenStrips ;
}
if ( best . valid ( ) ) {
selector . addIntersection ( best ) ;
}
}
void transform ( const Matrix4 & matrix )
{
for ( PatchControlIter i = m_ctrlTransformed . data ( ) ;
i ! = m_ctrlTransformed . data ( ) + m_ctrlTransformed . size ( ) ; + + i ) {
matrix4_transform_point ( matrix , ( * i ) . m_vertex ) ;
}
if ( matrix4_handedness ( matrix ) = = MATRIX4_LEFTHANDED ) {
PatchControlArray_invert ( m_ctrlTransformed , m_width , m_height ) ;
}
UpdateCachedData ( ) ;
}
void transformChanged ( )
{
m_transformChanged = true ;
m_lightsChanged ( ) ;
SceneChangeNotify ( ) ;
}
typedef MemberCaller < Patch , void ( ) , & Patch : : transformChanged > TransformChangedCaller ;
void evaluateTransform ( )
{
if ( m_transformChanged ) {
m_transformChanged = false ;
revertTransform ( ) ;
m_evaluateTransform ( ) ;
}
}
void revertTransform ( )
{
m_ctrlTransformed = m_ctrl ;
}
void freezeTransform ( )
{
undoSave ( ) ;
evaluateTransform ( ) ;
ASSERT_MESSAGE ( m_ctrlTransformed . size ( ) = = m_ctrl . size ( ) , " Patch::freeze: size mismatch " ) ;
std : : copy ( m_ctrlTransformed . begin ( ) , m_ctrlTransformed . end ( ) , m_ctrl . begin ( ) ) ;
}
void controlPointsChanged ( )
{
transformChanged ( ) ;
evaluateTransform ( ) ;
UpdateCachedData ( ) ;
}
bool isValid ( ) const ;
void snapto ( float snap )
{
undoSave ( ) ;
for ( PatchControlIter i = m_ctrl . data ( ) ; i ! = m_ctrl . data ( ) + m_ctrl . size ( ) ; + + i ) {
vector3_snap ( ( * i ) . m_vertex , snap ) ;
}
controlPointsChanged ( ) ;
}
void RenderDebug ( RenderStateFlags state ) const ;
void RenderNormals ( RenderStateFlags state ) const ;
void pushElement ( const XMLElement & element )
{
switch ( m_xml_state . back ( ) . state ( ) ) {
case xml_state_t : : eDefault :
ASSERT_MESSAGE ( string_equal ( element . name ( ) , " patch " ) , " parse error " ) ;
m_xml_state . push_back ( xml_state_t : : ePatch ) ;
break ;
case xml_state_t : : ePatch :
if ( string_equal ( element . name ( ) , " matrix " ) ) {
setDims ( atoi ( element . attribute ( " width " ) ) , atoi ( element . attribute ( " height " ) ) ) ;
m_xml_state . push_back ( xml_state_t : : eMatrix ) ;
} else if ( string_equal ( element . name ( ) , " shader " ) ) {
m_xml_state . push_back ( xml_state_t : : eShader ) ;
}
break ;
default :
ERROR_MESSAGE ( " parse error " ) ;
}
}
void popElement ( const char * name )
{
switch ( m_xml_state . back ( ) . state ( ) ) {
case xml_state_t : : eDefault :
ERROR_MESSAGE ( " parse error " ) ;
break ;
case xml_state_t : : ePatch :
break ;
case xml_state_t : : eMatrix : {
StringTokeniser content ( m_xml_state . back ( ) . content ( ) ) ;
for ( PatchControlIter i = m_ctrl . data ( ) , end = m_ctrl . data ( ) + m_ctrl . size ( ) ; i ! = end ; + + i ) {
( * i ) . m_vertex [ 0 ] = string_read_float ( content . getToken ( ) ) ;
( * i ) . m_vertex [ 1 ] = string_read_float ( content . getToken ( ) ) ;
( * i ) . m_vertex [ 2 ] = string_read_float ( content . getToken ( ) ) ;
( * i ) . m_texcoord [ 0 ] = string_read_float ( content . getToken ( ) ) ;
( * i ) . m_texcoord [ 1 ] = string_read_float ( content . getToken ( ) ) ;
}
controlPointsChanged ( ) ;
}
break ;
case xml_state_t : : eShader : {
SetShader ( m_xml_state . back ( ) . content ( ) ) ;
}
break ;
default :
ERROR_MESSAGE ( " parse error " ) ;
}
ASSERT_MESSAGE ( ! m_xml_state . empty ( ) , " popping empty stack " ) ;
m_xml_state . pop_back ( ) ;
}
std : : size_t write ( const char * buffer , std : : size_t length )
{
switch ( m_xml_state . back ( ) . state ( ) ) {
case xml_state_t : : eDefault :
break ;
case xml_state_t : : ePatch :
break ;
case xml_state_t : : eMatrix :
case xml_state_t : : eShader :
return m_xml_state . back ( ) . write ( buffer , length ) ;
break ;
default :
ERROR_MESSAGE ( " parse error " ) ;
}
return length ;
}
void exportXML ( XMLImporter & importer )
{
StaticElement patchElement ( " patch " ) ;
importer . pushElement ( patchElement ) ;
{
const StaticElement element ( " shader " ) ;
importer . pushElement ( element ) ;
importer . write ( m_shader . c_str ( ) , strlen ( m_shader . c_str ( ) ) ) ;
importer . popElement ( element . name ( ) ) ;
}
{
char width [ 16 ] , height [ 16 ] ;
sprintf ( width , " %u " , Unsigned ( m_width ) ) ;
sprintf ( height , " %u " , Unsigned ( m_height ) ) ;
StaticElement element ( " matrix " ) ;
element . insertAttribute ( " width " , width ) ;
element . insertAttribute ( " height " , height ) ;
importer . pushElement ( element ) ;
{
for ( PatchControlIter i = m_ctrl . data ( ) , end = m_ctrl . data ( ) + m_ctrl . size ( ) ; i ! = end ; + + i ) {
importer < < ( * i ) . m_vertex [ 0 ]
< < ' ' < < ( * i ) . m_vertex [ 1 ]
< < ' ' < < ( * i ) . m_vertex [ 2 ]
< < ' ' < < ( * i ) . m_texcoord [ 0 ]
< < ' ' < < ( * i ) . m_texcoord [ 1 ] ;
}
}
importer . popElement ( element . name ( ) ) ;
}
importer . popElement ( patchElement . name ( ) ) ;
}
void UpdateCachedData ( ) ;
const char * GetShader ( ) const
{
return m_shader . c_str ( ) ;
}
void SetShader ( const char * name )
{
ASSERT_NOTNULL ( name ) ;
if ( shader_equal ( m_shader . c_str ( ) , name ) ) {
return ;
}
undoSave ( ) ;
if ( m_instanceCounter . m_count ! = 0 ) {
m_state - > decrementUsed ( ) ;
}
releaseShader ( ) ;
m_shader = name ;
captureShader ( ) ;
if ( m_instanceCounter . m_count ! = 0 ) {
m_state - > incrementUsed ( ) ;
}
check_shader ( ) ;
Patch_textureChanged ( ) ;
}
int getShaderFlags ( ) const
{
if ( m_state ! = 0 ) {
return m_state - > getFlags ( ) ;
}
return 0 ;
}
typedef PatchControl * iterator ;
typedef const PatchControl * const_iterator ;
iterator begin ( )
{
return m_ctrl . data ( ) ;
}
const_iterator begin ( ) const
{
return m_ctrl . data ( ) ;
}
iterator end ( )
{
return m_ctrl . data ( ) + m_ctrl . size ( ) ;
}
const_iterator end ( ) const
{
return m_ctrl . data ( ) + m_ctrl . size ( ) ;
}
PatchControlArray & getControlPoints ( )
{
return m_ctrl ;
}
PatchControlArray & getControlPointsTransformed ( )
{
return m_ctrlTransformed ;
}
void setDims ( std : : size_t w , std : : size_t h ) ;
std : : size_t getWidth ( ) const
{
return m_width ;
}
std : : size_t getHeight ( ) const
{
return m_height ;
}
PatchControl & ctrlAt ( std : : size_t row , std : : size_t col )
{
return m_ctrl [ row * m_width + col ] ;
}
const PatchControl & ctrlAt ( std : : size_t row , std : : size_t col ) const
{
return m_ctrl [ row * m_width + col ] ;
}
void ConstructPrefab ( const AABB & aabb , EPatchPrefab eType , int axis , std : : size_t width = 3 , std : : size_t height = 3 ) ;
void constructPlane ( const AABB & aabb , int axis , std : : size_t width , std : : size_t height ) ;
void InvertMatrix ( ) ;
void TransposeMatrix ( ) ;
void Redisperse ( EMatrixMajor mt ) ;
void Smooth ( EMatrixMajor mt ) ;
void InsertRemove ( bool bInsert , bool bColumn , bool bFirst ) ;
Patch * MakeCap ( Patch * patch , EPatchCap eType , EMatrixMajor mt , bool bFirst ) ;
void ConstructSeam ( EPatchCap eType , Vector3 * p , std : : size_t width ) ;
void FlipTexture ( int nAxis ) ;
void TranslateTexture ( float s , float t ) ;
void ScaleTexture ( float s , float t ) ;
void RotateTexture ( float angle ) ;
void SetTextureRepeat ( float s , float t ) ; // call with s=1 t=1 for FIT
void CapTexture ( ) ;
void NaturalTexture ( ) ;
void ProjectTexture ( int nAxis ) ;
void IdentityColour ( void ) ; //sets all colours to 1,1,1,1
void undoSave ( )
{
if ( m_map ! = 0 ) {
m_map - > changed ( ) ;
}
if ( m_undoable_observer ! = 0 ) {
m_undoable_observer - > save ( this ) ;
}
}
UndoMemento * exportState ( ) const
{
return new SavedState ( m_width , m_height , m_ctrl , m_shader . c_str ( ) , m_patchDef3 , m_patchDefWS , m_subdivisions_x ,
m_subdivisions_y ) ;
}
void importState ( const UndoMemento * state )
{
undoSave ( ) ;
const SavedState & other = * ( static_cast < const SavedState * > ( state ) ) ;
// begin duplicate of SavedState copy constructor, needs refactoring
// copy construct
{
m_width = other . m_width ;
m_height = other . m_height ;
SetShader ( other . m_shader . c_str ( ) ) ;
m_ctrl = other . m_ctrl ;
onAllocate ( m_ctrl . size ( ) ) ;
m_patchDef3 = other . m_patchDef3 ;
m_patchDefWS = other . m_patchDefWS ;
m_subdivisions_x = other . m_subdivisions_x ;
m_subdivisions_y = other . m_subdivisions_y ;
}
// end duplicate code
Patch_textureChanged ( ) ;
controlPointsChanged ( ) ;
}
static void constructStatic ( EPatchType type )
{
Patch : : m_type = type ;
Patch : : m_state_ctrl = GlobalShaderCache ( ) . capture ( " $POINT " ) ;
Patch : : m_state_lattice = GlobalShaderCache ( ) . capture ( " $LATTICE " ) ;
}
static void destroyStatic ( )
{
GlobalShaderCache ( ) . release ( " $LATTICE " ) ;
GlobalShaderCache ( ) . release ( " $POINT " ) ;
}
private :
void captureShader ( )
{
m_state = GlobalShaderCache ( ) . capture ( m_shader . c_str ( ) ) ;
}
void releaseShader ( )
{
GlobalShaderCache ( ) . release ( m_shader . c_str ( ) ) ;
}
void check_shader ( )
{
if ( ! shader_valid ( GetShader ( ) ) ) {
globalErrorStream ( ) < < " patch has invalid texture name: ' " < < GetShader ( ) < < " ' \n " ;
}
}
void InsertPoints ( EMatrixMajor mt , bool bFirst ) ;
void RemovePoints ( EMatrixMajor mt , bool bFirst ) ;
void AccumulateBBox ( ) ;
void TesselateSubMatrixFixed ( ArbitraryMeshVertex * vertices , std : : size_t strideX , std : : size_t strideY ,
unsigned int nFlagsX , unsigned int nFlagsY , PatchControl * subMatrix [ 3 ] [ 3 ] ) ;
// uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
void TesselateSubMatrix ( const BezierCurveTree * BX , const BezierCurveTree * BY ,
std : : size_t offStartX , std : : size_t offStartY ,
std : : size_t offEndX , std : : size_t offEndY ,
std : : size_t nFlagsX , std : : size_t nFlagsY ,
Vector3 & left , Vector3 & mid , Vector3 & right ,
Vector2 & texLeft , Vector2 & texMid , Vector2 & texRight ,
Vector4 & colLeft , Vector4 & colMid , Vector4 & colRight ,
bool bTranspose ) ;
// tesselates the entire surface
void BuildTesselationCurves ( EMatrixMajor major ) ;
void accumulateVertexTangentSpace ( std : : size_t index , Vector3 tangentX [ 6 ] , Vector3 tangentY [ 6 ] , Vector2 tangentS [ 6 ] ,
Vector2 tangentT [ 6 ] , std : : size_t index0 , std : : size_t index1 ) ;
void BuildVertexArray ( ) ;
} ;
inline bool Patch_importHeader ( Patch & patch , Tokeniser & tokeniser )
{
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " { " ) ) ;
return true ;
}
inline bool Patch_importShader ( Patch & patch , Tokeniser & tokeniser )
{
// parse shader name
tokeniser . nextLine ( ) ;
const char * texture = tokeniser . getToken ( ) ;
if ( texture = = 0 ) {
Tokeniser_unexpectedError ( tokeniser , texture , " #texture-name " ) ;
return false ;
}
if ( string_equal ( texture , " NULL " ) ) {
patch . SetShader ( texdef_name_default ( ) ) ;
} else {
StringOutputStream shader ( string_length ( GlobalTexturePrefix_get ( ) ) + string_length ( texture ) ) ;
shader < < GlobalTexturePrefix_get ( ) < < texture ;
patch . SetShader ( shader . c_str ( ) ) ;
}
return true ;
}
inline bool PatchDoom3_importShader ( Patch & patch , Tokeniser & tokeniser )
{
// parse shader name
tokeniser . nextLine ( ) ;
const char * shader = tokeniser . getToken ( ) ;
if ( shader = = 0 ) {
Tokeniser_unexpectedError ( tokeniser , shader , " #shader-name " ) ;
return false ;
}
if ( string_equal ( shader , " _emptyname " ) ) {
shader = texdef_name_default ( ) ;
}
patch . SetShader ( shader ) ;
return true ;
}
inline bool Patch_importParams ( Patch & patch , Tokeniser & tokeniser )
{
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ( " ) ) ;
// parse matrix dimensions
{
std : : size_t c , r ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getSize ( tokeniser , c ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getSize ( tokeniser , r ) ) ;
patch . setDims ( c , r ) ;
}
if ( patch . m_patchDef3 ) {
RETURN_FALSE_IF_FAIL ( Tokeniser_getSize ( tokeniser , patch . m_subdivisions_x ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getSize ( tokeniser , patch . m_subdivisions_y ) ) ;
}
// ignore contents/flags/value
int tmp ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getInteger ( tokeniser , tmp ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getInteger ( tokeniser , tmp ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getInteger ( tokeniser , tmp ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ) " ) ) ;
return true ;
}
inline bool Patch_importMatrix ( Patch & patch , Tokeniser & tokeniser )
{
// parse matrix
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ( " ) ) ;
{
for ( std : : size_t c = 0 ; c < patch . getWidth ( ) ; c + + ) {
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ( " ) ) ;
for ( std : : size_t r = 0 ; r < patch . getHeight ( ) ; r + + ) {
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ( " ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_vertex [ 0 ] ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_vertex [ 1 ] ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_vertex [ 2 ] ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_texcoord [ 0 ] ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_texcoord [ 1 ] ) ) ;
patch . ctrlAt ( r , c ) . m_color = Vector4 ( 1 , 1 , 1 , 1 ) ; //assume opaque white.
if ( patch . m_patchDefWS ) {
//Temp Hack, to handle weird format...
if ( Tokeniser_nextTokenMatches ( tokeniser , " ) " ) )
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ( " ) ) ;
//End Temp Hack.
}
if ( Tokeniser_nextTokenMatches ( tokeniser , " ) " ) )
continue ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_color [ 0 ] ) ) ;
if ( Tokeniser_nextTokenMatches ( tokeniser , " ) " ) )
continue ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_color [ 1 ] ) ) ;
if ( Tokeniser_nextTokenMatches ( tokeniser , " ) " ) )
continue ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_color [ 2 ] ) ) ;
if ( Tokeniser_nextTokenMatches ( tokeniser , " ) " ) )
continue ;
RETURN_FALSE_IF_FAIL ( Tokeniser_getFloat ( tokeniser , patch . ctrlAt ( r , c ) . m_color [ 3 ] ) ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ) " ) ) ;
}
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ) " ) ) ;
}
}
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " ) " ) ) ;
return true ;
}
inline bool Patch_importFooter ( Patch & patch , Tokeniser & tokeniser )
{
patch . controlPointsChanged ( ) ;
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " } " ) ) ;
tokeniser . nextLine ( ) ;
RETURN_FALSE_IF_FAIL ( Tokeniser_parseToken ( tokeniser , " } " ) ) ;
return true ;
}
class PatchTokenImporter : public MapImporter {
Patch & m_patch ;
public :
PatchTokenImporter ( Patch & patch ) : m_patch ( patch )
{
}
bool importTokens ( Tokeniser & tokeniser )
{
RETURN_FALSE_IF_FAIL ( Patch_importHeader ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importShader ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importParams ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importMatrix ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importFooter ( m_patch , tokeniser ) ) ;
return true ;
}
} ;
class PatchDoom3TokenImporter : public MapImporter {
Patch & m_patch ;
public :
PatchDoom3TokenImporter ( Patch & patch ) : m_patch ( patch )
{
}
bool importTokens ( Tokeniser & tokeniser )
{
RETURN_FALSE_IF_FAIL ( Patch_importHeader ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( PatchDoom3_importShader ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importParams ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importMatrix ( m_patch , tokeniser ) ) ;
RETURN_FALSE_IF_FAIL ( Patch_importFooter ( m_patch , tokeniser ) ) ;
return true ;
}
} ;
inline void Patch_exportHeader ( const Patch & patch , TokenWriter & writer )
{
writer . writeToken ( " { " ) ;
writer . nextLine ( ) ;
//if it has colours, use our postfix on the patchdef type (to prevent incompatible tools giving weird results - our parser doesn't really care for now...)
bool hascolours = false ;
for ( std : : size_t c = 0 ; c < patch . getWidth ( ) & & ! hascolours ; c + + ) {
for ( std : : size_t r = 0 ; r < patch . getHeight ( ) ; r + + ) {
auto v = patch . ctrlAt ( r , c ) ;
if ( v . m_color [ 0 ] ! = 1 | | v . m_color [ 1 ] ! = 1 | | v . m_color [ 2 ] ! = 1 | | v . m_color [ 3 ] ! = 1 )
{
hascolours = true ;
break ;
}
}
}
if ( hascolours ) {
writer . writeToken ( patch . m_patchDef3 ? " patchDef3WS " : " patchDef2WS " ) ;
} else {
writer . writeToken ( patch . m_patchDef3 ? " patchDef3 " : " patchDef2 " ) ;
}
writer . nextLine ( ) ;
writer . writeToken ( " { " ) ;
writer . nextLine ( ) ;
}
inline void Patch_exportShader ( const Patch & patch , TokenWriter & writer )
{
// write shader name
if ( * ( shader_get_textureName ( patch . GetShader ( ) ) ) = = ' \0 ' ) {
writer . writeToken ( " NULL " ) ;
} else {
writer . writeToken ( shader_get_textureName ( patch . GetShader ( ) ) ) ;
}
writer . nextLine ( ) ;
}
inline void PatchDoom3_exportShader ( const Patch & patch , TokenWriter & writer )
{
// write shader name
if ( * ( shader_get_textureName ( patch . GetShader ( ) ) ) = = ' \0 ' ) {
writer . writeString ( " _emptyname " ) ;
} else {
writer . writeString ( patch . GetShader ( ) ) ;
}
writer . nextLine ( ) ;
}
inline void Patch_exportParams ( const Patch & patch , TokenWriter & writer )
{
// write matrix dimensions
writer . writeToken ( " ( " ) ;
writer . writeUnsigned ( patch . getWidth ( ) ) ;
writer . writeUnsigned ( patch . getHeight ( ) ) ;
if ( patch . m_patchDef3 ) {
writer . writeUnsigned ( patch . m_subdivisions_x ) ;
writer . writeUnsigned ( patch . m_subdivisions_y ) ;
}
writer . writeInteger ( 0 ) ;
writer . writeInteger ( 0 ) ;
writer . writeInteger ( 0 ) ;
writer . writeToken ( " ) " ) ;
writer . nextLine ( ) ;
}
inline void Patch_exportMatrix ( const Patch & patch , TokenWriter & writer )
{
// write matrix
writer . writeToken ( " ( " ) ;
writer . nextLine ( ) ;
for ( std : : size_t c = 0 ; c < patch . getWidth ( ) ; c + + ) {
writer . writeToken ( " ( " ) ;
for ( std : : size_t r = 0 ; r < patch . getHeight ( ) ; r + + ) {
writer . writeToken ( " ( " ) ;
auto v = patch . ctrlAt ( r , c ) ;
writer . writeFloat ( v . m_vertex [ 0 ] ) ;
writer . writeFloat ( v . m_vertex [ 1 ] ) ;
writer . writeFloat ( v . m_vertex [ 2 ] ) ;
writer . writeFloat ( v . m_texcoord [ 0 ] ) ;
writer . writeFloat ( v . m_texcoord [ 1 ] ) ;
if ( v . m_color [ 0 ] ! = 1 | | v . m_color [ 1 ] ! = 1 | | v . m_color [ 2 ] ! = 1 | | v . m_color [ 3 ] ! = 1 ) {
writer . writeFloat ( v . m_color [ 0 ] ) ;
writer . writeFloat ( v . m_color [ 1 ] ) ;
writer . writeFloat ( v . m_color [ 2 ] ) ;
writer . writeFloat ( v . m_color [ 3 ] ) ;
}
writer . writeToken ( " ) " ) ;
}
writer . writeToken ( " ) " ) ;
writer . nextLine ( ) ;
}
writer . writeToken ( " ) " ) ;
writer . nextLine ( ) ;
}
inline void Patch_exportFooter ( const Patch & patch , TokenWriter & writer )
{
writer . writeToken ( " } " ) ;
writer . nextLine ( ) ;
writer . writeToken ( " } " ) ;
writer . nextLine ( ) ;
}
class PatchTokenExporter : public MapExporter {
const Patch & m_patch ;
public :
PatchTokenExporter ( Patch & patch ) : m_patch ( patch )
{
}
void exportTokens ( TokenWriter & writer ) const
{
Patch_exportHeader ( m_patch , writer ) ;
Patch_exportShader ( m_patch , writer ) ;
Patch_exportParams ( m_patch , writer ) ;
Patch_exportMatrix ( m_patch , writer ) ;
Patch_exportFooter ( m_patch , writer ) ;
}
} ;
class PatchDoom3TokenExporter : public MapExporter {
const Patch & m_patch ;
public :
PatchDoom3TokenExporter ( Patch & patch ) : m_patch ( patch )
{
}
void exportTokens ( TokenWriter & writer ) const
{
Patch_exportHeader ( m_patch , writer ) ;
PatchDoom3_exportShader ( m_patch , writer ) ;
Patch_exportParams ( m_patch , writer ) ;
Patch_exportMatrix ( m_patch , writer ) ;
Patch_exportFooter ( m_patch , writer ) ;
}
} ;
class PatchControlInstance {
public :
PatchControl * m_ctrl ;
ObservedSelectable m_selectable ;
PatchControlInstance ( PatchControl * ctrl , const SelectionChangeCallback & observer )
: m_ctrl ( ctrl ) , m_selectable ( observer )
{
}
void testSelect ( Selector & selector , SelectionTest & test )
{
SelectionIntersection best ;
test . TestPoint ( m_ctrl - > m_vertex , best ) ;
if ( best . valid ( ) ) {
Selector_add ( selector , m_selectable , best ) ;
}
}
void snapto ( float snap )
{
vector3_snap ( m_ctrl - > m_vertex , snap ) ;
}
} ;
class PatchInstance :
public Patch : : Observer ,
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 < PatchInstance , Selectable > : : install ( m_casts ) ;
InstanceContainedCast < PatchInstance , Bounded > : : install ( m_casts ) ;
InstanceContainedCast < PatchInstance , Cullable > : : install ( m_casts ) ;
InstanceStaticCast < PatchInstance , Renderable > : : install ( m_casts ) ;
InstanceStaticCast < PatchInstance , SelectionTestable > : : install ( m_casts ) ;
InstanceStaticCast < PatchInstance , ComponentSelectionTestable > : : install ( m_casts ) ;
InstanceStaticCast < PatchInstance , ComponentEditable > : : install ( m_casts ) ;
InstanceStaticCast < PatchInstance , ComponentSnappable > : : install ( m_casts ) ;
InstanceStaticCast < PatchInstance , PlaneSelectable > : : install ( m_casts ) ;
InstanceIdentityCast < PatchInstance > : : install ( m_casts ) ;
InstanceContainedCast < PatchInstance , Transformable > : : install ( m_casts ) ;
}
InstanceTypeCastTable & get ( )
{
return m_casts ;
}
} ;
Patch & m_patch ;
typedef std : : vector < PatchControlInstance > PatchControlInstances ;
PatchControlInstances m_ctrl_instances ;
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
DragPlanes m_dragPlanes ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
mutable RenderablePointVector m_render_selected ;
mutable AABB m_aabb_component ;
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 ;
public :
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 < PatchInstance , void ( ) , & PatchInstance : : lightsChanged > LightsChangedCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
STRING_CONSTANT ( Name , " PatchInstance " ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
PatchInstance ( const scene : : Path & path , scene : : Instance * parent , Patch & patch ) :
Instance ( path , parent , this , StaticTypeCasts : : instance ( ) . get ( ) ) ,
m_patch ( patch ) ,
m_selectable ( SelectedChangedCaller ( * this ) ) ,
m_dragPlanes ( SelectedChangedComponentCaller ( * this ) ) ,
m_render_selected ( GL_POINTS ) ,
m_transform ( Patch : : TransformChangedCaller ( m_patch ) , ApplyTransformCaller ( * this ) )
{
m_patch . instanceAttach ( Instance : : path ( ) ) ;
m_patch . attach ( this ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_lightList = & GlobalShaderCache ( ) . attach ( * this ) ;
m_patch . m_lightsChanged = LightsChangedCaller ( * this ) ;
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
~ PatchInstance ( )
{
Instance : : setTransformChangedCallback ( Callback < void ( ) > ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_patch . m_lightsChanged = Callback < void ( ) > ( ) ;
GlobalShaderCache ( ) . detach ( * this ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_patch . detach ( this ) ;
m_patch . instanceDetach ( Instance : : path ( ) ) ;
}
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 < PatchInstance , void (
const Selectable & ) , & PatchInstance : : 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 < PatchInstance , void (
const Selectable & ) , & PatchInstance : : selectedChangedComponent > SelectedChangedComponentCaller ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Patch & getPatch ( )
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Bounded & get ( NullType < Bounded > )
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Cullable & get ( NullType < Cullable > )
{
return m_patch ;
}
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
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 allocate ( std : : size_t size )
{
m_ctrl_instances . clear ( ) ;
m_ctrl_instances . reserve ( size ) ;
for ( Patch : : iterator i = m_patch . begin ( ) ; i ! = m_patch . end ( ) ; + + i ) {
m_ctrl_instances . push_back ( PatchControlInstance ( & ( * i ) , SelectedChangedComponentCaller ( * this ) ) ) ;
}
}
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
bool isSelected ( ) const
{
return m_selectable . isSelected ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void update_selected ( ) const
{
m_render_selected . clear ( ) ;
Patch : : iterator ctrl = m_patch . getControlPointsTransformed ( ) . begin ( ) ;
for ( PatchControlInstances : : const_iterator i = m_ctrl_instances . begin ( ) ;
i ! = m_ctrl_instances . end ( ) ; + + i , + + ctrl ) {
if ( ( * i ) . m_selectable . isSelected ( ) ) {
const Colour4b colour_selected ( 0 , 0 , 255 , 255 ) ;
m_render_selected . push_back (
PointVertex ( reinterpret_cast < Vertex3f & > ( ( * ctrl ) . m_vertex ) , colour_selected ) ) ;
}
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
#if 0
void render ( Renderer & renderer , const VolumeTest & volume ) const {
if ( GlobalSelectionSystem ( ) . Mode ( ) = = SelectionSystem : : eComponent
& & m_selectable . isSelected ( ) ) {
renderer . Highlight ( Renderer : : eFace , false ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_patch . render ( renderer , volume , localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( GlobalSelectionSystem ( ) . ComponentMode ( ) = = SelectionSystem : : eVertex ) {
renderer . Highlight ( Renderer : : ePrimitive , false ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
m_patch . render_component ( renderer , volume , localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderComponentsSelected ( renderer , volume ) ;
}
}
else {
m_patch . render ( renderer , volume , localToWorld ( ) ) ;
}
}
# endif
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_patch . evaluateTransform ( ) ;
renderer . setLights ( * m_lightList ) ;
m_patch . render_solid ( renderer , volume , localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderComponentsSelected ( renderer , volume ) ;
}
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_patch . evaluateTransform ( ) ;
m_patch . render_wireframe ( renderer , volume , localToWorld ( ) ) ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
renderComponentsSelected ( renderer , volume ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void renderComponentsSelected ( Renderer & renderer , const VolumeTest & volume ) const
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
m_patch . evaluateTransform ( ) ;
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
void renderComponents ( Renderer & renderer , const VolumeTest & volume ) const
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
m_patch . evaluateTransform ( ) ;
if ( GlobalSelectionSystem ( ) . ComponentMode ( ) = = SelectionSystem : : eVertex ) {
m_patch . render_component ( renderer , volume , localToWorld ( ) ) ;
}
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
void testSelect ( Selector & selector , SelectionTest & test )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
test . BeginMesh ( localToWorld ( ) , true ) ;
m_patch . testSelect ( selector , test ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
void selectCtrl ( bool select )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
for ( PatchControlInstances : : iterator i = m_ctrl_instances . begin ( ) ; i ! = m_ctrl_instances . end ( ) ; + + i ) {
( * i ) . m_selectable . setSelected ( select ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
bool isSelectedComponents ( ) const
{
for ( PatchControlInstances : : const_iterator i = m_ctrl_instances . begin ( ) ; i ! = m_ctrl_instances . end ( ) ; + + i ) {
if ( ( * i ) . m_selectable . isSelected ( ) ) {
return true ;
}
}
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 )
{
if ( mode = = SelectionSystem : : eVertex ) {
selectCtrl ( select ) ;
} else if ( mode = = SelectionSystem : : eFace ) {
m_dragPlanes . setSelected ( select ) ;
}
}
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 ( PatchControlInstances : : const_iterator i = m_ctrl_instances . begin ( ) ; i ! = m_ctrl_instances . end ( ) ; + + i ) {
if ( ( * i ) . m_selectable . isSelected ( ) ) {
aabb_extend_by_point_safe ( m_aabb_component , ( * i ) . m_ctrl - > m_vertex ) ;
}
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
return m_aabb_component ;
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 )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
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 ( PatchControlInstances : : iterator i = m_ctrl_instances . begin ( ) ; i ! = m_ctrl_instances . end ( ) ; + + i ) {
( * i ) . testSelect ( selector , test ) ;
}
}
break ;
default :
break ;
}
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
bool selectedVertices ( )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
for ( PatchControlInstances : : iterator i = m_ctrl_instances . begin ( ) ; i ! = m_ctrl_instances . end ( ) ; + + i ) {
if ( ( * i ) . m_selectable . isSelected ( ) ) {
return true ;
}
}
return false ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void transformComponents ( const Matrix4 & matrix )
{
if ( selectedVertices ( ) ) {
PatchControlIter ctrl = m_patch . getControlPointsTransformed ( ) . begin ( ) ;
for ( PatchControlInstances : : iterator i = m_ctrl_instances . begin ( ) ;
i ! = m_ctrl_instances . end ( ) ; + + i , + + ctrl ) {
if ( ( * i ) . m_selectable . isSelected ( ) ) {
matrix4_transform_point ( matrix , ( * ctrl ) . m_vertex ) ;
}
}
m_patch . UpdateCachedData ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
if ( m_dragPlanes . isSelected ( ) ) { // this should only be true when the transform is a pure translation.
m_patch . transform ( m_dragPlanes . evaluateTransform ( vector4_to_vector3 ( matrix . t ( ) ) ) ) ;
}
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
m_dragPlanes . selectPlanes ( m_patch . localAABB ( ) , selector , test , selectedPlaneCallback ) ;
}
void selectReversedPlanes ( Selector & selector , const SelectedPlanes & selectedPlanes )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
m_dragPlanes . selectReversedPlanes ( m_patch . localAABB ( ) , selector , selectedPlanes ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void snapComponents ( float snap )
{
if ( selectedVertices ( ) ) {
m_patch . undoSave ( ) ;
for ( PatchControlInstances : : iterator i = m_ctrl_instances . begin ( ) ; i ! = m_ctrl_instances . end ( ) ; + + i ) {
if ( ( * i ) . m_selectable . isSelected ( ) ) {
( * i ) . snapto ( snap ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
m_patch . controlPointsChanged ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
}
void evaluateTransform ( )
{
Matrix4 matrix ( m_transform . calculateTransform ( ) ) ;
if ( m_transform . getType ( ) = = TRANSFORM_PRIMITIVE ) {
m_patch . transform ( matrix ) ;
2020-11-17 03:16:16 -08:00
} else {
2021-08-04 13:23:18 -07:00
transformComponents ( matrix ) ;
2020-11-17 03:16:16 -08:00
}
}
2021-08-04 13:23:18 -07:00
void applyTransform ( )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
m_patch . revertTransform ( ) ;
evaluateTransform ( ) ;
m_patch . freezeTransform ( ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
typedef MemberCaller < PatchInstance , void ( ) , & PatchInstance : : applyTransform > ApplyTransformCaller ;
bool testLight ( const RendererLight & light ) const
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
return light . testAABB ( worldAABB ( ) ) ;
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 TokenImporter , typename TokenExporter >
class PatchNode :
public scene : : Node : : Symbiot ,
public scene : : Instantiable ,
public scene : : Cloneable {
typedef PatchNode < TokenImporter , TokenExporter > Self ;
class TypeCasts {
InstanceTypeCastTable m_casts ;
public :
TypeCasts ( )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
NodeStaticCast < PatchNode , scene : : Instantiable > : : install ( m_casts ) ;
NodeStaticCast < PatchNode , scene : : Cloneable > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , Snappable > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , TransformNode > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , Patch > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , XMLImporter > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , XMLExporter > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , MapImporter > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , MapExporter > : : install ( m_casts ) ;
NodeContainedCast < PatchNode , Nameable > : : install ( m_casts ) ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
InstanceTypeCastTable & get ( )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
return m_casts ;
}
} ;
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
scene : : Node m_node ;
InstanceSet m_instances ;
Patch m_patch ;
TokenImporter m_importMap ;
TokenExporter m_exportMap ;
public :
typedef LazyStatic < TypeCasts > StaticTypeCasts ;
Snappable & get ( NullType < Snappable > )
{
return m_patch ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
TransformNode & get ( NullType < TransformNode > )
2020-11-17 03:16:16 -08:00
{
2021-08-04 13:23:18 -07:00
return m_patch ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
Patch & get ( NullType < Patch > )
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
XMLImporter & get ( NullType < XMLImporter > )
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
XMLExporter & get ( NullType < XMLExporter > )
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
MapImporter & get ( NullType < MapImporter > )
{
return m_importMap ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
MapExporter & get ( NullType < MapExporter > )
{
return m_exportMap ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Nameable & get ( NullType < Nameable > )
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
PatchNode ( bool patchDef3 , bool patchWS ) :
m_node ( this , this , StaticTypeCasts : : instance ( ) . get ( ) ) ,
m_patch ( m_node , InstanceSetEvaluateTransform < PatchInstance > : : Caller ( m_instances ) ,
InstanceSet : : BoundsChangedCaller ( m_instances ) ) ,
m_importMap ( m_patch ) ,
m_exportMap ( m_patch )
{
m_patch . m_patchDef3 = patchDef3 ;
m_patch . m_patchDefWS = patchWS ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
PatchNode ( const PatchNode & other ) :
scene : : Node : : Symbiot ( other ) ,
scene : : Instantiable ( other ) ,
scene : : Cloneable ( other ) ,
m_node ( this , this , StaticTypeCasts : : instance ( ) . get ( ) ) ,
m_patch ( other . m_patch , m_node , InstanceSetEvaluateTransform < PatchInstance > : : Caller ( m_instances ) ,
InstanceSet : : BoundsChangedCaller ( m_instances ) ) ,
m_importMap ( m_patch ) ,
m_exportMap ( m_patch )
{
}
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
scene : : Node & node ( )
{
return m_node ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
Patch & get ( )
{
return m_patch ;
2020-11-17 03:16:16 -08:00
}
2021-08-04 13:23:18 -07:00
const Patch & get ( ) const
{
return m_patch ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
scene : : Node & clone ( ) const
{
return ( new PatchNode ( * this ) ) - > node ( ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
scene : : Instance * create ( const scene : : Path & path , scene : : Instance * parent )
{
return new PatchInstance ( path , parent , m_patch ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
void forEachInstance ( const scene : : Instantiable : : Visitor & visitor )
{
m_instances . forEachInstance ( visitor ) ;
}
void insert ( scene : : Instantiable : : Observer * observer , const scene : : Path & path , scene : : Instance * instance )
{
m_instances . insert ( observer , path , instance ) ;
}
2020-11-17 03:16:16 -08:00
2021-08-04 13:23:18 -07:00
scene : : Instance * erase ( scene : : Instantiable : : Observer * observer , const scene : : Path & path )
{
return m_instances . erase ( observer , path ) ;
}
2020-11-17 03:16:16 -08:00
} ;
typedef PatchNode < PatchTokenImporter , PatchTokenExporter > PatchNodeQuake3 ;
typedef PatchNode < PatchDoom3TokenImporter , PatchDoom3TokenExporter > PatchNodeDoom3 ;
inline Patch * Node_getPatch ( scene : : Node & node )
{
2021-08-04 13:23:18 -07:00
return NodeTypeCast < Patch > : : cast ( node ) ;
2020-11-17 03:16:16 -08:00
}
inline PatchInstance * Instance_getPatch ( scene : : Instance & instance )
{
2021-08-04 13:23:18 -07:00
return InstanceTypeCast < PatchInstance > : : cast ( instance ) ;
2020-11-17 03:16:16 -08:00
}
template < typename Functor >
class PatchSelectedVisitor : 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
PatchSelectedVisitor ( const Functor & functor ) : m_functor ( functor )
{
}
void visit ( scene : : Instance & instance ) const
{
PatchInstance * patch = Instance_getPatch ( instance ) ;
if ( patch ! = 0 ) {
m_functor ( * patch ) ;
}
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline void Scene_forEachSelectedPatch ( const Functor & functor )
{
2021-08-04 13:23:18 -07:00
GlobalSelectionSystem ( ) . foreachSelected ( PatchSelectedVisitor < Functor > ( functor ) ) ;
2020-11-17 03:16:16 -08:00
}
template < typename Functor >
class PatchVisibleSelectedVisitor : 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
PatchVisibleSelectedVisitor ( const Functor & functor ) : m_functor ( functor )
{
}
void visit ( scene : : Instance & instance ) const
{
PatchInstance * patch = Instance_getPatch ( instance ) ;
if ( patch ! = 0
& & instance . path ( ) . top ( ) . get ( ) . visible ( ) ) {
m_functor ( * patch ) ;
}
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline void Scene_forEachVisibleSelectedPatchInstance ( const Functor & functor )
{
2021-08-04 13:23:18 -07:00
GlobalSelectionSystem ( ) . foreachSelected ( PatchVisibleSelectedVisitor < Functor > ( functor ) ) ;
2020-11-17 03:16:16 -08:00
}
template < typename Functor >
class PatchForEachWalker : 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
PatchForEachWalker ( const Functor & functor ) : m_functor ( functor )
{
}
bool pre ( const scene : : Path & path , scene : : Instance & instance ) const
{
if ( path . top ( ) . get ( ) . visible ( ) ) {
Patch * patch = Node_getPatch ( path . top ( ) ) ;
if ( patch ! = 0 ) {
m_functor ( * patch ) ;
}
}
return true ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline void Scene_forEachVisiblePatch ( const Functor & functor )
{
2021-08-04 13:23:18 -07:00
GlobalSceneGraph ( ) . traverse ( PatchForEachWalker < Functor > ( functor ) ) ;
2020-11-17 03:16:16 -08:00
}
template < typename Functor >
class PatchForEachSelectedWalker : 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
PatchForEachSelectedWalker ( const Functor & functor ) : m_functor ( functor )
{
}
bool pre ( const scene : : Path & path , scene : : Instance & instance ) const
{
if ( path . top ( ) . get ( ) . visible ( ) ) {
Patch * patch = Node_getPatch ( path . top ( ) ) ;
if ( patch ! = 0
& & Instance_getSelectable ( instance ) - > isSelected ( ) ) {
m_functor ( * patch ) ;
}
}
return true ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline void Scene_forEachVisibleSelectedPatch ( const Functor & functor )
{
2021-08-04 13:23:18 -07:00
GlobalSceneGraph ( ) . traverse ( PatchForEachSelectedWalker < Functor > ( functor ) ) ;
2020-11-17 03:16:16 -08:00
}
template < typename Functor >
class PatchForEachInstanceWalker : 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
PatchForEachInstanceWalker ( const Functor & functor ) : m_functor ( functor )
{
}
bool pre ( const scene : : Path & path , scene : : Instance & instance ) const
{
if ( path . top ( ) . get ( ) . visible ( ) ) {
PatchInstance * patch = Instance_getPatch ( instance ) ;
if ( patch ! = 0 ) {
m_functor ( * patch ) ;
}
}
return true ;
}
2020-11-17 03:16:16 -08:00
} ;
template < typename Functor >
inline void Scene_forEachVisiblePatchInstance ( const Functor & functor )
{
2021-08-04 13:23:18 -07:00
GlobalSceneGraph ( ) . traverse ( PatchForEachInstanceWalker < Functor > ( functor ) ) ;
2020-11-17 03:16:16 -08:00
}
# endif