GameOptionsMenu::GameOptionsMenu(SMenuConfig* menuConfig) : title("Options de la partie", TITLEFONT, 30), category(TITLEFONT, 100), cancel("Annuler", 550, CREATEGAMEMENU), save("Valider", 550, CREATEGAMEMENU), menuConfig(menuConfig) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); category.push_back("Bonus de bombe"); category.push_back("Bonus de personnage"); category.push_back("Infections"); cancel.move(-100, 0); save.move(100, 0); cancel.setSelected(true); cancel.setNext(&save); save.setNext(&cancel); this->widgets.push_back(&title); this->widgets.push_back(&category); this->widgets.push_back(&cancel); this->widgets.push_back(&save); initBonus(); }
void GraphicsConfigMenu::validPressed(EMenuScreen* nextScreen) { ISkin* skin = PolyBomberApp::getISkin(); if (cancel.getSelected()) { skin->reloadConfig(); *nextScreen = cancel.activate(); } if (save.getSelected()) { if (window->canFullScreen()) { window->setFullScreen(fullscreen.getCurrentItem()); IConfigFile* configFile = new ConfigFileManager(); configFile->setIntValue("window.fullscreen.enabled", fullscreen.getCurrentItem()); delete configFile; } skin->saveConfig(); *nextScreen = save.activate(); } }
void GameOptionsMenu::initBonus() { ISkin* skin = PolyBomberApp::getISkin(); EImage icones[18] = {EIMAGE_BOMBPLUS, EIMAGE_BOMBMOINS, EIMAGE_RANGEPLUS, EIMAGE_RANGEMOINS, EIMAGE_RANGEMAX, EIMAGE_MINEBONUS, EIMAGE_INFINITY, EIMAGE_ATOMIC, EIMAGE_VITESSEPLUS, EIMAGE_VITESSEMOINS, EIMAGE_BOMBLINE, EIMAGE_REMOTEBONUS, EIMAGE_CRANE, EIMAGE_HELL, EIMAGE_CONFUSION, EIMAGE_SPASME, EIMAGE_DILATATION, EIMAGE_RAGE}; int i; for (i=0; i<18; i++) { int j = i; if (i >= 12) j -= 12; else if (i >= 8) j -= 8; this->images[i] = new ImageWidget(); this->images[i]->setImage(skin->loadImage(icones[i])); this->images[i]->setPosition(300,200+40*j); this->bonus[i] = new SelectionWidget(TEXTFONT, 200 + 40*j); this->bonus[i]->push_back("0"); this->bonus[i]->push_back("1"); this->bonus[i]->push_back("2"); this->bonus[i]->push_back("3"); this->bonus[i]->push_back("4"); this->bonus[i]->push_back("5"); this->bonus[i]->push_back("6"); this->bonus[i]->push_back("7"); this->bonus[i]->push_back("8"); this->bonus[i]->push_back("9"); this->bonus[i]->push_back("10"); this->bonus[i]->setCurrentItem(this->menuConfig->gameConfig.nbBonus[i]); this->bonus[i]->move(70, 0); if (j > 0) this->bonus[i]->setPrevious(this->bonus[i-1]); else this->bonus[i]->setPrevious(&category); this->widgets.push_back(this->images[i]); this->widgets.push_back(this->bonus[i]); } for (i=0; i<7; i++) this->bonus[i]->setNext(this->bonus[i+1]); for (i=8; i<11; i++) this->bonus[i]->setNext(this->bonus[i+1]); for (i=12; i<17; i++) this->bonus[i]->setNext(this->bonus[i+1]); this->bonus[7]->setNext(&cancel); this->bonus[11]->setNext(&cancel); this->bonus[17]->setNext(&cancel); setCategory(); }
//// FindSkinModifier /////////////////////////////////////////////////////// // Given an INode, gets the ISkin object of that node, or nil if there is // none. Taken from the Max4 SDK, ISkin.h ISkin* plMaxNodeBase::FindSkinModifier() { int modStackIndex; // Get object from node. Abort if no object. Object *pObj = GetObjectRef(); if( pObj == nil ) return nil; // Is derived object ? while( pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID ) { IDerivedObject *pDerObj = (IDerivedObject *)pObj; // Iterate over all entries of the modifier stack. for( modStackIndex = 0; modStackIndex < pDerObj->NumModifiers(); modStackIndex++ ) { // Get current modifier. Modifier *mod = pDerObj->GetModifier( modStackIndex ); // Is this Skin ? if( mod->ClassID() == SKIN_CLASSID ) { ISkin* skin = (ISkin*)mod->GetInterface(I_SKIN); if( skin->GetNumBones() > 0 ) return skin; } } pObj = pDerObj->GetObjRef(); } // Not found. return nil; }
EMenuScreen GraphicsConfigMenu::run(MainWindow& window, EMenuScreen previous) { this->window = &window; // Configuration plein ecran fullscreen.setCurrentItem(window.getFullScreen()); if (window.canFullScreen()) { skinList.setPrevious(&fullscreen); this->widgets.push_back(&fullscreen); } else this->widgets.push_back(&noFullscreen); // Mise à jour du skin ISkin* skin = PolyBomberApp::getISkin(); std::vector<std::string> skins = skin->getSkinsList(); for (unsigned int i=0; i<skins.size(); i++) { if (skin->getSkin().compare(skins[i]) == 0) skinList.setCurrentItem(i); } return IMenuScreen::run(window, previous); }
ScoreMenu::ScoreMenu(SMenuConfig* menuConfig) : title("Score de la partie", TITLEFONT, 100), winner("Le joueur i a gagne !", TEXTFONT, 170), back("Retour au menu", 550, MAINMENU), menuConfig(menuConfig) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); winner.setColor(skin->getColor(TEXTCOLOR)); back.setSelected(true); this->widgets.push_back(&title); this->widgets.push_back(&winner); this->widgets.push_back(&back); for (int i=0; i<4; i++) { this->pictures[i] = new ImageWidget(); this->pictures[i]->setPosition(300, 250 + 60*i); this->pictures[i]->setImage(skin->loadImage((EImage)(PLAYER1 + i))); this->names[i] = new TextWidget("", TEXTFONT, 250 + 60*i); this->names[i]->setColor(skin->getColor(TEXTCOLOR)); this->widgets.push_back(this->pictures[i]); this->widgets.push_back(this->names[i]); } }
void GraphicsConfigMenu::rightPressed() { ISkin* skin = PolyBomberApp::getISkin(); std::vector<std::string> skins = skin->getSkinsList(); cancel.goNext(); fullscreen.goNextItem(); skinList.goNextItem(); skin->setSkin(skins[skinList.getCurrentItem()]); }
//--------------------------------------------------------------- bool SkinController::isSkinController( Modifier * modifier ) { Class_ID classId = modifier->ClassID(); if (classId == SKIN_CLASSID) { ISkin* skin = (ISkin*) modifier->GetInterface(I_SKIN); if ( !skin) return false; return skin->GetNumBonesFlat() > 0; } else return (classId == PHYSIQUE_CLASSID) != false; return false; }
ControllersConfigMenu::ControllersConfigMenu() : title("Configuration des controleurs", TITLEFONT, 100), error("Aucun controleur detecte", TEXTFONT, 200), cancel("Retour", 500, CONFIGMENU) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); error.setColor(skin->getColor(ERRORCOLOR)); this->widgets.push_back(&title); this->widgets.push_back(&error); this->widgets.push_back(&cancel); error.setVisible(false); for (int i=0; i<4; i++) { std::ostringstream text; text << "Joueur " << i+1 << " : "; playerText[i] = new TextWidget(text.str(), TEXTFONT, 250 + 50*i); playerText[i]->setColor(skin->getColor(TEXTCOLOR)); playerText[i]->move(-100, 0); playerController[i] = new SelectionWidget(LINKFONT, 250 + 50*i); playerController[i]->push_back("Gamepad"); playerController[i]->push_back("Clavier"); playerController[i]->push_back("Wii"); playerController[i]->move(100, 0); if (i > 0) playerController[i]->setPrevious(playerController[i-1]); this->widgets.push_back(playerText[i]); this->widgets.push_back(playerController[i]); } playerController[0]->setNext(playerController[1]); playerController[1]->setNext(playerController[2]); playerController[2]->setNext(playerController[3]); playerController[3]->setNext(&cancel); cancel.setPrevious(playerController[3]); cancel.setSelected(true); }
WaitingMenu::WaitingMenu(SMenuConfig* menuConfig) : title("Resume de la partie", TITLEFONT, 50), ip("Adresse IP du serveur : ", TEXTFONT, 150), cancel("Annuler", 500, GAMEMENU), start("Jouer !", 500, RUNGAME), menuConfig(menuConfig) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); ip.setColor(skin->getColor(TEXTCOLOR)); this->network = PolyBomberApp::getINetworkToMenu(); ip.setString(ip.getString() + this->network->getIpAddress()); ip.move(-80, 0); cancel.move(-100, 0); start.move(100, 0); cancel.setSelected(true); cancel.setNext(&start); start.setNext(&cancel); this->widgets.push_back(&title); this->widgets.push_back(&ip); this->widgets.push_back(&cancel); this->widgets.push_back(&start); for (int i=0; i<4; i++) { this->pictures[i] = new ImageWidget(); this->pictures[i]->setPosition(300, 200 + 60*i); this->pictures[i]->setImage(skin->loadImage((EImage)(PLAYER1 + i))); this->names[i] = new TextWidget("...", TEXTFONT, 210 + 60*i); this->names[i]->setColor(skin->getColor(TEXTCOLOR)); this->names[i]->move(100, 0); this->widgets.push_back(this->pictures[i]); this->widgets.push_back(this->names[i]); } }
InputWidget::InputWidget(ETextFont font, unsigned int y, ETextPosition position, unsigned int width) : ClickableWidget(), text("", font, 0, LEFT), maxLength(10), WIDTH(800) { ISkin* skin = PolyBomberApp::getISkin(); area.setSize(sf::Vector2f(width, 35)); area.setFillColor(skin->getColor(BGCOLOR)); area.setOutlineColor(skin->getColor(TEXTCOLOR)); area.setOutlineThickness(3); text.setPosition(5, 5); text.setColor(skin->getColor(TEXTCOLOR)); if (position == RIGHT) setPosition(this->WIDTH - width, y); else if (position == CENTER) setPosition(this->WIDTH/2 - (width)/2, y); }
SelectSlotsMenu::SelectSlotsMenu(SMenuConfig* menuConfig) : title("Creation d'une partie", TITLEFONT, 100), error("Pas assez de place sur le serveur", TEXTFONT, 300), nbPlayersText("Nombre de joueurs sur cet ordinateur :", TEXTFONT, 250), nbPlayers(TEXTFONT, 300), cancel("Annuler", 450, GAMEMENU), next("Valider", 450, SELECTNAMEMENU), menuConfig(menuConfig) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); error.setColor(skin->getColor(ERRORCOLOR)); nbPlayersText.setColor(skin->getColor(TEXTCOLOR)); cancel.move(-100, 0); next.move(100, 0); nbPlayers.push_back("1"); nbPlayers.setCurrentItem(0); error.setVisible(false); cancel.setSelected(true); nbPlayers.setNext(&cancel); cancel.setPrevious(&nbPlayers); next.setPrevious(&nbPlayers); cancel.setNext(&next); next.setNext(&cancel); this->widgets.push_back(&title); this->widgets.push_back(&error); this->widgets.push_back(&nbPlayersText); this->widgets.push_back(&nbPlayers); this->widgets.push_back(&cancel); this->widgets.push_back(&next); this->network = PolyBomberApp::getINetworkToMenu(); }
GraphicsConfigMenu::GraphicsConfigMenu() : title("Configuration graphique", TITLEFONT, 100), textFullscreen("Mode plein-ecran : ", TEXTFONT, 200), fullscreen(TEXTFONT, 200), noFullscreen("Indisponible", ERRORFONT, 200), skinText("Skin choisi :", TEXTFONT, 300), skinList(TEXTFONT, 350), cancel("Annuler", 450, CONFIGMENU), save("Valider", 450, CONFIGMENU) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); skinText.setColor(skin->getColor(TEXTCOLOR)); textFullscreen.setColor(skin->getColor(TEXTCOLOR)); // Mode plein ecran textFullscreen.move(-100, 0); fullscreen.push_back("non"); fullscreen.push_back("oui"); fullscreen.move(100, 0); noFullscreen.setColor(skin->getColor(ERRORCOLOR)); noFullscreen.move(100, 0); // Liste des skins std::vector<std::string> skins = skin->getSkinsList(); for (unsigned int i=0; i<skins.size(); i++) skinList.push_back(skins[i]); cancel.move(-100, 0); save.move(100, 0); cancel.setSelected(true); fullscreen.setNext(&skinList); skinList.setNext(&cancel); cancel.setPrevious(&skinList); cancel.setNext(&save); save.setPrevious(&skinList); save.setNext(&cancel); this->widgets.push_back(&title); this->widgets.push_back(&textFullscreen); this->widgets.push_back(&skinText); this->widgets.push_back(&skinList); this->widgets.push_back(&cancel); this->widgets.push_back(&save); this->window = NULL; }
void InputWidget::setSelected(bool selected) { ISkin* skin = PolyBomberApp::getISkin(); ClickableWidget::setSelected(selected); if (selected) { area.setFillColor(skin->getColor(SELECTEDBGCOLOR)); area.setOutlineColor(skin->getColor(SELECTEDCOLOR)); text.setColor(skin->getColor(SELECTEDCOLOR)); } else { area.setFillColor(skin->getColor(BGCOLOR)); area.setOutlineColor(skin->getColor(TEXTCOLOR)); text.setColor(skin->getColor(TEXTCOLOR)); } }
CVertexCandidate *CMaxMesh::GetVertexCandidate(CSkeletonCandidate *pSkeletonCandidate, int faceId, int faceVertexId) { // check for valid mesh and physique modifier if((m_pIMesh == 0)) { theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__); return 0; } // check if face id is valid if((faceId < 0) || (faceId >= m_pIMesh->getNumFaces())) { theExporter.SetLastError("Invalid face id found.", __FILE__, __LINE__); return 0; } // check if face vertex id is valid if((faceVertexId < 0) || (faceVertexId >= 3)) { theExporter.SetLastError("Invalid face vertex id found.", __FILE__, __LINE__); return 0; } // allocate a new vertex candidate CVertexCandidate *pVertexCandidate; pVertexCandidate = new CVertexCandidate(); if(pVertexCandidate == 0) { theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__); return 0; } // create the new vertex candidate if(!pVertexCandidate->Create()) { delete pVertexCandidate; return 0; } // get vertex id int vertexId; vertexId = m_pIMesh->faces[faceId].v[faceVertexId]; // get the absolute vertex position Point3 vertex; vertex = m_pIMesh->getVert(vertexId) * m_tm; // set the vertex candidate position pVertexCandidate->SetPosition(vertex.x, vertex.y, vertex.z); pVertexCandidate->SetUniqueId(vertexId); // get the absolute vertex normal Point3 normal; normal = GetVertexNormal(faceId, vertexId); normal = normal * Inverse(Transpose(m_tm)); normal = normal.Normalize(); // set the vertex candidate normal pVertexCandidate->SetNormal(normal.x, normal.y, normal.z); if(m_pIMesh->numCVerts > 0) { VertColor vc; vc = m_pIMesh->vertCol[m_pIMesh->vcFace[faceId].t[faceVertexId]]; CalVector vcCal(vc.x, vc.y, vc.z); pVertexCandidate->SetVertColor(vcCal); } // get the vertex weight array float *pVertexWeights; pVertexWeights = m_pIMesh->getVertexWeights(); //if( pVertexWeights == NULL ) { // delete pVertexCandidate; // theExporter.SetLastError("Mesh has no vertex weights", __FILE__, __LINE__); // return 0; //} // get the vertex weight (if possible) float weight; if(pVertexWeights != 0) { weight = pVertexWeights[vertexId]; } else { weight = 0.0f; } // another 3ds max weird behaviour: // zero out epsilon weights if(weight < 0.0005f) weight = 0.0f; // set the vertex candidate weight pVertexCandidate->SetPhysicalProperty(weight); // get the material id of the face int materialId; materialId = GetFaceMaterialId(faceId); if((materialId < 0) || (materialId >= (int)m_vectorStdMat.size())) { delete pVertexCandidate; theExporter.SetLastError("Invalid material id found.", __FILE__, __LINE__); return 0; } // get the material of the face StdMat *pStdMat; pStdMat = m_vectorStdMat[materialId]; // loop through all the mapping channels and extract texture coordinates int mapId; for(mapId = 0; mapId < pStdMat->NumSubTexmaps(); mapId++) { // get texture map Texmap *pTexMap; pTexMap = pStdMat->GetSubTexmap(mapId); // check if map is valid if((pTexMap != 0) && (pStdMat->MapEnabled(mapId))) { // get the mapping channel int channel; channel = pTexMap->GetMapChannel(); bool bValidUV; bValidUV = false; // extract the texture coordinate UVVert uvVert; if(m_pIMesh->mapSupport(channel)) { TVFace *pTVFace; pTVFace = m_pIMesh->mapFaces(channel); UVVert *pUVVert; pUVVert = m_pIMesh->mapVerts(channel); uvVert = pUVVert[pTVFace[faceId].t[faceVertexId]]; bValidUV = true; } else if(m_pIMesh->numTVerts > 0) { uvVert = m_pIMesh->tVerts[m_pIMesh->tvFace[faceId].t[faceVertexId]]; bValidUV = true; } // if we found valid texture coordinates, add them to the vertex candidate if(bValidUV) { // apply a possible uv generator StdUVGen *pStdUVGen; pStdUVGen = (StdUVGen *)pTexMap->GetTheUVGen(); if(pStdUVGen != 0) { Matrix3 tmUV; pStdUVGen->GetUVTransform(tmUV); uvVert = uvVert * tmUV; } // add texture coordinate to the vertex candidate, inverting the y coordinate pVertexCandidate->AddTextureCoordinate(uvVert.x, 1.0f - uvVert.y); } } } // check for physique modifier if(m_modifierType == MODIFIER_PHYSIQUE) { // create a physique export interface IPhysiqueExport *pPhysiqueExport; pPhysiqueExport = (IPhysiqueExport *)m_pModifier->GetInterface(I_PHYINTERFACE); if(pPhysiqueExport == 0) { delete pVertexCandidate; theExporter.SetLastError("Physique modifier interface not found.", __FILE__, __LINE__); return 0; } // create a context export interface IPhyContextExport *pContextExport; pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(m_pINode); if(pContextExport == 0) { m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Context export interface not found.", __FILE__, __LINE__); return 0; } // set the flags in the context export interface pContextExport->ConvertToRigid(TRUE); pContextExport->AllowBlending(TRUE); // get the vertex export interface IPhyVertexExport *pVertexExport; pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(vertexId); if(pVertexExport == 0) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Vertex export interface not found.", __FILE__, __LINE__); return 0; } // get the vertex type int vertexType; vertexType = pVertexExport->GetVertexType(); // handle the specific vertex type if(vertexType == RIGID_TYPE) { // typecast to rigid vertex IPhyRigidVertex *pTypeVertex; pTypeVertex = (IPhyRigidVertex *)pVertexExport; // add the influence to the vertex candidate // get the influencing bone if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(), 1.0f)) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } else if(vertexType == RIGID_BLENDED_TYPE) { // typecast to blended vertex IPhyBlendedRigidVertex *pTypeVertex; pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++) { // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(nodeId), pTypeVertex->GetWeight(nodeId))) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } } // release all interfaces pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); } #if MAX_RELEASE >= 4000 // check for skin modifier else if(m_modifierType == MODIFIER_SKIN) { // create a skin interface ISkin *pSkin; pSkin = (ISkin*)m_pModifier->GetInterface(I_SKIN); if(pSkin == 0) { delete pVertexCandidate; theExporter.SetLastError("Skin modifier interface not found.", __FILE__, __LINE__); return 0; } // create a skin context data interface ISkinContextData *pSkinContextData; pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(m_pINode); if(pSkinContextData == 0) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Skin context data interface not found.", __FILE__, __LINE__); return 0; } // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(vertexId); nodeId++) { // get the bone id int boneId; boneId = pSkinContextData->GetAssignedBone(vertexId, nodeId); if(boneId < 0) continue; // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pSkin->GetBone(boneId), pSkinContextData->GetBoneWeight(vertexId, nodeId))) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } // release all interfaces m_pModifier->ReleaseInterface(I_SKIN, pSkin); } #endif else if( m_modifierType == MODIFIER_MORPHER || m_modifierType == MODIFIER_NONE ) { } else { theExporter.SetLastError("No physique/skin/morpher modifier found.", __FILE__, __LINE__); return 0; } return pVertexCandidate; }
void SGP_MaxInterface::GetBoneGroup( Modifier *pModifier, int nModifierType, INode* pNode, Mesh* pMesh, int nVertexId, BoneGroup& boneGroup ) { if( !pMesh ) { assert( false ); return; } if( nVertexId >= pMesh->numVerts ) { assert( false ); return; } // static mesh if( nModifierType == MODIFIER_NONE ) { INode* pParent = pNode->GetParentNode(); if( pParent && ( IsBone( pParent ) || IsBipedBone( pParent ) ) ) { Influence infl; infl.fWeight = 1.0f; strcpy( infl.szBoneName, pParent->GetName() ); boneGroup.AddInfluence( infl ); } } // check for physique modifier else if( nModifierType == MODIFIER_PHYSIQUE ) { assert( pModifier && "get bone group error, modifier is null" ); // create a physique export interface IPhysiqueExport *pPhysiqueExport = (IPhysiqueExport *)pModifier->GetInterface(I_PHYINTERFACE); if(pPhysiqueExport == NULL) { return; } // create a context export interface IPhyContextExport *pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(pNode); if(pContextExport == NULL) { pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); return; } // set the flags in the context export interface pContextExport->ConvertToRigid(TRUE); pContextExport->AllowBlending(TRUE); // get the vertex export interface IPhyVertexExport *pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(nVertexId); if(pVertexExport == NULL) { pPhysiqueExport->ReleaseContextInterface(pContextExport); pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); return; } // get the vertex type int vertexType = pVertexExport->GetVertexType(); // handle the specific vertex type if(vertexType == RIGID_TYPE) { // typecast to rigid vertex IPhyRigidVertex *pTypeVertex = (IPhyRigidVertex *)pVertexExport; Influence infl; if( pTypeVertex->GetNode() ) { strcpy( infl.szBoneName, pTypeVertex->GetNode()->GetName() ); infl.fWeight = 1.0f; boneGroup.AddInfluence( infl ); } else return; } else if(vertexType == RIGID_BLENDED_TYPE) { // typecast to blended vertex IPhyBlendedRigidVertex *pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; // loop through all influencing bones Influence infl; for(int nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++) { strcpy( infl.szBoneName, pTypeVertex->GetNode( nodeId )->GetName() ); infl.fWeight = pTypeVertex->GetWeight( nodeId ); boneGroup.AddInfluence( infl ); } } // release all interfaces pPhysiqueExport->ReleaseContextInterface(pContextExport); pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); } else if( nModifierType == MODIFIER_SKIN) { assert( pModifier && "get bone group error, modifier is null" ); // create a skin interface ISkin *pSkin = (ISkin*)pModifier->GetInterface(I_SKIN); if(pSkin == 0) { return; } // create a skin context data interface ISkinContextData *pSkinContextData; pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(pNode); if(pSkinContextData == NULL) { pModifier->ReleaseInterface(I_SKIN, pSkin); return; } // loop through all influencing bones for(int nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(nVertexId); nodeId++) { // get the bone id int boneId = pSkinContextData->GetAssignedBone(nVertexId, nodeId); if(boneId < 0) continue; INode* pBone = pSkin->GetBone( boneId ); Influence infl; strcpy( infl.szBoneName, pBone->GetName() ); infl.fWeight = pSkinContextData->GetBoneWeight(nVertexId, nodeId); boneGroup.AddInfluence( infl ); } // release all interfaces pModifier->ReleaseInterface(I_SKIN, pSkin); } }
IMenuScreen::IMenuScreen() { ISkin* skin = PolyBomberApp::getISkin(); background.setImage(skin->loadImage(MENU_BACKGROUND)); this->widgets.push_back(&background); }
static void extractTriangleGeometry( GmModel* gm, INode* node, Mesh* mesh, Mtl* material ) { #ifdef SGEXPORT_PHYSIQUE Modifier* phyMod = 0; IPhysiqueExport* phyExport = 0; IPhyContextExport* mcExport = 0; #endif Modifier* skinMod = 0; ISkin* skin = 0; String nodeName ( node->GetName() ); try { // vertex transform to left-handed system Matrix3 pivot = TmUtil::getPivotTransform( node ); Matrix3 vertexTM = pivot * s_convtm; bool insideOut = TmUtil::hasNegativeParity( pivot ); /*Matrix4x4 pm = TmUtil::toLH( vertexTM ); Debug::println( "Object {0} vertex local TM is", nodeName ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(0,0), pm(0,1), pm(0,2), pm(0,3) ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(1,0), pm(1,1), pm(1,2), pm(1,3) ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(2,0), pm(2,1), pm(2,2), pm(2,3) ); Debug::println( " {0,#.###} {1,#.###} {2,#.###} {3,#.###}", pm(3,0), pm(3,1), pm(3,2), pm(3,3) );*/ // add vertex positions int vertices = mesh->getNumVerts(); for ( int vi = 0 ; vi < vertices ; ++vi ) { Point3 v = vertexTM * mesh->verts[vi]; mb::Vertex* vert = gm->addVertex(); vert->setPosition( v.x, v.y, v.z ); } // add vertex weights (from Physique modifier) #ifdef SGEXPORT_PHYSIQUE phyMod = PhyExportUtil::findPhysiqueModifier( node ); if ( phyMod ) { Debug::println( " Found Physique modifier: {0}", gm->name ); // get (possibly shared) Physique export interface phyExport = (IPhysiqueExport*)phyMod->GetInterface( I_PHYINTERFACE ); if( !phyExport ) throw Exception( Format("No Physique modifier export interface") ); // export from initial pose? phyExport->SetInitialPose( false ); // get (unique) context dependent export inteface mcExport = (IPhyContextExport*)phyExport->GetContextInterface( node ); if( !mcExport ) throw Exception( Format("No Physique modifier context export interface") ); // convert to rigid for time independent vertex assignment mcExport->ConvertToRigid( true ); // allow blending to export multi-link assignments mcExport->AllowBlending( true ); // list bones Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) ); PhyExportUtil::listBones( mcExport, bones ); // add vertex weight maps for ( int i = 0 ; i < bones.size() ; ++i ) { INode* bone = bones[i]; String name = bone->GetName(); mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT ); PhyExportUtil::addWeights( vmap, bone, mcExport ); } } #endif // SGEXPORT_PHYSIQUE // add vertex weights (from Skin modifier) skinMod = SkinExportUtil::findSkinModifier( node ); if ( skinMod ) { skin = (ISkin*)skinMod->GetInterface(I_SKIN); require( skin ); ISkinContextData* skincx = skin->GetContextInterface( node ); require( skincx ); Debug::println( " Found Skin modifier: {0} ({1} bones, {2} points)", gm->name, skin->GetNumBones(), skincx->GetNumPoints() ); if ( skincx->GetNumPoints() != gm->vertices() ) throw Exception( Format("Only some vertices ({0}/{1}) of {2} are skinned", skincx->GetNumPoints(), gm->vertices(), gm->name) ); // list bones Vector<INode*> bones( Allocator<INode*>(__FILE__,__LINE__) ); SkinExportUtil::listBones( skin, bones ); // add vertex weight maps for ( int i = 0 ; i < bones.size() ; ++i ) { INode* bone = bones[i]; String name = bone->GetName(); mb::VertexMap* vmap = gm->addVertexMap( 1, name, mb::VertexMapFormat::VERTEXMAP_WEIGHT ); SkinExportUtil::addWeights( vmap, bone, skin, skincx ); //Debug::println( " Bone {0} is affecting {1} vertices", name, vmap->size() ); } // DEBUG: print skin node tm and initial object tm /*Matrix3 tm; int ok = skin->GetSkinInitTM( node, tm ); require( ok == SKIN_OK ); Debug::println( " NodeInitTM of {0}", nodeName ); TmUtil::println( tm, 4 ); ok = skin->GetSkinInitTM( node, tm, true ); require( ok == SKIN_OK ); Debug::println( " NodeObjectTM of {0}", nodeName ); TmUtil::println( tm, 4 );*/ // DEBUG: print bones /*Debug::println( " bones of {0}:", nodeName ); for ( int i = 0 ; i < bones.size() ; ++i ) { Debug::println( " bone ({0}): {1}", i, String(bones[i]->GetName()) ); skin->GetBoneInitTM( bones[i], tm ); Debug::println( " InitNodeTM:" ); TmUtil::println( tm, 6 ); skin->GetBoneInitTM( bones[i], tm, true ); Debug::println( " InitObjectTM:" ); TmUtil::println( tm, 6 ); }*/ // DEBUG: print bones used by the points /*for ( int i = 0 ; i < skincx->GetNumPoints() ; ++i ) { int bonec = skincx->GetNumAssignedBones(i); Debug::println( " point {0} has {1} bones", i, bonec ); for ( int k = 0 ; k < bonec ; ++k ) { int boneidx = skincx->GetAssignedBone( i, k ); float w = skincx->GetBoneWeight( i, k ); Debug::println( " point {0} boneidx ({1}): {2}, weight {3}", i, k, boneidx, w ); } }*/ } // ensure clockwise polygon vertex order int vx[3] = {2,1,0}; if ( insideOut ) { int tmp = vx[0]; vx[0] = vx[2]; vx[2] = tmp; } // list unique materials used by the triangles Vector<ShellMaterial> usedMaterials( Allocator<ShellMaterial>(__FILE__,__LINE__) ); if ( material ) { for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { Face& face = mesh->faces[fi]; int mergesubmaterial = -1; int originalsubmaterial = -1; for ( int j = 0; j < material->NumSubMtls(); ++j) { // Get Sub Material Slot name TSTR name = material->GetSubMtlSlotName(j); // Light maps are stored in sub material slot named "Baked Material" if ( strcmp( name, "Baked Material" ) == 0 ) mergesubmaterial = j; else originalsubmaterial = j; } if ( mergesubmaterial != -1 ) // A baked material was found, shell materials will be created { Mtl* mat = material->GetSubMtl( originalsubmaterial ); Mtl* bakedmtl = material->GetSubMtl( mergesubmaterial ); if ( mat->NumSubMtls() > 0 ) // Check for nested multi-material { for ( int j = 0; j < mat->NumSubMtls(); ++j) usedMaterials.add( ShellMaterial( mat->GetSubMtl( face.getMatID() % mat->NumSubMtls() ), bakedmtl ) ); } else usedMaterials.add( ShellMaterial( mat, bakedmtl ) ); } else if ( material->NumSubMtls() > 0 ) // Multi-material without baked material { usedMaterials.add( ShellMaterial( material->GetSubMtl( face.getMatID() % material->NumSubMtls() ), 0 ) ); } else // Single material without baked material { usedMaterials.add( ShellMaterial( material, 0 ) ); } } std::sort( usedMaterials.begin(), usedMaterials.end() ); usedMaterials.setSize( std::unique( usedMaterials.begin(), usedMaterials.end() ) - usedMaterials.begin() ); } // create used materials for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi ) { ShellMaterial shellmtl = usedMaterials[mi]; gm->materials.add( GmUtil::createGmMaterial( shellmtl.original, shellmtl.baked ) ); } // add triangles for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { mb::Polygon* poly = gm->addPolygon(); // triangle indices Face& face = mesh->faces[fi]; for ( int vxi = 0 ; vxi < 3 ; ++vxi ) { int vi = face.v[ vx[vxi] ]; require( vi >= 0 && vi < gm->vertices() ); mb::Vertex* vert = gm->getVertex( vi ); poly->addVertex( vert ); } // triangle material int polyMaterialIndex = 0; if ( material ) { ShellMaterial mat( material, 0 ); int numsubmaterials = material->NumSubMtls(); if ( numsubmaterials > 0 ) { mat.original = material->GetSubMtl( face.getMatID() % material->NumSubMtls() ); for ( int j = 0; j < numsubmaterials; ++j) // Is baked material present? { TSTR name = material->GetSubMtlSlotName(j); if ( strcmp( name, "Baked Material" ) == 0 ) mat.baked = material->GetSubMtl( j ); if ( strcmp( name, "Original Material" ) == 0 ) mat.original = material->GetSubMtl( j ); } if ( mat.original->NumSubMtls() > 0 ) // Is there a nested multi-material? { mat.original = mat.original->GetSubMtl( face.getMatID() % mat.original->NumSubMtls() ); } } for ( int mi = 0 ; mi < usedMaterials.size() ; ++mi ) { if ( usedMaterials[mi] == mat ) { polyMaterialIndex = mi; break; } } } poly->setMaterial( polyMaterialIndex ); } // add vertex colors int mp = 0; if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 ) { mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "rgb", mb::VertexMapFormat::VERTEXMAP_RGB ); int tverts = mesh->getNumMapVerts( mp ); UVVert* tvert = mesh->mapVerts( mp ); TVFace* tface = mesh->mapFaces( mp ); //Debug::println( "Vertex colors:" ); for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { Face& face = mesh->faces[fi]; mb::Polygon* poly = gm->getPolygon( fi ); for ( int vxi = 0 ; vxi < 3 ; ++vxi ) { int vi = face.v[ vx[vxi] ]; mb::Vertex* vert = gm->getVertex( vi ); Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ]; float rgb[3] = {tc.x, tc.y, tc.z}; vmad->addValue( vert->index(), poly->index(), rgb, 3 ); //Debug::println( " vertex[{0}].rgb: {1} {2} {3}", vert->index(), rgb[0], rgb[1], rgb[2] ); } } } // add texcoord layers int lastCoords = MAX_MESHMAPS-2; while ( lastCoords > 0 && (!mesh->mapSupport(lastCoords) || 0 == mesh->getNumMapVerts(lastCoords)) ) --lastCoords; if ( lastCoords > 8 ) throw IOException( Format("Too many texture coordinate sets ({1}) in {0}", gm->name, lastCoords) ); for ( mp = 1 ; mp <= lastCoords ; ++mp ) { mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 2, "uv", mb::VertexMapFormat::VERTEXMAP_TEXCOORD ); if ( mesh->mapSupport(mp) && mesh->getNumMapVerts(mp) > 0 ) { int tverts = mesh->getNumMapVerts( mp ); UVVert* tvert = mesh->mapVerts( mp ); TVFace* tface = mesh->mapFaces( mp ); for ( int fi = 0 ; fi < mesh->getNumFaces() ; ++fi ) { Face& face = mesh->faces[fi]; mb::Polygon* poly = gm->getPolygon( fi ); for ( int vxi = 0 ; vxi < 3 ; ++vxi ) { int vi = face.v[ vx[vxi] ]; mb::Vertex* vert = gm->getVertex( vi ); Point3 tc = tvert[ tface[fi].t[ vx[vxi] ] % tverts ]; float uv[2] = {tc.x, 1.f-tc.y}; vmad->addValue( vert->index(), poly->index(), uv, 2 ); } } } } // compute face vertex normals from smoothing groups require( mesh->getNumFaces() == gm->polygons() ); mb::DiscontinuousVertexMap* vmad = gm->addDiscontinuousVertexMap( 3, "vnormals", mb::VertexMapFormat::VERTEXMAP_NORMALS ); for ( int fi = 0 ; fi < gm->polygons() ; ++fi ) { mb::Polygon* poly = gm->getPolygon( fi ); require( poly ); require( poly->index() >= 0 && poly->index() < mesh->getNumFaces() ); Face& face = mesh->faces[ poly->index() ]; require( poly->vertices() == 3 ); for ( int j = 0 ; j < poly->vertices() ; ++j ) { Vector3 vn(0,0,0); mb::Vertex* vert = poly->getVertex( j ); // sum influencing normals for ( int k = 0 ; k < vert->polygons() ; ++k ) { mb::Polygon* vpoly = vert->getPolygon( k ); require( vpoly ); require( vpoly->index() >= 0 && vpoly->index() < mesh->getNumFaces() ); Face& vface = mesh->faces[ vpoly->index() ]; if ( 0 != (face.smGroup & vface.smGroup) || poly == vpoly ) { Vector3 vpolyn; vpoly->getNormal( &vpolyn.x, &vpolyn.y, &vpolyn.z ); vn += vpolyn; } } // normalize float lensqr = vn.lengthSquared(); if ( lensqr > Float::MIN_VALUE ) vn *= 1.f / Math::sqrt(lensqr); else vn = Vector3(0,0,0); vmad->addValue( vert->index(), poly->index(), vn.begin(), 3 ); } } // re-export mesh points in non-deformed pose if Skin modifier present // NOTE: 3ds Mesh must not be used after this, because collapsing can invalidate it if ( skin ) { // evaluate derived object before Skin modifier TimeValue time = 0; bool evalNext = false; bool evalDone = false; ::ObjectState os; ::Object* obj = node->GetObjectRef(); while ( obj->SuperClassID() == GEN_DERIVOB_CLASS_ID && !evalDone ) { IDerivedObject* derivedObj = static_cast<IDerivedObject*>(obj); for ( int modStack = 0 ; modStack < derivedObj->NumModifiers() ; ++modStack ) { if ( evalNext ) { os = derivedObj->Eval( time, modStack ); evalDone = true; break; } Modifier* mod = derivedObj->GetModifier(modStack); if ( mod->ClassID() == SKIN_CLASSID ) evalNext = true; } obj = derivedObj->GetObjRef(); } // evaluate possible non-derived object if ( evalNext && !evalDone ) { os = obj->Eval( time ); evalDone = true; } // convert to TriObject and get points if ( evalDone && os.obj->CanConvertToType( Class_ID(TRIOBJ_CLASS_ID,0) ) ) { Debug::println( " Evaluating object {0} before Skin modifier", nodeName ); // get TriObject std::auto_ptr<TriObject> triAutoDel(0); TriObject* tri = static_cast<TriObject*>( os.obj->ConvertToType( time, Class_ID(TRIOBJ_CLASS_ID,0) ) ); if ( tri != os.obj ) triAutoDel = std::auto_ptr<TriObject>( tri ); // get mesh points before Skin is applied //Debug::println( " Original collapsed mesh has {0} points, before Skin modifier {1} points", mesh->getNumVerts(), tri->mesh.getNumVerts() ); require( gm->vertices() == tri->mesh.getNumVerts() ); Mesh* mesh = &tri->mesh; int vertices = mesh->getNumVerts(); for ( int vi = 0 ; vi < vertices ; ++vi ) { Point3 v = vertexTM * mesh->verts[vi]; mb::Vertex* vert = gm->getVertex( vi ); vert->setPosition( v.x, v.y, v.z ); } } } // split vertices with discontinuous vertex map values for ( int vmi = 0 ; vmi < gm->discontinuousVertexMaps() ; ++vmi ) { mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap( vmi ); gm->splitVertexDiscontinuities( vmad ); } // find base texcoord layer mb::DiscontinuousVertexMap* texcoords = 0; for ( int i = 0 ; i < gm->discontinuousVertexMaps() ; ++i ) { mb::DiscontinuousVertexMap* vmad = gm->getDiscontinuousVertexMap(i); if ( vmad->dimensions() == 2 && vmad->format() == mb::VertexMapFormat::VERTEXMAP_TEXCOORD ) { texcoords = vmad; break; } } if ( !texcoords ) Debug::printlnError( "Object {0} must have texture coordinates", gm->name ); // requires identification of footsteps in MySceneExport::isExportableGeometry //throw IOException( Format("Object {0} must have texture coordinates", gm->name) ); // optimize gm->removeUnusedVertices(); // cleanup export interfaces #ifdef SGEXPORT_PHYSIQUE if ( mcExport ) { require( phyExport ); phyExport->ReleaseContextInterface( mcExport ); mcExport = 0; } if ( phyExport ) { require( phyMod ); phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport ); phyExport = 0; } #endif // SGEXPORT_PHYSIQUE if ( skin ) { skinMod->ReleaseInterface( I_SKIN, skin ); skin = 0; skinMod = 0; } } catch ( ... ) { // cleanup export interfaces #ifdef SGEXPORT_PHYSIQUE if ( mcExport ) { require( phyExport ); phyExport->ReleaseContextInterface( mcExport ); mcExport = 0; } if ( phyExport ) { require( phyMod ); phyMod->ReleaseInterface( I_PHYINTERFACE, phyExport ); phyExport = 0; } #endif // SGEXPORT_PHYSIQUE if ( skin ) { skinMod->ReleaseInterface( I_SKIN, skin ); skin = 0; skinMod = 0; } throw; } }
//---------------------------------------------------------------------------- void SceneBuilder::ProcessSkin(INode *node, Modifier *skinMod) { // 构造皮肤控制器。如果Max的网格被按照材质细分,每一个网格都需要自己的蒙皮 // 信息控制器。蒙皮信息中的offset,在动画起始时被计算,是骨骼的世界变换。 // // node: // 指向蒙皮修改器指向的Max中的节点。 // skinMod: // 指向蒙皮修改器 // 1. 获得max蒙皮信息中的骨骼,对应的在Phoenix的骨骼节点列表 // 2. 获得maxNode影响的Phoenix网格 // 3. 获得max中每个骨骼所影响的Phoenix网格中的顶点的数量,忽略不受蒙皮信息 // 影响的网格 // 4. 计算Phoenix mesh的蒙皮信息,生成SkinControl,AttachController到 // Phoenix mesh上。 // 1 bool needDel; TriObject *triObj = GetTriObject(node, &needDel); Mesh *maxMesh = &triObj->GetMesh(); // Max皮肤控制器接口 ISkin *skin = (ISkin*)skinMod->GetInterface(I_SKIN); ISkinContextData *skinData = skin->GetContextInterface(node); // max Skin Bones -> Phoenix2 Skin Bones int b, numSkinBone = skin->GetNumBones(); PX2::Node **bones = new1<PX2::Node*>(numSkinBone); for (b=0; b<numSkinBone; b++) { INode *boneNode = skin->GetBone(b); const std::string &boneName = boneNode->GetName(); PX2::Node *node = PX2::StaticCast<PX2::Node>(mScene->GetObjectByName(boneName)); bones[b] = node; } // 1 // 获得maxNode相关联的Phoenix mesh std::vector<PX2::TriMesh*> meshes; PX2::Object *object = mScene->GetObjectByName(node->GetName()); if (object->IsExactly(PX2::TriMesh::TYPE)) { meshes.push_back(PX2::StaticCast<PX2::TriMesh>(object)); } else { PX2::Node *node = PX2::StaticCast<PX2::Node>(object); const char *nName = node->GetName().c_str(); for (int c=0; c<node->GetNumChildren(); c++) { PX2::Movable *child = node->GetChild(c); const char *cName = child->GetName().c_str(); if (strncmp(cName, nName, strlen(nName)) == 0) // 这里必须是strlen(nName),因为子节点有_1,_2 { meshes.push_back(PX2::StaticCast<PX2::TriMesh>(child)); } } } // 为Phoenix2的每个网格建立相关的皮肤控制器 int *boneInfuseNumVert = new1<int>(numSkinBone); for (int m=0; m<(int)meshes.size(); m++) { PX2::TriMesh *mesh = meshes[m]; // Phoenix顶点在max顶点中的索引 PX2::VertexBuffer *vb = mesh->GetVertexBuffer(); int px2MeshVertexNum = vb->GetNumElements(); std::vector<int> MaxVertexIndex; // i->max索引 int v, i, j, k; PX2::VertexBufferAccessor vba(mesh->GetVertexFormat(), vb); // 3 for (int v=0; v<px2MeshVertexNum; ++v) { Float3 &position = vba.Position<Float3>(v); for (i=0; i<maxMesh->getNumVerts(); i++) { if (position[0] == maxMesh->verts[i].x && position[1] == maxMesh->verts[i].y && position[2] == maxMesh->verts[i].z) { MaxVertexIndex.push_back(i); break; } } } // 确定每个骨骼所影响的顶点数量 int maxVertexSize = (int)MaxVertexIndex.size(); memset(boneInfuseNumVert, 0, sizeof(int)*numSkinBone); for (i=0; i<maxVertexSize; i++) { v = MaxVertexIndex[i]; for (j=0; j<skinData->GetNumAssignedBones(v); j++) { // 这个max中的顶点受到几个骨骼影响啊?! b = skinData->GetAssignedBone(v, j); // 获得这个影响的骨骼索引(这个j是第几个) boneInfuseNumVert[b]++; // 这个骨骼影响的顶点数量++ } } // (通过PX2中的顶点找到Max中的顶点,找到Max中影响该顶点的骨骼) // 如果Max的网格是被按照材质分割的,可能一些骨骼对当前Phoenix2网格没有 // 影响 int bQuantity = 0; // 影响当前Phoenix2网格的骨骼数量 for (b=0; b<numSkinBone; b++) { if (boneInfuseNumVert[b] > 0) bQuantity++; } if (bQuantity == 0) { // Phoenix网格不被任何骨骼影响,进入下一个网格 continue; } // 4 PX2::Node **theBones = new1<PX2::Node*>(bQuantity); float **weight = new2<float>(bQuantity, maxVertexSize); memset(weight[0],0,bQuantity*maxVertexSize*sizeof(float)); PX2::APoint **offset = new2<PX2::APoint>(bQuantity, maxVertexSize); memset(offset[0],0,bQuantity*maxVertexSize*sizeof(PX2::APoint)); PX2::HMatrix *mats = new1<PX2::HMatrix>(bQuantity); // 计算max骨骼到Phoenix骨骼对应的索引(k) std::vector<int> bIArray(numSkinBone); for (b=0, k=0; b<numSkinBone; b++) { if (boneInfuseNumVert[b] > 0) { theBones[k] = bones[b]; // 获取对Mesh有影响的骨骼 bIArray[b] = k; // max bone index -> px2 可用bone index HMatrix boneWorldMat = theBones[k]->WorldTransform.Matrix(); HMatrix meshWorldMat = mesh->WorldTransform.Matrix(); mats[k] = boneWorldMat.Inverse() * meshWorldMat; k++; } } // 遍历顶点,计算顶点权重和offset for (i=0; i<maxVertexSize; i++) { v = MaxVertexIndex[i]; for (j=0; j<skinData->GetNumAssignedBones(v); j++) { // 遍历影响该Max顶点的骨骼 b = skinData->GetAssignedBone(v, j); k = bIArray[b]; float wit = skinData->GetBoneWeight(v, j); // 第j个骨骼的影响权重 weight[i][k] = wit; Float3 &position = vba.Position<Float3>(i); APoint point = theBones[k]->WorldTransform.Inverse() * (mesh->WorldTransform * APoint(position)); offset[i][k] = Float3(point.X(), point.Y(), point.Z()); // 在所受影响骨骼中的位置 } } PX2::SkinController *skinCtrl = new0 PX2::SkinController (maxVertexSize, bQuantity); skinCtrl->SetName("SkinController"); for (int i=0; i<bQuantity; i++) { skinCtrl->GetBones()[i] = theBones[i]; skinCtrl->GetTMMatrixs()[i] = mats[i]; } // offset for (int i=0; i<maxVertexSize; i++) { for (int j=0; j<bQuantity; j++) { skinCtrl->GetWeights()[i][j] = weight[i][j]; skinCtrl->GetOffsets()[i][j] = offset[i][j]; } } // index weights for (int i=0; i<maxVertexSize; i++) { Float4 inds = Float4(0.0f, 0.0f, 0.0f, 0.0f); Float4 wights = Float4(0.0f, 0.0f, 0.0f, 0.0f); In *pSortBone = new In[bQuantity]; for (int j=0; j<bQuantity; j++) { pSortBone[j].index = j; pSortBone[j].data = weight[i][j]; } qsort(pSortBone, bQuantity, sizeof(pSortBone[0]), cmp); int useBoneNum = bQuantity; if (useBoneNum > 4) useBoneNum = 4; float allWeight = 0.0f; for (int useBoneIndex=0; useBoneIndex<useBoneNum; useBoneIndex++) { allWeight += pSortBone[useBoneIndex].data; } if (allWeight <= 0.0f) allWeight = 1.0f; for (int useBoneIndex=0; useBoneIndex<useBoneNum; useBoneIndex++) { inds[useBoneIndex] = (float)(pSortBone[useBoneIndex].index); wights[useBoneIndex] = pSortBone[useBoneIndex].data/allWeight; } vba.TCoord<Float4>(1, i) = inds; vba.TCoord<Float4>(2, i) = wights; delete [] pSortBone; } skinCtrl->Repeat = Controller::RT_WRAP; skinCtrl->MinTime = 0.0f; skinCtrl->MaxTime = TicksToSec(mTimeEnd - mTimeStart); mesh->AttachController(skinCtrl); delete1(theBones); delete2(weight); delete2(offset); delete1(mats); } if (needDel) { delete0(triObj); } delete1(bones); delete1(boneInfuseNumVert); }
bool Exporter::makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, TimeValue t) { if (!mExportSkin) return false; if (grp.verts.empty()) return false; //get the skin modifier Modifier *mod = GetSkin(node); if (!mod) return false; ISkin *skin = (ISkin *) mod->GetInterface(I_SKIN); if (!skin) return false; ISkinContextData *skinData = skin->GetContextInterface(node); if (!skinData) return false; if (grp.strips.empty()) strippify(grp); // Create new call back to finish export SkinInstance* si = new SkinInstance(this); mPostExportCallbacks.push_back(si); skin->GetSkinInitTM(node, si->bone_init_tm, false); skin->GetSkinInitTM(node, si->node_init_tm, true); si->shape = shape; // Get bone references (may not actually exist in proper structure at this time) int totalBones = skin->GetNumBones(); si->boneWeights.resize(totalBones); si->boneList.resize(totalBones); for (int i=0; i<totalBones; ++i) { si->boneList[i] = getNode(skin->GetBone(i)); } vector<int>& vidx = grp.vidx; int nv = vidx.size(); for (int i=0; i<nv; ++i) { int vi = vidx[i]; int nbones = skinData->GetNumAssignedBones(vi); for (int j=0; j<nbones; ++j) { SkinWeight sw; sw.index = i; sw.weight = skinData->GetBoneWeight(vi,j); int boneIndex = skinData->GetAssignedBone(vi,j); SkinInstance::SkinWeightList& weights = si->boneWeights[boneIndex]; weights.push_back(sw); } } // remove unused bones vector<NiNodeRef>::iterator bitr = si->boneList.begin(); SkinInstance::BoneWeightList::iterator switr = si->boneWeights.begin(); for (int i=0; i<totalBones; ++i) { vector<SkinWeight> &weights = (*switr); if (weights.empty()) { bitr = si->boneList.erase(bitr); switr = si->boneWeights.erase(switr); } else { ++bitr, ++switr; } } // Check for dismemberment if (IsFallout3() || IsSkyrim()) { Modifier *dismemberSkinMod = GetBSDismemberSkin(node); if (dismemberSkinMod) { if (IBSDismemberSkinModifier *disSkin = (IBSDismemberSkinModifier *) dismemberSkinMod->GetInterface(I_BSDISMEMBERSKINMODIFIER)){ Tab<IBSDismemberSkinModifierData*> modData = disSkin->GetModifierData(); if (modData.Count() >= 1) { IBSDismemberSkinModifierData* bsdsmd = modData[0]; si->SkinInstConstructor = BSDismemberSkinInstance::Create; Tab<BSDSPartitionData> &flags = bsdsmd->GetPartitionFlags(); GenericNamedSelSetList &fselSet = bsdsmd->GetFaceSelList(); FaceMap fmap; NiTriBasedGeomDataRef data = DynamicCast<NiTriBasedGeomData>(shape->GetData()); vector<Triangle> tris = data->GetTriangles(); for (int i=0; i<tris.size(); ++i) { Triangle tri = tris[i]; fmap[ rotate(tri) ] = i; } // Build up list of partitions and face to partition map si->partitions.resize(flags.Count()); si->facePartList.resize( grp.faces.size(), -1 ); for (int i=0; i<flags.Count(); ++i) { BodyPartList& bp = si->partitions[i]; bp.bodyPart = (BSDismemberBodyPartType)flags[i].bodyPart; bp.partFlag = (BSPartFlag)(flags[i].partFlag | PF_START_NET_BONESET); BitArray& fSelect = fselSet[i]; for (int j=0; j<fSelect.GetSize(); ++j){ if ( fSelect[j] ) { Triangle tri = grp.faces[grp.fidx[j]]; FaceMap::iterator fitr = fmap.find( rotate(tri) ); if (fitr != fmap.end()) si->facePartList[ (*fitr).second ] = i; } } } } } } } return true; }
KeyAssignMenu::KeyAssignMenu(unsigned int player) : title("Configuration des touches", TITLEFONT, 50), subtitle("Joueur 1", TITLEFONT, 100), errorKey("La touche est deja utilisee", TEXTFONT, 170), cancel("Annuler", 550, CONTROLLERSCONFIGMENU), save("Valider", 550, CONTROLLERSCONFIGMENU), player(player) { ISkin* skin = PolyBomberApp::getISkin(); title.setColor(skin->getColor(TITLECOLOR)); subtitle.setColor(skin->getColor(TEXTCOLOR)); errorKey.setColor(skin->getColor(ERRORCOLOR)); std::ostringstream text; text << "Joueur " << player; subtitle.setString(text.str()); errorKey.setVisible(false); this->widgets.push_back(&title); this->widgets.push_back(&subtitle); this->widgets.push_back(&errorKey); this->widgets.push_back(&cancel); this->widgets.push_back(&save); std::string actions[7] = {"Haut :", "Bas :", "Gauche :", "Droite :", "Action 1 :", "Action 2 :", "Pause :"}; for (int i=0; i<7; i++) { actionText[i] = new TextWidget(actions[i], TEXTFONT, 220 + 45*i, RIGHT); actionText[i]->setColor(skin->getColor(TEXTCOLOR)); actionText[i]->move(-420, 0); keyText[i] = new LinkWidget("touche", 220 + 45*i, NONEMENU); keyText[i]->move(70, 0); if (i > 0) keyText[i]->setPrevious(keyText[i-1]); this->widgets.push_back(actionText[i]); this->widgets.push_back(keyText[i]); } cancel.move(-100, 0); save.move(100, 0); for (int i=0; i<6; i++) keyText[i]->setNext(keyText[i+1]); keyText[6]->setNext(&cancel); cancel.setPrevious(keyText[6]); cancel.setNext(&save); save.setPrevious(keyText[6]); save.setNext(&cancel); cancel.setSelected(true); this->window = NULL; }