/* * psmeshutil.cpp * * Copyright (C) 2005 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program 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 (version 2 of the License) * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include "util/psmeshutil.h" #include "util/psstring.h" #include "util/log.h" #include #include #include #include #include #include #include #include #include #include #include #include #include psMeshUtil::psMeshUtil(iObjectRegistry *obj_reg) { engine = CS_QUERY_REGISTRY (obj_reg, iEngine); loader = CS_QUERY_REGISTRY (obj_reg, iLoader); vfs = CS_QUERY_REGISTRY (obj_reg, iVFS); g3d = CS_QUERY_REGISTRY (obj_reg, iGraphics3D); txtmgr = g3d->GetTextureManager(); } iMaterialWrapper* psMeshUtil::LoadMaterial(const char* name, const char* texture, iRegion* region) { if (!name || !texture) return NULL; iMaterialWrapper* mat_wrapper = engine->FindMaterial(name); if ( mat_wrapper ) return mat_wrapper; // Check to see if we even have this texture if ( !vfs->Exists(texture) ) return NULL; csRef th = loader->LoadTexture(texture); iTextureList *txlist = engine->GetTextureList(); if ( !th || !txlist ) return NULL; // Add the texture to the engine's list of textures iTextureWrapper* tex_wrapper = txlist->NewTexture(th); if ( !tex_wrapper ) return NULL; // Create the material and register it with the engine mat_wrapper = engine->CreateMaterial(name,tex_wrapper); if (region && mat_wrapper) region->Add(mat_wrapper->QueryObject()); return mat_wrapper; } csString psMeshUtil::ParseStrings(iMeshWrapper* mesh, const char * part, const char* str) const { psString result(str); const char* factname = mesh->GetFactory()->QueryObject()->GetName(); result.ReplaceAllSubString("$F",factname); result.ReplaceAllSubString("$P",part); return result; } bool psMeshUtil::ChangeMaterial( iMeshWrapper* mesh, const char* part, const char* meshName, const char* textureName ) { if (!mesh || !part || !meshName || !textureName) return false; csRef state = SCF_QUERY_INTERFACE( mesh->GetMeshObject(), iSpriteCal3DState ); if ( !state ) return false; csString meshNameParsed = ParseStrings(mesh, part, meshName); csString textureNameParsed = ParseStrings(mesh, part, textureName); iMaterialWrapper* material = LoadMaterial( meshNameParsed, textureNameParsed ); if ( !material ) { // Not necisarily an error; this texture may just not exist for this character, yet Notify3(LOG_CHARACTER,"Failed to load texture \"%s\" for part \"%s\"",textureNameParsed.GetData(),part); return false; } if ( !state->SetMaterial(part,material) ) { csString left,right; left.Format("Left %s",part); right.Format("Right %s",part); // Try mirroring if ( !state->SetMaterial(left,material) || !state->SetMaterial(right,material) ) { Error3("Failed to set material \"%s\" on part \"%s\"",meshNameParsed.GetData(),part); return false; } } return true; } bool psMeshUtil::DefaultMaterial( iMeshWrapper* mesh, const char* part ) { if (!mesh || !part) return false; csRef state = SCF_QUERY_INTERFACE( mesh->GetMeshObject()->GetFactory(), iSpriteCal3DFactoryState ); if ( !state ) return false; const char* materialName = state->GetDefaultMaterial( part ); if (materialName) { return ChangeMaterial( mesh, part, materialName, materialName ); } else // Try mirroring { csString left,right; left.Format("Left %s",part); right.Format("Right %s",part); const char* leftMaterialName = state->GetDefaultMaterial( left ); const char* rightMaterialName = state->GetDefaultMaterial( right ); bool L = ChangeMaterial( mesh, left, leftMaterialName, leftMaterialName ); bool R = ChangeMaterial( mesh, right, rightMaterialName, rightMaterialName ); return (L && R); } } bool psMeshUtil::ChangeMesh( iMeshWrapper* mesh, const char* partPattern, const char* newPart) { csRef statefac = SCF_QUERY_INTERFACE( mesh->GetMeshObject()->GetFactory(), iSpriteCal3DFactoryState ); if ( !statefac ) { return false; } csRef state = SCF_QUERY_INTERFACE(mesh->GetMeshObject(), iSpriteCal3DState); if ( !state ) { return false; } csString newPartParsed = ParseStrings(mesh, partPattern, newPart); // If the new mesh cannot be found then do nothing. int newMeshAvailable = statefac->FindMeshName(newPartParsed); if ( newMeshAvailable == -1 ) return false; /* First we detach every mesh that match the partPattern */ for (int idx=0; idx < statefac->GetMeshCount(); idx++) { const char * meshName = statefac->GetMeshName( idx ); if (strstr(meshName,partPattern)) { state->DetachCoreMesh( meshName ); } } state->AttachCoreMesh( newPartParsed ); return true; } bool psMeshUtil::DefaultMesh( iMeshWrapper* mesh, const char* partPattern ) { csRef statefac = SCF_QUERY_INTERFACE( mesh->GetMeshObject()->GetFactory(), iSpriteCal3DFactoryState ); if ( !statefac ) { return false; } csRef state = SCF_QUERY_INTERFACE(mesh->GetMeshObject(), iSpriteCal3DState); if ( !state ) { return false; } const char * defaultPart = NULL; /* First we detach every mesh that match the partPattern */ for (int idx=0; idx < statefac->GetMeshCount(); idx++) { const char * meshName = statefac->GetMeshName( idx ); if (strstr(meshName,partPattern)) { state->DetachCoreMesh( meshName ); if (statefac->IsMeshDefault(idx)) { defaultPart = meshName; } } } if (!defaultPart) { return false; } state->AttachCoreMesh( defaultPart ); return true; } bool psMeshUtil::Attach( iMeshWrapper* mesh, const char* socketName, const char* meshFactName ) { if (!mesh || !socketName || !meshFactName) return false; csRef state = SCF_QUERY_INTERFACE( mesh->GetMeshObject(), iSpriteCal3DState ); if ( !state ) return false; csRef socket = state->FindSocket( socketName ); if ( !socket ) { Notify2(LOG_CHARACTER, "Socket %s not found.", socketName ); return false; } csRef factory = engine->GetMeshFactories()->FindByName (meshFactName); if ( !factory ) { Error2("Mesh Factory %s not found", meshFactName ); return false; } csRef meshWrap = engine->CreateMeshWrapper( factory, meshFactName ); // Given a socket name of "righthand", we're looking for a key in the form of "socket_righthand" char * keyName = (char *)malloc(strlen(socketName)+strlen("socket_")+1); strcpy(keyName,"socket_"); strcat(keyName,socketName); // Variables for transform to be specified float trans_x = 0, trans_y = 0.0, trans_z = 0, rot_x = -PI/2, rot_y = 0, rot_z = 0; csRef it = factory->QueryObject()->GetIterator(); while ( it->HasNext() ) { csRef key (SCF_QUERY_INTERFACE (it->Next(), iKeyValuePair)); if (key && strcmp(key->GetKey(),keyName) == 0) { sscanf(key->GetValue(),"%f,%f,%f,%f,%f,%f",&trans_x,&trans_y,&trans_z,&rot_x,&rot_y,&rot_z); } } free(keyName); keyName = NULL; meshWrap->QuerySceneNode()->SetParent( mesh->QuerySceneNode ()); socket->SetMeshWrapper( meshWrap ); socket->SetTransform( csTransform(csZRotMatrix3(rot_z)*csYRotMatrix3(rot_y)*csXRotMatrix3(rot_x), csVector3(trans_x,trans_y,trans_z)) ); return true; } bool psMeshUtil::Detach( iMeshWrapper* mesh, const char* socketName ) { if (!mesh || !socketName) return false; csRef state = SCF_QUERY_INTERFACE( mesh->GetMeshObject(), iSpriteCal3DState ); if ( !state ) return false; csRef socket = state->FindSocket( socketName ); if ( !socket ) { Notify2(LOG_CHARACTER, "Socket %s not found.", socketName ); return false; } csRef meshWrap = socket->GetMeshWrapper(); if ( !meshWrap ) { Notify2(LOG_CHARACTER, "No mesh in socket: %s.", socketName ); } else { meshWrap->QuerySceneNode ()->SetParent (0); socket->SetMeshWrapper( NULL ); engine->RemoveObject( meshWrap ); } return true; }