* support misc_model::_remap facility of q3map2
q3map2: fix inconsistency, introduced in d92c32d453
(_remap result could depend on _remap keys order, e.g. remapping src: moo/rock, moo/sand-rock by: rock, sand-rock suffix matches; rock could be used for moo/sand-rock)
This commit is contained in:
parent
fbbbd2e7d7
commit
7fd32180e2
|
|
@ -50,6 +50,87 @@
|
||||||
|
|
||||||
#include "entity.h"
|
#include "entity.h"
|
||||||
|
|
||||||
|
#include "modelskinkey.h"
|
||||||
|
|
||||||
|
#include "modelskin.h"
|
||||||
|
class RemapKeysObserver : public Entity::Observer, public ModelSkin
|
||||||
|
{
|
||||||
|
class RemapKey
|
||||||
|
{
|
||||||
|
const Callback& m_skinChangedCallback;
|
||||||
|
public:
|
||||||
|
CopiedString m_from;
|
||||||
|
CopiedString m_to;
|
||||||
|
RemapKey( const Callback& skinChangedCallback ) : m_skinChangedCallback( skinChangedCallback ){
|
||||||
|
}
|
||||||
|
void remapKeyChanged( const char* value ){
|
||||||
|
const char* split = strchr( value, ';' );
|
||||||
|
if( split != nullptr ){
|
||||||
|
m_from = { value, split };
|
||||||
|
StringOutputStream stream( 64 );
|
||||||
|
stream << PathCleaned( split + 1 );
|
||||||
|
m_to = stream.c_str();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
m_from = "";
|
||||||
|
m_to = "";
|
||||||
|
}
|
||||||
|
m_skinChangedCallback();
|
||||||
|
}
|
||||||
|
typedef MemberCaller1<RemapKey, const char*, &RemapKey::remapKeyChanged> remapKeyChangedCaller;
|
||||||
|
};
|
||||||
|
typedef std::multimap<CopiedString, RemapKey> RemapKeys;
|
||||||
|
RemapKeys m_remapKeys;
|
||||||
|
const Callback m_skinChangedCallback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RemapKeysObserver() = delete;
|
||||||
|
RemapKeysObserver( const RemapKeysObserver& ) = delete;
|
||||||
|
RemapKeysObserver operator=( const RemapKeysObserver& ) = delete;
|
||||||
|
RemapKeysObserver( const Callback& skinChangedCallback ) : m_skinChangedCallback( skinChangedCallback ){
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert( const char* key, EntityKeyValue& value ) override {
|
||||||
|
if( string_equal_prefix( key, "_remap" ) ){
|
||||||
|
value.attach( RemapKey::remapKeyChangedCaller( m_remapKeys.emplace( key, m_skinChangedCallback )->second ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void erase( const char* key, EntityKeyValue& value ) override {
|
||||||
|
if( string_equal_prefix( key, "_remap" ) ){
|
||||||
|
for( RemapKeys::iterator i = m_remapKeys.find( key ); i != m_remapKeys.end() && string_equal( ( *i ).first.c_str(), key ); ){
|
||||||
|
value.detach( RemapKey::remapKeyChangedCaller( i->second ) );
|
||||||
|
i = m_remapKeys.erase( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach( ModuleObserver& observer ) override {
|
||||||
|
}
|
||||||
|
void detach( ModuleObserver& observer ) override {
|
||||||
|
}
|
||||||
|
bool realised() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const char* getRemap( const char* name ) const override { // this logic is supposed to respect one in q3map2
|
||||||
|
const char* to = "";
|
||||||
|
std::size_t fromlen = 0;
|
||||||
|
for( const auto& pair : m_remapKeys ){
|
||||||
|
const RemapKey& remapKey = pair.second;
|
||||||
|
if( remapKey.m_from == "*" && fromlen == 0 ){ // only globbing, if no respective match
|
||||||
|
to = remapKey.m_to.c_str();
|
||||||
|
}
|
||||||
|
else if( string_equal_suffix_nocase( name, remapKey.m_from.c_str() ) && strlen( remapKey.m_from.c_str() ) > fromlen ){ // longer match has priority
|
||||||
|
to = remapKey.m_to.c_str();
|
||||||
|
fromlen = strlen( remapKey.m_from.c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
void forEachRemap( const SkinRemapCallback& callback ) const override {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const char EXCLUDE_NAME[] = "misc_model";
|
const char EXCLUDE_NAME[] = "misc_model";
|
||||||
|
|
||||||
class MiscModel :
|
class MiscModel :
|
||||||
|
|
@ -57,6 +138,7 @@ class MiscModel :
|
||||||
{
|
{
|
||||||
EntityKeyValues m_entity;
|
EntityKeyValues m_entity;
|
||||||
KeyObserverMap m_keyObservers;
|
KeyObserverMap m_keyObservers;
|
||||||
|
RemapKeysObserver m_remapKeysObserver;
|
||||||
MatrixTransform m_transform;
|
MatrixTransform m_transform;
|
||||||
|
|
||||||
OriginKey m_originKey;
|
OriginKey m_originKey;
|
||||||
|
|
@ -114,10 +196,20 @@ void scaleChanged(){
|
||||||
updateTransform();
|
updateTransform();
|
||||||
}
|
}
|
||||||
typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
|
typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
|
||||||
|
|
||||||
|
void skinChanged(){
|
||||||
|
scene::Node* node = m_model.getNode();
|
||||||
|
if ( node != 0 ) {
|
||||||
|
Node_modelSkinChanged( *node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typedef MemberCaller<MiscModel, &MiscModel::skinChanged> SkinChangedCaller;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MiscModel( EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
|
MiscModel( EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
|
||||||
m_entity( eclass ),
|
m_entity( eclass ),
|
||||||
|
m_remapKeysObserver( SkinChangedCaller( *this ) ),
|
||||||
m_originKey( OriginChangedCaller( *this ) ),
|
m_originKey( OriginChangedCaller( *this ) ),
|
||||||
m_origin( ORIGINKEY_IDENTITY ),
|
m_origin( ORIGINKEY_IDENTITY ),
|
||||||
m_anglesKey( AnglesChangedCaller( *this ) ),
|
m_anglesKey( AnglesChangedCaller( *this ) ),
|
||||||
|
|
@ -134,6 +226,7 @@ MiscModel( EntityClass* eclass, scene::Node& node, const Callback& transformChan
|
||||||
}
|
}
|
||||||
MiscModel( const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
|
MiscModel( const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
|
||||||
m_entity( other.m_entity ),
|
m_entity( other.m_entity ),
|
||||||
|
m_remapKeysObserver( SkinChangedCaller( *this ) ),
|
||||||
m_originKey( OriginChangedCaller( *this ) ),
|
m_originKey( OriginChangedCaller( *this ) ),
|
||||||
m_origin( ORIGINKEY_IDENTITY ),
|
m_origin( ORIGINKEY_IDENTITY ),
|
||||||
m_anglesKey( AnglesChangedCaller( *this ) ),
|
m_anglesKey( AnglesChangedCaller( *this ) ),
|
||||||
|
|
@ -155,10 +248,12 @@ void instanceAttach( const scene::Path& path ){
|
||||||
m_filter.instanceAttach();
|
m_filter.instanceAttach();
|
||||||
m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
|
m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
|
||||||
m_entity.attach( m_keyObservers );
|
m_entity.attach( m_keyObservers );
|
||||||
|
m_entity.attach( m_remapKeysObserver );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void instanceDetach( const scene::Path& path ){
|
void instanceDetach( const scene::Path& path ){
|
||||||
if ( --m_instanceCounter.m_count == 0 ) {
|
if ( --m_instanceCounter.m_count == 0 ) {
|
||||||
|
m_entity.detach( m_remapKeysObserver );
|
||||||
m_entity.detach( m_keyObservers );
|
m_entity.detach( m_keyObservers );
|
||||||
m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
|
m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
|
||||||
m_filter.instanceDetach();
|
m_filter.instanceDetach();
|
||||||
|
|
@ -184,6 +279,9 @@ Nameable& getNameable(){
|
||||||
TransformNode& getTransformNode(){
|
TransformNode& getTransformNode(){
|
||||||
return m_transform;
|
return m_transform;
|
||||||
}
|
}
|
||||||
|
ModelSkin& getModelSkin(){
|
||||||
|
return m_remapKeysObserver;
|
||||||
|
}
|
||||||
|
|
||||||
void attach( scene::Traversable::Observer* observer ){
|
void attach( scene::Traversable::Observer* observer ){
|
||||||
m_model.attach( observer );
|
m_model.attach( observer );
|
||||||
|
|
@ -328,6 +426,7 @@ TypeCasts(){
|
||||||
NodeContainedCast<MiscModelNode, Entity>::install( m_casts );
|
NodeContainedCast<MiscModelNode, Entity>::install( m_casts );
|
||||||
NodeContainedCast<MiscModelNode, Nameable>::install( m_casts );
|
NodeContainedCast<MiscModelNode, Nameable>::install( m_casts );
|
||||||
NodeContainedCast<MiscModelNode, Namespaced>::install( m_casts );
|
NodeContainedCast<MiscModelNode, Namespaced>::install( m_casts );
|
||||||
|
NodeContainedCast<MiscModelNode, ModelSkin>::install( m_casts );
|
||||||
}
|
}
|
||||||
NodeTypeCastTable& get(){
|
NodeTypeCastTable& get(){
|
||||||
return m_casts;
|
return m_casts;
|
||||||
|
|
@ -367,6 +466,9 @@ Nameable& get( NullType<Nameable>){
|
||||||
Namespaced& get( NullType<Namespaced>){
|
Namespaced& get( NullType<Namespaced>){
|
||||||
return m_contained.getNamespaced();
|
return m_contained.getNamespaced();
|
||||||
}
|
}
|
||||||
|
ModelSkin& get( NullType<ModelSkin>){
|
||||||
|
return m_contained.getModelSkin();
|
||||||
|
}
|
||||||
|
|
||||||
MiscModelNode( EntityClass* eclass ) :
|
MiscModelNode( EntityClass* eclass ) :
|
||||||
m_node( this, this, StaticTypeCasts::instance().get() ),
|
m_node( this, this, StaticTypeCasts::instance().get() ),
|
||||||
|
|
|
||||||
|
|
@ -218,12 +218,11 @@ void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap
|
||||||
shaderInfo_t *si;
|
shaderInfo_t *si;
|
||||||
mapDrawSurface_t *ds;
|
mapDrawSurface_t *ds;
|
||||||
bspDrawVert_t *dv;
|
bspDrawVert_t *dv;
|
||||||
char *picoShaderName;
|
const char *picoShaderName;
|
||||||
char shaderName[ MAX_QPATH ];
|
char shaderName[ MAX_QPATH ];
|
||||||
picoVec_t *xyz, *normal, *st;
|
picoVec_t *xyz, *normal, *st;
|
||||||
byte *color;
|
byte *color;
|
||||||
picoIndex_t *indexes;
|
picoIndex_t *indexes;
|
||||||
remap_t *rm, *rmto, *glob;
|
|
||||||
skinfile_t *sf, *sf2;
|
skinfile_t *sf, *sf2;
|
||||||
char skinfilename[ MAX_QPATH ];
|
char skinfilename[ MAX_QPATH ];
|
||||||
char *skinfilecontent;
|
char *skinfilecontent;
|
||||||
|
|
@ -371,25 +370,23 @@ void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle shader remapping */
|
/* handle shader remapping */
|
||||||
glob = rmto = NULL;
|
|
||||||
for ( rm = remap; rm != NULL; rm = rm->next )
|
|
||||||
{
|
{
|
||||||
if ( strEqual( rm->from, "*" ) ) {
|
const char* to = NULL;
|
||||||
glob = rm;
|
size_t fromlen = 0;
|
||||||
|
for ( remap_t *rm = remap; rm != NULL; rm = rm->next )
|
||||||
|
{
|
||||||
|
if ( strEqual( rm->from, "*" ) && fromlen == 0 ) { // only globbing, if no respective match
|
||||||
|
to = rm->to;
|
||||||
}
|
}
|
||||||
else if( striEqualSuffix( picoShaderName, rm->from ) ){
|
else if( striEqualSuffix( picoShaderName, rm->from ) && strlen( rm->from ) > fromlen ){ // longer match has priority
|
||||||
rmto = rm;
|
to = rm->to;
|
||||||
if( striEqual( picoShaderName, rm->from ) ) // exact match priority
|
fromlen = strlen( rm->from );
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( rmto != NULL ){
|
if( to != NULL ){
|
||||||
Sys_FPrintf( SYS_VRB, "Remapping '%s' to '%s'\n", picoShaderName, rmto->to );
|
Sys_FPrintf( SYS_VRB, ( fromlen == 0? "Globbing '%s' to '%s'\n" : "Remapping '%s' to '%s'\n" ), picoShaderName, to );
|
||||||
picoShaderName = rmto->to;
|
picoShaderName = to;
|
||||||
}
|
}
|
||||||
else if ( glob != NULL ) {
|
|
||||||
Sys_FPrintf( SYS_VRB, "Globbing '%s' to '%s'\n", picoShaderName, glob->to );
|
|
||||||
picoShaderName = glob->to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shader renaming for sof2 */
|
/* shader renaming for sof2 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user