void SceneAnimator::load(PlatformContext& context, ByteBuffer& dataIn) { // make sure to clear this before writing new data release(); _skeleton = loadSkeleton(dataIn, nullptr); stringImpl boneName; uint32_t nsize = 0; dataIn >> nsize; _bones.resize(nsize); for (uint32_t i(0); i < nsize; i++) { dataIn >> boneName; _bones[i] = _skeleton->find(boneName); } _skeletonDepthCache = nsize; // the number of animations dataIn >> nsize; _animations.resize(nsize); uint32_t idx = 0; for (std::shared_ptr<AnimEvaluator>& anim : _animations) { anim = std::make_unique<AnimEvaluator>(); AnimEvaluator::load(*anim, dataIn); // get all the animation names so I can reference them by name and get the correct id hashAlg::insert(_animationNameToID, _ID(anim->name().c_str()), idx++); } init(context); }
Bone* SceneAnimator::loadSkeleton(ByteBuffer& dataIn, Bone* parent) { stringImpl tempString; // create a node Bone* internalNode = MemoryManager_NEW Bone(); // set the parent, in the case this is the root node, it will be null internalNode->_parent = parent; // the name of the bone dataIn >> tempString; internalNode->name(tempString); // the bone offsets dataIn >> internalNode->_offsetMatrix; // original bind pose dataIn >> internalNode->_originalLocalTransform; // a copy saved internalNode->_localTransform = internalNode->_originalLocalTransform; calculateBoneToWorldTransform(internalNode); // the number of children U32 nsize = 0; dataIn >> nsize; // recursively call this function on all children // continue for all child nodes and assign the created internal nodes as our children for (U32 a = 0; a < nsize; a++) { internalNode->_children.push_back(loadSkeleton(dataIn, internalNode)); } return internalNode; }
//----------------------------------------------------------------------------- //! Loads the skeleton void SLAssimpImporter::loadSkeleton(SLJoint* parent, aiNode* node) { if (!node) return; SLJoint* joint; SLstring name = node->mName.C_Str(); if (!parent) { logMessage(LV_normal, "Loading skeleton skeleton.\n"); _skeleton = new SLSkeleton; _jointIndex = 0; joint = _skeleton->createJoint(name, _jointIndex++); _skeleton->root(joint); } else { joint = parent->createChild(name, _jointIndex++); } joint->offsetMat(getOffsetMat(name)); // set the initial state for the joints (in case we render the model without playing its animation) // an other possibility is to set the joints to the inverse offset matrix so that the model remains in // its bind pose // some files will report the node transformation as the animation state transformation that the // model had when exporting (in case of our astroboy its in the middle of the animation= // it might be more desirable to have ZERO joint transformations in the initial pose // to be able to see the model without any joint modifications applied // exported state // set the current node transform as the initial state /** SLMat4f om; memcpy(&om, &node->mTransformation, sizeof(SLMat4f)); om.transpose(); joint->om(om); joint->setInitialState(); /*/ // set the binding pose as initial state SLMat4f om; om = joint->offsetMat().inverse(); if (parent) om = parent->updateAndGetWM().inverse() * om; joint->om(om); joint->setInitialState(); /**/ for (SLuint i = 0; i < node->mNumChildren; i++) loadSkeleton(joint, node->mChildren[i]); }
Skeleton *AnimationLibrary::getSkeleton(const std::string &id) { std::map<std::string, Skeleton *>::iterator it = m_animations.find(id); if (it == m_animations.end()) { std::pair<std::map<std::string, Skeleton *>::iterator, bool> ret; ret = m_animations.insert( std::pair<std::string, Skeleton *>(id, loadSkeleton(id))); it = ret.first; } return it->second; }
// Create a model by deserializing it from Json Model::Model(const Json::Value& root, const std::string& directory, TextureCache &_textureCache) : meshes(0, NULL), skeleton(new Node()), textureCache(_textureCache), previousProgram(NULL), uploaded(false) { // Load animations loadAnimations(root); // Load materials loadMaterials(root, directory); // Load mesh data loadMeshes(root); // Load node data loadSkeleton(root); // Load parts loadParts(root); }
Player::Player(Game& g, b2Vec2 p) : Character(g),swordFix(NULL), left(false), right(false), landed(true), contact(false), lastproc(0), life(100), attacking(false), attackcooldown(0) { bodyDef.type = b2_dynamicBody; bodyDef.position.Set(p.x, p.y); bodyDef.fixedRotation = true; body = g.w.CreateBody(&bodyDef); dynamicBox.SetAsBox(.25f, 0.9f); fixtureDef.shape = &dynamicBox; fixtureDef.density = 5.0f; fixtureDef.friction = 0.0f; fixtureDef.filter.categoryBits = PLAYER; fixtureDef.filter.maskBits = MONSTER | TRIGGER | WALL | SWORD; (body->CreateFixture(&fixtureDef))->SetUserData(this); //add "feet" to detect floor dynamicBox.SetAsBox(0.2, 0.05, b2Vec2(0, 0.9f), 0); fixtureDef.isSensor = true; fixtureDef.density = 0.1; fixtureDef.filter.categoryBits = FOOT; fixtureDef.filter.maskBits = WALL | MONSTER; (body->CreateFixture(&fixtureDef))->SetUserData(this); //add sword to kill monsters dynamicBox.SetAsBox(0.4, 0.1, b2Vec2(0.65, 0), 0); swordDef.shape = &dynamicBox; swordDef.isSensor = true; swordDef.density = 0.1; swordDef.filter.categoryBits = SWORD; swordDef.filter.maskBits = MONSTER; // Loads the Spine model ALLEGRO_PATH *path, *resourceDir, *file; resourceDir= al_get_standard_path(ALLEGRO_RESOURCES_PATH); std::cerr << al_path_cstr(resourceDir, ALLEGRO_NATIVE_PATH_SEP) << std::endl; if (modelAtlas == NULL) { file = al_create_path("data/animations/hero.atlas"); path = al_clone_path(resourceDir); al_join_paths(path, file); al_destroy_path(file); modelAtlas = spAtlas_createFromFile(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP), NULL); if (!modelAtlas) throw Failure("Failed to load the hero's atlas."); al_destroy_path(path); jsonSkel = spSkeletonJson_create(modelAtlas); file = al_create_path("data/animations/hero.json"); path = al_clone_path(resourceDir); al_join_paths(path, file); al_destroy_path(file); modelData = spSkeletonJson_readSkeletonDataFile(jsonSkel, al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); if (!modelData) throw Failure("Failed to load the hero's data."); al_destroy_path(path); al_destroy_path(resourceDir); stateData = spAnimationStateData_create(modelData); spAnimationStateData_setMixByName(stateData, "walk", "rest", 0.2f); spAnimationStateData_setMixByName(stateData, "rest", "walk", 0.2f); spAnimationStateData_setMixByName(stateData, "rest", "slash", 0.1f); spAnimationStateData_setMixByName(stateData, "slash", "rest", 0.1f); spAnimationStateData_setMixByName(stateData, "walk", "slash", 0.1f); spAnimationStateData_setMixByName(stateData, "slash", "walk", 0.1f); model = loadSkeleton(modelData, stateData); if (!model) throw Failure("Failed to load the hero's skeleton."); spAnimationState_setAnimationByName(model->state, 0, "rest", true); } }
Skeleton::Skeleton(const Common::String &filename, Common::SeekableReadStream *data) { loadSkeleton(data); }
void updateEditor(SDL_Event event, EditorData* data) { GUI_sendEventToGUI(data->gui, &event); const unsigned char* keyboardState = SDL_GetKeyboardState(NULL); int2 mousePixel; SDL_GetMouseState(&mousePixel.x, &mousePixel.y); float2 mousePos = pixelToPoint(&data->view, mousePixel); updateBones(data); switch (event.type) { case SDL_KEYDOWN: { switch (event.key.keysym.scancode) { case SDL_SCANCODE_S: if (event.key.keysym.mod == KMOD_LCTRL) { SDL_Event lastEvent = data->lowEventStack.Top(); if (lastEvent.key.keysym.scancode == SDL_SCANCODE_S && lastEvent.key.keysym.mod == KMOD_LCTRL) { // save skeleton GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 25, 200, 50}, GUI_Container::Orientation::HORIZONTAL); auto callbackSave = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; saveSkeleton(filename, &data->skeleton[0], &data->names[0], data->skeleton.size()); GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Save", data, callbackSave); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } else if (lastEvent.key.keysym.scancode == SDL_SCANCODE_O && lastEvent.key.keysym.mod == KMOD_LCTRL) { // load skeleton GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 15, 200, 30 }, GUI_Container::Orientation::HORIZONTAL); auto callbackLoad = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; strcpy(data->skeletonName, filename); const SkeletonSave* save = loadSkeleton(filename); if (save != 0) { data->bones.clear(); data->skeleton.clear(); data->constraints.clear(); data->names.clear(); const char* name = save->names; for (int i = 0; i < save->numBones; ++i) { Bone newBone; newBone.jointAngle = { 1, 0 }; newBone.jointPos = save->jointPos[i]; newBone.parentJoint = save->parentJoints[i]; newBone.name = data->names.push({ { 0 } }); memcpy(data->names[newBone.name].string, name, save->nameLen[i] * sizeof(char)); name += save->nameLen[i]; Constraint constraint; constraint.minAngle = -PI; constraint.maxAngle = 3 * PI; data->skeleton.push(newBone); data->constraints.push(constraint); } updateBones(data); } GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Load", data, callbackLoad); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } data->lowEventStack.Push(event); } break; case SDL_SCANCODE_K: if (event.key.keysym.mod == KMOD_LCTRL) { SDL_Event lastEvent = data->lowEventStack.Top(); if (lastEvent.key.keysym.scancode == SDL_SCANCODE_S && lastEvent.key.keysym.mod == KMOD_LCTRL) { // save keyFrame GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 15, 200, 30 }, GUI_Container::Orientation::HORIZONTAL); auto callbackSave = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; saveKeyFrame(filename, &data->skeleton[0], &data->names[0], data->skeleton.size()); GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Save", data, callbackSave); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } else if (lastEvent.key.keysym.scancode == SDL_SCANCODE_O && lastEvent.key.keysym.mod == KMOD_LCTRL) { // load keyframe GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, { 400 - 100, 300 - 15, 200, 30 }, GUI_Container::Orientation::HORIZONTAL); auto callbackLoad = [](GUI* gui, GUI_WidgetID widgetID, void* editorData) { EditorData* data = (EditorData*)editorData; GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); const char* filename = GUI_getTextfield(gui, GUI_getChildWidget(gui, widget, 0)).text; strcpy(data->frameName, filename); const KeyFrameSave* save = loadKeyFrame(filename); if (save != 0) { const char* name = save->names; for (int i = 0; i < save->numBones; ++i) { int nameID = -1; for (int j = 0; j < data->names.size(); ++j) { if (strncmp(name, data->names[j].string, save->nameLen[i]) == 0) { nameID = j; break; } } if (nameID != -1) { if (data->skeleton[nameID].name == nameID) { data->skeleton[nameID].jointAngle = save->jointAngles[i]; } else { for (int j = 0; j < data->skeleton.size(); j++) { if (data->skeleton[j].name = nameID) data->skeleton[j].jointAngle = save->jointAngles[i]; } } } name += save->nameLen[i]; } updateBones(data); } GUI_removeWidget(gui, widget); }; auto callbackCancel = [](GUI* gui, GUI_WidgetID widgetID, void*) { GUI_WidgetID widget = GUI_getParentWidget(gui, widgetID); GUI_removeWidget(gui, widget); }; GUI_addTextfield(data->gui, widget, { 0, 0, -1, -1 }, "filename"); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Load", data, callbackLoad); GUI_addButton(data->gui, widget, { 0, 0, 50, -1 }, "Cancel", 0, callbackCancel); break; } data->lowEventStack.Push(event); } break; default: data->lowEventStack.Push(event); break; } break; } case SDL_MOUSEBUTTONDOWN: { data->newBone = -1; if (keyboardState[SDL_SCANCODE_A]) { for (int i = 0; i < data->bones.size(); ++i) { if (pointInRect(mousePos, data->bones[i].rect)) { int name = data->names.push({ "test" }); Bone newBone; newBone.jointAngle = { 1, 0 }; newBone.jointPos = { 0, 0 }; newBone.parentJoint = i; newBone.name = name; Constraint constraint; constraint.minAngle = -PI; constraint.maxAngle = 3 * PI; int newBoneID = data->skeleton.push(newBone); data->constraints.push(constraint); int* ids = new int[data->skeleton.size()]; sortSkeleton(&data->skeleton[0], data->skeleton.size(), ids); Constraint* tempConstraints = new Constraint[data->constraints.size()]; memcpy(tempConstraints, &data->constraints[0], sizeof(Constraint) * data->constraints.size()); for (int i = 0; i < data->constraints.size(); ++i) { data->constraints[i] = tempConstraints[ids[i]]; } delete[] tempConstraints; //find bone again data->newBone = ids[newBoneID]; // rebuild bone selection updateBones(data); delete[]ids; break; } } } else if (keyboardState[SDL_SCANCODE_N]) { for (int i = 0; i < data->bones.size(); ++i) { if (pointInRect(mousePos, data->bones[i].rect)) { int2 pos = pointToPixel(&data->view, float2{ data->bones[i].rect.x + 10, data->bones[i].rect.y }); GUI_WidgetID widget = GUI_addContainer(data->gui, GUI_MAIN_WIDGET, intRect{ pos.x, pos.y, 100, 30 }, GUI_Container::HORIZONTAL); struct Args { EditorData* data; int boneId; }*args = new Args{ data, i }; auto callbackOk = [](GUI* gui, GUI_WidgetID widgetID, void* args) { EditorData* data = ((Args*)args)->data; int boneID = ((Args*)args)->boneId; GUI_WidgetID parentID = GUI_getParentWidget(gui, widgetID); const char* newName = GUI_getTextfield(gui, GUI_getChildWidget(gui, parentID, 0)).text; strcpy(data->names[data->skeleton[boneID].name].string, newName); GUI_removeWidget(gui, parentID); delete args; }; GUI_addTextfield(data->gui, widget, intRect{ 0, 0, -1, -1 }, data->names[data->skeleton[i].name].string); GUI_addButton(data->gui, widget, intRect{ 0, 0, 30, -1 }, "OK", args, callbackOk); break; } } } else { for (int i = 0; i < data->bones.size(); i++) { if (pointInRect(mousePos, data->bones[i].rect)) { data->selectedBones.push(i); data->grabbedBone = i; } } if (data->grabbedBone == -1 && !keyboardState[SDL_SCANCODE_LCTRL]) data->selectedBones.clear(); } break; } case SDL_MOUSEBUTTONUP: { data->grabbedBone = -1; break; } case SDL_MOUSEMOTION: { if (SDL_GetMouseState(0, 0) == SDL_BUTTON_MIDDLE) { data->view.position.x -= (event.motion.xrel / data->view.scale.x); data->view.position.y -= (event.motion.yrel / data->view.scale.y); } else { float2 motion = rotate({ (float)event.motion.xrel, (float)event.motion.yrel }, data->view.angle) * float2{ 1 / data->view.scale.x, 1 / data->view.scale.y }; if (data->newBone != -1) { float2 angle = getBoneWorldTransform(&data->skeleton[0], data->skeleton.size(), data->newBone).angle; float2 rel = rotate(float2{ motion.x, motion.y }, negateRotation(angle)); data->skeleton[data->newBone].jointPos += rel; } if (data->grabbedBone != -1) { if (keyboardState[SDL_SCANCODE_LCTRL]) { float2 angle = getBoneWorldTransform(&data->skeleton[0], data->skeleton.size(), data->skeleton[data->grabbedBone].parentJoint).angle; float2 rel = rotate(float2{ motion.x, motion.y }, negateRotation(angle)); data->skeleton[data->grabbedBone].jointPos += rel; } else { animateCCDIKSelection(&data->skeleton[0], &data->constraints[0], data->skeleton.size(), &data->selectedBones[0], data->selectedBones.size(), data->grabbedBone, mousePos - float2{ 400, 300 }); } } } break; } case SDL_MOUSEWHEEL: { data->view.scale.x += event.wheel.y*0.1f; data->view.scale.y += event.wheel.y*0.1f; break; } } }
/*! Loads the scene from a file and creates materials with textures, the meshes and the nodes for the scene graph. Materials, textures and meshes are added to the according vectors of SLScene for later deallocation. */ SLNode* SLAssimpImporter::load(SLstring file, //!< File with path or on default path SLbool loadMeshesOnly, //!< Only load nodes with meshes SLuint flags) //!< Import flags (see assimp/postprocess.h) { // clear the intermediate data clear(); // Check existance if (!SLFileSystem::fileExists(file)) { file = defaultPath + file; if (!SLFileSystem::fileExists(file)) { SLstring msg = "SLAssimpImporter: File not found: " + file + "\n"; SL_WARN_MSG(msg.c_str()); return nullptr; } } // Import file with assimp importer Assimp::Importer ai; const aiScene* scene = ai.ReadFile(file.c_str(), (SLuint)flags); if (!scene) { SLstring msg = "Failed to load file: " + file + "\n" + ai.GetErrorString() + "\n"; SL_WARN_MSG(msg.c_str()); return nullptr; } // initial scan of the scene performInitialScan(scene); // load skeleton loadSkeleton(nullptr, _skeletonRoot); // load materials SLstring modelPath = SLUtils::getPath(file); SLVMaterial materials; for(SLint i = 0; i < (SLint)scene->mNumMaterials; i++) materials.push_back(loadMaterial(i, scene->mMaterials[i], modelPath)); // load meshes & set their material std::map<int, SLMesh*> meshMap; // map from the ai index to our mesh for(SLint i = 0; i < (SLint)scene->mNumMeshes; i++) { SLMesh* mesh = loadMesh(scene->mMeshes[i]); if (mesh != 0) { mesh->mat = materials[scene->mMeshes[i]->mMaterialIndex]; _meshes.push_back(mesh); meshMap[i] = mesh; } else SL_LOG("SLAsssimpImporter::load failed: %s\nin path: %s\n", file.c_str(), modelPath.c_str()); } // load the scene nodes recursively _sceneRoot = loadNodesRec(nullptr, scene->mRootNode, meshMap, loadMeshesOnly); // load animations vector<SLAnimation*> animations; for (SLint i = 0; i < (SLint)scene->mNumAnimations; i++) animations.push_back(loadAnimation(scene->mAnimations[i])); logMessage(LV_minimal, "\n---------------------------\n\n"); return _sceneRoot; }