From 3706e1131aa7842adee42580b19a5277823ac5f1 Mon Sep 17 00:00:00 2001 From: Garux Date: Sat, 11 Aug 2018 23:36:50 +0300 Subject: [PATCH] binds... * m3: copy texture name, alignment +new: color, light power, color * alt + m3/drag: paste texture name (to pointed and selected stuff) * shift + m3/drag: paste texture name, alignment +new: light power * ctrl + m3/drag: paste texture seamlessly between brush faces +new: light color * ctrl + shift + m3/drag: project texture from copied brush face +new: paste light power, color * alt + ctrl/shift/ctrl+shift + m3/drag: respective texture alignment paste w/o texture name fix void NormalizeColor( Vector3& color ) fix: reset texture clipboard texdef on selection in texbro (was only resetting scales) --- libs/generic/callback.h | 83 ++++++++++++ libs/generic/functional.h | 30 +++++ plugins/entity/colour.h | 2 +- plugins/entity/light.cpp | 10 +- radiant/brush_primit.h | 4 +- radiant/entity.cpp | 6 +- radiant/patch.h | 4 + radiant/selection.cpp | 23 ++-- radiant/surfacedialog.cpp | 257 +++++++++++++++++++++++--------------- 9 files changed, 296 insertions(+), 123 deletions(-) diff --git a/libs/generic/callback.h b/libs/generic/callback.h index 2ce007fc..a22a3ffd 100644 --- a/libs/generic/callback.h +++ b/libs/generic/callback.h @@ -187,6 +187,33 @@ void* getEnvironment() const { } }; +template +class BindFirstOpaque4 +{ +typedef typename Caller::first_argument_type FirstBound; +FirstBound firstBound; +public: +typedef typename Caller::second_argument_type first_argument_type; +typedef typename Caller::third_argument_type second_argument_type; +typedef typename Caller::fourth_argument_type third_argument_type; +typedef typename Caller::fifth_argument_type fourth_argument_type; +typedef typename Caller::result_type result_type; +explicit BindFirstOpaque4( FirstBound firstBound ) : firstBound( firstBound ){ +} +result_type operator()( first_argument_type a1, second_argument_type a2, third_argument_type a3, fourth_argument_type a4 ) const { + return Caller::call( firstBound, a1, a2, a3, a4 ); +} +FirstBound getBound() const { + return firstBound; +} +static result_type thunk( void* environment, first_argument_type a1, second_argument_type a2, third_argument_type a3, fourth_argument_type a4 ){ + return Caller::call( ConvertFromOpaque::apply( environment ), a1, a2, a3, a4 ); +} +void* getEnvironment() const { + return convertToOpaque( firstBound ); +} +}; + template class CallbackBase { @@ -393,6 +420,62 @@ inline Callback3< } +/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and four other arguments. +/// +template +class Callback4 : public CallbackBase +{ +typedef CallbackBase Base; +static Result nullThunk( void*, FirstArgument, SecondArgument, ThirdArgument, FourthArgument ){ +} + +public: +typedef FirstArgument first_argument_type; +typedef SecondArgument second_argument_type; +typedef ThirdArgument third_argument_type; +typedef FourthArgument fourth_argument_type; +typedef Result result_type; + +Callback4() : Base( 0, nullThunk ){ +} +template +Callback4( const BindFirstOpaque4& caller ) : Base( caller.getEnvironment(), BindFirstOpaque4::thunk ){ +} +Callback4( void* environment, typename Base::Thunk function ) : Base( environment, function ){ +} +result_type operator()( FirstArgument firstArgument, SecondArgument secondArgument, ThirdArgument thirdArgument, FourthArgument fourthArgument ) const { + return Base::getThunk() ( Base::getEnvironment(), firstArgument, secondArgument, thirdArgument, fourthArgument ); +} +}; + +template +inline Callback4< + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::fourth_argument_type, + typename Caller::fifth_argument_type, + typename Caller::result_type + > makeCallback4( const Caller& caller, typename Caller::first_argument_type callee ){ + return Callback4< + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::fourth_argument_type, + typename Caller::fifth_argument_type, + typename Caller::result_type + >( BindFirstOpaque4( callee ) ); +} +template +inline Callback4< + typename Caller::first_argument_type, + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::fourth_argument_type, + typename Caller::result_type + > makeStatelessCallback4( const Caller& caller ){ + return makeCallback4( Caller4To5(), 0 ); +} + + /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function. /// /// \dontinclude generic/callback.cpp diff --git a/libs/generic/functional.h b/libs/generic/functional.h index 940d4e7f..5459ba0d 100644 --- a/libs/generic/functional.h +++ b/libs/generic/functional.h @@ -162,6 +162,21 @@ static result_type call( first_argument_type a1, second_argument_type a2, third_ } }; +template +class Function5 +{ +public: +typedef A1 first_argument_type; +typedef A2 second_argument_type; +typedef A3 third_argument_type; +typedef A4 fourth_argument_type; +typedef A5 fifth_argument_type; +typedef R result_type; +static result_type call( first_argument_type a1, second_argument_type a2, third_argument_type a3, fourth_argument_type a4, fifth_argument_type a5 ){ + return (func)( a1, a2, a3, a4, a5 ); +} +}; + template class Caller0To1 { @@ -212,6 +227,21 @@ static result_type call( first_argument_type, second_argument_type a2, third_arg } }; +template +class Caller4To5 +{ +public: +typedef FirstArgument first_argument_type; +typedef typename Caller::first_argument_type second_argument_type; +typedef typename Caller::second_argument_type third_argument_type; +typedef typename Caller::third_argument_type fourth_argument_type; +typedef typename Caller::fourth_argument_type fifth_argument_type; +typedef typename Caller::result_type result_type; +static result_type call( first_argument_type, second_argument_type a2, third_argument_type a3, fourth_argument_type a4, fifth_argument_type a5 ){ + return Caller::call( a2, a3, a4, a5 ); +} +}; + template class FunctorInvoke { diff --git a/plugins/entity/colour.h b/plugins/entity/colour.h index 159703e0..2ecbc3d2 100644 --- a/plugins/entity/colour.h +++ b/plugins/entity/colour.h @@ -41,7 +41,7 @@ inline void read_colour( Vector3& colour, const char* value ){ inline void write_colour( const Vector3& colour, Entity* entity ){ char value[64]; - sprintf( value, "%f %f %f", colour[0], colour[1], colour[2] ); + sprintf( value, "%g %g %g", colour[0], colour[1], colour[2] ); entity->setKeyValue( "_color", value ); } diff --git a/plugins/entity/light.cpp b/plugins/entity/light.cpp index ffcc9022..6b54c04e 100644 --- a/plugins/entity/light.cpp +++ b/plugins/entity/light.cpp @@ -689,14 +689,10 @@ void light_draw( const AABB& aabb_light, RenderStateFlags state ){ inline void write_intensity( const float intensity, Entity* entity ){ char value[64]; sprintf( value, "%g", intensity ); - - //primaryIntensity - if( !string_empty( entity->getKeyValue( "_light" ) ) ){ + if( !string_empty( entity->getKeyValue( "_light" ) ) ) //primaryIntensity //if set or default is set in .ent entity->setKeyValue( "_light", value ); - } - else{ //secondaryIntensity - entity->setKeyValue( "light", value ); - } + else //secondaryIntensity + entity->setKeyValue( "light", value ); //otherwise default to "light", which is understood by both q3 and q1 } // These variables are tweakable on the q3map2 console, setting to q3map2 diff --git a/radiant/brush_primit.h b/radiant/brush_primit.h index 5bb5c5c4..555a8cd0 100644 --- a/radiant/brush_primit.h +++ b/radiant/brush_primit.h @@ -37,7 +37,7 @@ struct brushprimit_texdef_t coords[1][1] = 2.0f; coords[1][2] = 0.f; } - void removeScale( std::size_t width, std::size_t height ){ + void removeScale( std::size_t width, std::size_t height ){ /* values in texture size scale for certain operations */ #if 1 coords[0][0] *= width; coords[0][1] *= width; @@ -47,7 +47,7 @@ struct brushprimit_texdef_t coords[1][2] *= height; #endif } - void addScale( std::size_t width, std::size_t height ){ + void addScale( std::size_t width, std::size_t height ){ /* addScaled in .map; offsets in range -1..1; texture size irrelevant */ #if 1 ASSERT_MESSAGE( width > 0, "shader-width is 0" ); ASSERT_MESSAGE( height > 0, "shader-height is 0" ); diff --git a/radiant/entity.cpp b/radiant/entity.cpp index 0975315a..410531ce 100644 --- a/radiant/entity.cpp +++ b/radiant/entity.cpp @@ -515,8 +515,10 @@ void NormalizeColor( Vector3& color ){ const std::size_t maxi = vector3_max_abs_component_index( color ); if ( color[maxi] == 0.f ) color = Vector3( 1, 1, 1 ); - else - color /= color[maxi]; + else{ + const float max = color[maxi]; + color /= max; + } } void Entity_normalizeColor(){ diff --git a/radiant/patch.h b/radiant/patch.h index 67d1f9cb..6a14e0a5 100644 --- a/radiant/patch.h +++ b/radiant/patch.h @@ -865,6 +865,10 @@ int getShaderFlags() const { } return 0; } +const Shader* getShader(){ + ASSERT_MESSAGE( m_state != 0, "patch shader is not realised" ); + return m_state; +} typedef PatchControl* iterator; typedef const PatchControl* const_iterator; diff --git a/radiant/selection.cpp b/radiant/selection.cpp index a780a78b..91266254 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -5570,7 +5570,8 @@ const ModifierFlags c_modifier_copy_texture = c_modifierNone; void Scene_copyClosestTexture( SelectionTest& test ); -void Scene_applyClosestTexture( SelectionTest& test, bool seamless, bool project, bool texturize_selected = false ); +void Scene_applyClosestTexture( SelectionTest& test, bool shift, bool ctrl, bool alt, bool texturize_selected = false ); +const char* Scene_applyClosestTexture_getUndoName( bool shift, bool ctrl, bool alt ); class TexManipulator_ { @@ -5591,13 +5592,15 @@ void mouseDown( DeviceVector position ){ ConstructSelectionTest( scissored, SelectionBoxForPoint( &position[0], &m_epsilon[0] ) ); SelectionVolume volume( scissored ); - if ( m_state == c_modifier_apply_texture1_project || m_state == c_modifier_apply_texture2_seamless || m_state == c_modifier_apply_texture3 ) { + if( m_state == c_modifier_copy_texture ) { + Scene_copyClosestTexture( volume ); + } + else{ m_undo_begun = true; GlobalUndoSystem().start(); - Scene_applyClosestTexture( volume, m_state == c_modifier_apply_texture2_seamless, m_state == c_modifier_apply_texture1_project, true ); - } - else if ( m_state == c_modifier_copy_texture ) { - Scene_copyClosestTexture( volume ); + Scene_applyClosestTexture( volume, bitfield_enabled( m_state, c_modifierShift ), + bitfield_enabled( m_state, c_modifierControl ), + bitfield_enabled( m_state, c_modifierAlt ), true ); } } @@ -5607,14 +5610,18 @@ void mouseMoved( DeviceVector position ){ ConstructSelectionTest( scissored, SelectionBoxForPoint( &device_constrained( position )[0], &m_epsilon[0] ) ); SelectionVolume volume( scissored ); - Scene_applyClosestTexture( volume, m_state == c_modifier_apply_texture2_seamless, m_state == c_modifier_apply_texture1_project ); + Scene_applyClosestTexture( volume, bitfield_enabled( m_state, c_modifierShift ), + bitfield_enabled( m_state, c_modifierControl ), + bitfield_enabled( m_state, c_modifierAlt ) ); } } typedef MemberCaller1 MouseMovedCaller; void mouseUp( DeviceVector position ){ if( m_undo_begun ){ - GlobalUndoSystem().finish( ( m_state == c_modifier_apply_texture1_project )? "projectTexture" : ( m_state == c_modifier_apply_texture2_seamless )? "paintTextureSeamless" : "paintTexture&Projection" ); + GlobalUndoSystem().finish( Scene_applyClosestTexture_getUndoName( bitfield_enabled( m_state, c_modifierShift ), + bitfield_enabled( m_state, c_modifierControl ), + bitfield_enabled( m_state, c_modifierAlt ) ) ); m_undo_begun = false; } g_mouseMovedCallback.clear(); diff --git a/radiant/surfacedialog.cpp b/radiant/surfacedialog.cpp index 321d5a75..c7f69db1 100644 --- a/radiant/surfacedialog.cpp +++ b/radiant/surfacedialog.cpp @@ -1460,17 +1460,40 @@ void SurfaceInspector::ApplyFlags(){ } + +enum EPasteMode{ + ePasteNone, + ePasteValues, + ePasteSeamless, + ePasteProject, +}; + +EPasteMode pastemode_for_modifiers( bool shift, bool ctrl ){ + if( shift ) + return ctrl? ePasteProject : ePasteValues; + else if( ctrl ) + return ePasteSeamless; + return ePasteNone; +} +bool pastemode_if_setShader( EPasteMode mode, bool alt ){ + return ( mode == ePasteNone ) || !alt; +} + + class FaceTexture { public: - TextureProjection m_projection; + TextureProjection m_projection; //BP part is removeScale()'d ContentsFlagsValue m_flags; Plane3 m_plane; std::size_t m_width; std::size_t m_height; - FaceTexture() : m_plane( 0, 0, 1, 0 ), m_width( 64 ), m_height( 64 ) { + float m_light; + Vector3 m_colour; + + FaceTexture() : m_plane( 0, 0, 1, 0 ), m_width( 64 ), m_height( 64 ), m_light( 300 ), m_colour( 1, 1, 1 ) { m_projection.m_basis_s = Vector3( 0.7071067811865, 0.7071067811865, 0 ); m_projection.m_basis_t = Vector3( -0.4082482904639, 0.4082482904639, -0.4082482904639 * 2.0 ); } @@ -1480,6 +1503,8 @@ FaceTexture g_faceTextureClipboard; void FaceTextureClipboard_setDefault(){ g_faceTextureClipboard.m_flags = ContentsFlagsValue( 0, 0, 0, false ); + g_faceTextureClipboard.m_projection.m_texdef = texdef_t(); + g_faceTextureClipboard.m_projection.m_brushprimit_texdef = brushprimit_texdef_t(); TexDef_Construct_Default( g_faceTextureClipboard.m_projection ); } @@ -1489,88 +1514,105 @@ void TextureClipboard_textureSelected( const char* shader ){ -void Face_getTexture( Face& face, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags ){ +void Face_getTexture( Face& face, CopiedString& shader, FaceTexture& clipboard ){ shader = face.GetShader(); - face.GetTexdef( projection ); - flags = face.getShader().m_flags; - g_faceTextureClipboard.m_plane = face.getPlane().plane3(); - g_faceTextureClipboard.m_width = face.getShader().width(); - g_faceTextureClipboard.m_height = face.getShader().height(); + face.GetTexdef( clipboard.m_projection ); + clipboard.m_flags = face.getShader().m_flags; + + clipboard.m_plane = face.getPlane().plane3(); + clipboard.m_width = face.getShader().width(); + clipboard.m_height = face.getShader().height(); + + clipboard.m_colour = face.getShader().state()->getTexture().color; } -typedef Function4 FaceGetTexture; +typedef Function3 FaceGetTexture; - -void Face_setTexture_Seamless( Face& face, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){ - face.SetShader( shader ); - - DoubleLine line = plane3_intersect_plane3( g_faceTextureClipboard.m_plane, face.getPlane().plane3() ); - if( vector3_length_squared( line.direction ) == 0 ){ - face.ProjectTexture( g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_plane.normal() ); - face.SetFlags( flags ); - return; +void Face_setTexture( Face& face, const char* shader, const FaceTexture& clipboard, EPasteMode mode, bool setShader ){ + if( setShader ){ + face.SetShader( shader ); + face.SetFlags( clipboard.m_flags ); } + if( mode == ePasteValues ){ + face.SetTexdef( clipboard.m_projection, false ); + } + else if( mode == ePasteProject ){ + face.ProjectTexture( clipboard.m_projection, clipboard.m_plane.normal() ); + } + else if( mode == ePasteSeamless ){ + DoubleLine line = plane3_intersect_plane3( clipboard.m_plane, face.getPlane().plane3() ); + if( vector3_length_squared( line.direction ) == 0 ){ + face.ProjectTexture( clipboard.m_projection, clipboard.m_plane.normal() ); + return; + } - const Quaternion rotation = quaternion_for_unit_vectors( g_faceTextureClipboard.m_plane.normal(), face.getPlane().plane3().normal() ); -// globalOutputStream() << "rotation: " << rotation.x() << " " << rotation.y() << " " << rotation.z() << " " << rotation.w() << " " << "\n"; - Matrix4 transform = g_matrix4_identity; - matrix4_pivoted_rotate_by_quaternion( transform, rotation, line.origin ); + const Quaternion rotation = quaternion_for_unit_vectors( clipboard.m_plane.normal(), face.getPlane().plane3().normal() ); +// globalOutputStream() << "rotation: " << rotation.x() << " " << rotation.y() << " " << rotation.z() << " " << rotation.w() << " " << "\n"; + Matrix4 transform = g_matrix4_identity; + matrix4_pivoted_rotate_by_quaternion( transform, rotation, line.origin ); - TextureProjection proj = projection; - proj.m_brushprimit_texdef.addScale( g_faceTextureClipboard.m_width, g_faceTextureClipboard.m_height ); - Texdef_transformLocked( proj, g_faceTextureClipboard.m_width, g_faceTextureClipboard.m_height, g_faceTextureClipboard.m_plane, transform, line.origin ); - proj.m_brushprimit_texdef.removeScale( g_faceTextureClipboard.m_width, g_faceTextureClipboard.m_height ); + TextureProjection proj = clipboard.m_projection; + proj.m_brushprimit_texdef.addScale( clipboard.m_width, clipboard.m_height ); + Texdef_transformLocked( proj, clipboard.m_width, clipboard.m_height, clipboard.m_plane, transform, line.origin ); + proj.m_brushprimit_texdef.removeScale( clipboard.m_width, clipboard.m_height ); + face.SetTexdef( proj ); - //face.SetTexdef( projection ); - face.SetTexdef( proj ); - face.SetFlags( flags ); - - g_faceTextureClipboard.m_plane = face.getPlane().plane3(); - g_faceTextureClipboard.m_projection = proj; + g_faceTextureClipboard.m_plane = face.getPlane().plane3(); + g_faceTextureClipboard.m_projection = proj; + } } -typedef Function4 FaceSetTextureSeamless; +typedef Function5 FaceSetTexture; -void Face_setTexture_Project( Face& face, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){ - face.SetShader( shader ); - //face.SetTexdef( projection ); - face.SetFlags( flags ); - - face.ProjectTexture( g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_plane.normal() ); -} -typedef Function4 FaceSetTextureProject; - - -void Face_setTexture( Face& face, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){ - face.SetShader( shader ); - face.SetTexdef( projection, false ); - face.SetFlags( flags ); -} -typedef Function4 FaceSetTexture; - - -void Patch_getTexture( Patch& patch, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags ){ +void Patch_getTexture( Patch& patch, CopiedString& shader, FaceTexture& clipboard ){ shader = patch.GetShader(); - projection = TextureProjection( texdef_t(), brushprimit_texdef_t(), Vector3( 0, 0, 0 ), Vector3( 0, 0, 0 ) ); - flags = ContentsFlagsValue( 0, 0, 0, false ); + FaceTextureClipboard_setDefault(); + + clipboard.m_width = patch.getShader()->getTexture().width; + clipboard.m_height = patch.getShader()->getTexture().height; + + clipboard.m_colour = patch.getShader()->getTexture().color; } -typedef Function4 PatchGetTexture; +typedef Function3 PatchGetTexture; -void Patch_setTexture_Project( Patch& patch, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){ - patch.SetShader( shader ); - patch.ProjectTexture( g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_plane.normal() ); +void Patch_setTexture( Patch& patch, const char* shader, const FaceTexture& clipboard, EPasteMode mode, bool setShader ){ + if( setShader ) + patch.SetShader( shader ); + if( mode == ePasteProject ) + patch.ProjectTexture( clipboard.m_projection, clipboard.m_plane.normal() ); } -typedef Function4 PatchSetTextureProject; +typedef Function5 PatchSetTexture; -void Patch_setTexture( Patch& patch, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags ){ - patch.SetShader( shader ); +#include "ientity.h" +void Light_getTexture( Entity& entity, CopiedString& shader, FaceTexture& clipboard ){ + string_parse_vector3( entity.getKeyValue( "_color" ), clipboard.m_colour ); + if( !string_parse_float( entity.getKeyValue( "_light" ), clipboard.m_light ) ) + string_parse_float( entity.getKeyValue( "light" ), clipboard.m_light ); } -typedef Function4 PatchSetTexture; +typedef Function3 LightGetTexture; + +void Light_setTexture( Entity& entity, const char* shader, const FaceTexture& clipboard, EPasteMode mode, bool setShader ){ + if( mode == ePasteSeamless || mode == ePasteProject ){ + char value[64]; + sprintf( value, "%g %g %g", clipboard.m_colour[0], clipboard.m_colour[1], clipboard.m_colour[2] ); + entity.setKeyValue( "_color", value ); + } + if( mode == ePasteValues || mode == ePasteProject ){ + /* copypaste of write_intensity() from entity plugin */ + char value[64]; + sprintf( value, "%g", clipboard.m_light ); + if( !string_empty( entity.getKeyValue( "_light" ) ) ) //primaryIntensity //if set or default is set in .ent + entity.setKeyValue( "_light", value ); + else //secondaryIntensity + entity.setKeyValue( "light", value ); //otherwise default to "light", which is understood by both q3 and q1 + } +} +typedef Function5 LightSetTexture; -typedef Callback3 GetTextureCallback; -typedef Callback3 SetTextureCallback; +typedef Callback2 GetTextureCallback; +typedef Callback4 SetTextureCallback; struct Texturable { @@ -1579,7 +1621,7 @@ struct Texturable }; -void Face_getClosest( Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Texturable& texturable, bool seamless, bool project ){ +void Face_getClosest( Face& face, SelectionTest& test, SelectionIntersection& bestIntersection, Texturable& texturable ){ if ( face.isFiltered() ) { return; } @@ -1588,13 +1630,8 @@ void Face_getClosest( Face& face, SelectionTest& test, SelectionIntersection& be if ( intersection.valid() && SelectionIntersection_closer( intersection, bestIntersection ) ) { bestIntersection = intersection; - if( project ) - texturable.setTexture = makeCallback3( FaceSetTextureProject(), face ); - else if( seamless ) - texturable.setTexture = makeCallback3( FaceSetTextureSeamless(), face ); - else - texturable.setTexture = makeCallback3( FaceSetTexture(), face ); - texturable.getTexture = makeCallback3( FaceGetTexture(), face ); + texturable.setTexture = makeCallback4( FaceSetTexture(), face ); + texturable.getTexture = makeCallback2( FaceGetTexture(), face ); } } @@ -1618,16 +1655,14 @@ void addIntersection( const SelectionIntersection& intersection ){ } } }; - +#include "eclasslib.h" class BrushGetClosestFaceVisibleWalker : public scene::Graph::Walker { SelectionTest& m_test; Texturable& m_texturable; -const bool m_seamless; -const bool m_project; mutable SelectionIntersection m_bestIntersection; public: -BrushGetClosestFaceVisibleWalker( SelectionTest& test, Texturable& texturable, bool seamless, bool project ) : m_test( test ), m_texturable( texturable ), m_seamless( seamless ), m_project( project ){ +BrushGetClosestFaceVisibleWalker( SelectionTest& test, Texturable& texturable ) : m_test( test ), m_texturable( texturable ){ } bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( !path.top().get().visible() ) @@ -1638,7 +1673,7 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { for ( Brush::const_iterator i = brush->getBrush().begin(); i != brush->getBrush().end(); ++i ) { - Face_getClosest( *( *i ), m_test, m_bestIntersection, m_texturable, m_seamless, m_project ); + Face_getClosest( *( *i ), m_test, m_bestIntersection, m_texturable ); } } else @@ -1651,14 +1686,16 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( occluded ) { Patch* patch = Node_getPatch( path.top() ); if ( patch != 0 ) { - if( m_project ) - m_texturable.setTexture = makeCallback3( PatchSetTextureProject(), *patch ); - else - m_texturable.setTexture = makeCallback3( PatchSetTexture(), *patch ); - m_texturable.getTexture = makeCallback3( PatchGetTexture(), *patch ); + m_texturable.setTexture = makeCallback4( PatchSetTexture(), *patch ); + m_texturable.getTexture = makeCallback2( PatchGetTexture(), *patch ); + return true; } - else - { + Entity* entity = Node_getEntity( path.top() ); + if( entity != 0 && string_equal_n( entity->getEntityClass().name(), "light", 5 ) ){ + m_texturable.setTexture = makeCallback4( LightSetTexture(), *entity ); + m_texturable.getTexture = makeCallback2( LightGetTexture(), *entity ); + } + else{ m_texturable = Texturable(); } } @@ -1668,25 +1705,25 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { } }; -Texturable Scene_getClosestTexturable( scene::Graph& graph, SelectionTest& test, bool seamless = false, bool project = false ){ +Texturable Scene_getClosestTexturable( scene::Graph& graph, SelectionTest& test ){ Texturable texturable; - graph.traverse( BrushGetClosestFaceVisibleWalker( test, texturable, seamless, project ) ); + graph.traverse( BrushGetClosestFaceVisibleWalker( test, texturable ) ); return texturable; } -bool Scene_getClosestTexture( scene::Graph& graph, SelectionTest& test, CopiedString& shader, TextureProjection& projection, ContentsFlagsValue& flags ){ +bool Scene_getClosestTexture( scene::Graph& graph, SelectionTest& test, CopiedString& shader, FaceTexture& clipboard ){ Texturable texturable = Scene_getClosestTexturable( graph, test ); if ( texturable.getTexture != GetTextureCallback() ) { - texturable.getTexture( shader, projection, flags ); + texturable.getTexture( shader, clipboard ); return true; } return false; } -void Scene_setClosestTexture( scene::Graph& graph, SelectionTest& test, const char* shader, const TextureProjection& projection, const ContentsFlagsValue& flags, bool seamless, bool project ){ - Texturable texturable = Scene_getClosestTexturable( graph, test, seamless, project ); +void Scene_setClosestTexture( scene::Graph& graph, SelectionTest& test, const char* shader, const FaceTexture& clipboard, EPasteMode mode, bool setShader ){ + Texturable texturable = Scene_getClosestTexturable( graph, test ); if ( texturable.setTexture != SetTextureCallback() ) { - texturable.setTexture( shader, projection, flags ); + texturable.setTexture( shader, clipboard, mode, setShader ); } } @@ -1695,29 +1732,43 @@ const char* TextureBrowser_GetSelectedShader(); void Scene_copyClosestTexture( SelectionTest& test ){ CopiedString shader; - if ( Scene_getClosestTexture( GlobalSceneGraph(), test, shader, g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags ) ) { + if ( Scene_getClosestTexture( GlobalSceneGraph(), test, shader, g_faceTextureClipboard ) ) { TextureBrowser_SetSelectedShader( shader.c_str() ); -// UndoableCommand undo( "textureNameAndProjectionSetSelected" ); -// Select_SetShader( shader.c_str() ); -// Select_SetTexdef( g_faceTextureClipboard.m_projection ); } } -void Scene_applyClosestTexture( SelectionTest& test, bool seamless, bool project, bool texturize_selected = false ){ +const char* Scene_applyClosestTexture_getUndoName( bool shift, bool ctrl, bool alt ){ + const EPasteMode mode = pastemode_for_modifiers( shift, ctrl ); + const bool setShader = pastemode_if_setShader( mode, alt ); + switch ( mode ) + { + default: //case ePasteNone: + return "paintTexture"; + case ePasteValues: + return setShader? "paintTexture,Values,LightPower" : "paintTexDefValues"; + case ePasteSeamless: + return setShader? "paintTextureSeamless,LightColor" : "paintTexDefValuesSeamless"; + case ePasteProject: + return setShader? "projectTexture,LightColor&Power" : "projectTexDefValues"; + } +} + +void Scene_applyClosestTexture( SelectionTest& test, bool shift, bool ctrl, bool alt, bool texturize_selected = false ){ // UndoableCommand command( "facePaintTexture" ); + const EPasteMode mode = pastemode_for_modifiers( shift, ctrl ); + const bool setShader = pastemode_if_setShader( mode, alt ); + if( texturize_selected ){ - if( project ){ - Select_SetShader( TextureBrowser_GetSelectedShader() ); - Select_ProjectTexture( g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_plane.normal() ); - } - else if( !seamless ){ + if( setShader && mode != ePasteSeamless ) Select_SetShader( TextureBrowser_GetSelectedShader() ); + if( mode == ePasteValues ) Select_SetTexdef( g_faceTextureClipboard.m_projection, false, false ); - } + else if( mode == ePasteProject ) + Select_ProjectTexture( g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_plane.normal() ); } - Scene_setClosestTexture( GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader(), g_faceTextureClipboard.m_projection, g_faceTextureClipboard.m_flags, seamless, project ); + Scene_setClosestTexture( GlobalSceneGraph(), test, TextureBrowser_GetSelectedShader(), g_faceTextureClipboard, mode, setShader ); SceneChangeNotify(); }