* 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:
Garux 2020-03-25 11:53:14 +03:00
parent fbbbd2e7d7
commit 7fd32180e2
2 changed files with 117 additions and 18 deletions

View File

@ -50,6 +50,87 @@
#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";
class MiscModel :
@ -57,6 +138,7 @@ class MiscModel :
{
EntityKeyValues m_entity;
KeyObserverMap m_keyObservers;
RemapKeysObserver m_remapKeysObserver;
MatrixTransform m_transform;
OriginKey m_originKey;
@ -114,10 +196,20 @@ void scaleChanged(){
updateTransform();
}
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:
MiscModel( EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
m_entity( eclass ),
m_remapKeysObserver( SkinChangedCaller( *this ) ),
m_originKey( OriginChangedCaller( *this ) ),
m_origin( ORIGINKEY_IDENTITY ),
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 ) :
m_entity( other.m_entity ),
m_remapKeysObserver( SkinChangedCaller( *this ) ),
m_originKey( OriginChangedCaller( *this ) ),
m_origin( ORIGINKEY_IDENTITY ),
m_anglesKey( AnglesChangedCaller( *this ) ),
@ -155,10 +248,12 @@ void instanceAttach( const scene::Path& path ){
m_filter.instanceAttach();
m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
m_entity.attach( m_keyObservers );
m_entity.attach( m_remapKeysObserver );
}
}
void instanceDetach( const scene::Path& path ){
if ( --m_instanceCounter.m_count == 0 ) {
m_entity.detach( m_remapKeysObserver );
m_entity.detach( m_keyObservers );
m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
m_filter.instanceDetach();
@ -184,6 +279,9 @@ Nameable& getNameable(){
TransformNode& getTransformNode(){
return m_transform;
}
ModelSkin& getModelSkin(){
return m_remapKeysObserver;
}
void attach( scene::Traversable::Observer* observer ){
m_model.attach( observer );
@ -328,6 +426,7 @@ TypeCasts(){
NodeContainedCast<MiscModelNode, Entity>::install( m_casts );
NodeContainedCast<MiscModelNode, Nameable>::install( m_casts );
NodeContainedCast<MiscModelNode, Namespaced>::install( m_casts );
NodeContainedCast<MiscModelNode, ModelSkin>::install( m_casts );
}
NodeTypeCastTable& get(){
return m_casts;
@ -367,6 +466,9 @@ Nameable& get( NullType<Nameable>){
Namespaced& get( NullType<Namespaced>){
return m_contained.getNamespaced();
}
ModelSkin& get( NullType<ModelSkin>){
return m_contained.getModelSkin();
}
MiscModelNode( EntityClass* eclass ) :
m_node( this, this, StaticTypeCasts::instance().get() ),

View File

@ -218,12 +218,11 @@ void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap
shaderInfo_t *si;
mapDrawSurface_t *ds;
bspDrawVert_t *dv;
char *picoShaderName;
const char *picoShaderName;
char shaderName[ MAX_QPATH ];
picoVec_t *xyz, *normal, *st;
byte *color;
picoIndex_t *indexes;
remap_t *rm, *rmto, *glob;
skinfile_t *sf, *sf2;
char skinfilename[ MAX_QPATH ];
char *skinfilecontent;
@ -371,26 +370,24 @@ void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap
}
/* handle shader remapping */
glob = rmto = NULL;
for ( rm = remap; rm != NULL; rm = rm->next )
{
if ( strEqual( rm->from, "*" ) ) {
glob = rm;
const char* to = NULL;
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 ) && strlen( rm->from ) > fromlen ){ // longer match has priority
to = rm->to;
fromlen = strlen( rm->from );
}
}
else if( striEqualSuffix( picoShaderName, rm->from ) ){
rmto = rm;
if( striEqual( picoShaderName, rm->from ) ) // exact match priority
break;
if( to != NULL ){
Sys_FPrintf( SYS_VRB, ( fromlen == 0? "Globbing '%s' to '%s'\n" : "Remapping '%s' to '%s'\n" ), picoShaderName, to );
picoShaderName = to;
}
}
if( rmto != NULL ){
Sys_FPrintf( SYS_VRB, "Remapping '%s' to '%s'\n", picoShaderName, rmto->to );
picoShaderName = rmto->to;
}
else if ( glob != NULL ) {
Sys_FPrintf( SYS_VRB, "Globbing '%s' to '%s'\n", picoShaderName, glob->to );
picoShaderName = glob->to;
}
/* shader renaming for sof2 */
if ( renameModelShaders ) {