SpriteObj* Sprite_Clone(SpriteObj* other) { SpriteObj* sprite = new SpriteObj(); sprite->resource = other->resource; Resource_IncRefCount(sprite->resource); Sprite_PlayAnimation(sprite); return sprite; }
void Sprite::PlayAnimation(const std::string& name, AnimationMode mode, float transitionTime) { if (obj) Sprite_PlayAnimation(obj, name, mode, transitionTime); }
SpriteObj* Sprite_Create(const std::string& name, bool immediate) { immediate = immediate || !g_supportAsynchronousResourceLoading; SpriteResource* resource = static_cast<SpriteResource*>(Resource_Find("sprite", name)); if (resource) Resource_IncRefCount(resource); // Create sprite from XML else if (!strstr(name.c_str(), ".")) { const std::string path = name + ".sprite.xml"; XMLDoc doc; if (!doc.Load(path)) { Log::Error("Failed to load sprite resource from " + path); return NULL; } XMLNode* spriteNode = doc.AsNode()->GetFirstNode("sprite"); if (!spriteNode) { Log::Error("Failed to load sprite resource from " + path + ", reason: root node 'sprite' not found."); return NULL; } MaterialObj* material = NULL; if (const char* materialName = XMLNode_GetAttributeValue(spriteNode, "material")) { material = Material_Create(materialName); if (!material) { Log::Error("Failed to load sprite resource from " + path + ", reason: can't load material " + materialName); return NULL; } } resource = new SpriteResource(); resource->state = ResourceState_CreationInProgress; resource->name = name; Material_SetHandle(material, resource->material); Resource_IncRefCount(resource); // Load animations std::string defaultAnimationName; for (XMLNode* animNode = XMLNode_GetFirstNode(spriteNode, "animation"); animNode; animNode = XMLNode_GetNext(animNode, "animation")) { const std::string name = XMLNode_GetAttributeValue(animNode, "name"); SpriteResource::Animation& anim = map_add(resource->animations, name); anim.name = name; // Get frame time XMLNode_GetAttributeValueFloat(animNode, "frameTime", anim.frameTime, 0.1f); // Check blend mode //XMLNode_GetAttributeValueBool(animNode, "blending", anim->blendFrames); // Check if default bool isDefault; if (defaultAnimationName.empty() || (XMLNode_GetAttributeValueBool(animNode, "isDefault", isDefault) && isDefault)) defaultAnimationName = anim.name; // Load all frames and events float time = 0.0f; for (XMLNode* elemNode = XMLNode_GetFirstNode(animNode); elemNode; elemNode = XMLNode_GetNext(elemNode)) { const char* elemName = XMLNode_GetName(elemNode); if (!strcmp(elemName, "frame")) { SpriteResource::Frame& frame = vector_add(anim.frames); const char* textureName = XMLNode_GetAttributeValue(elemNode, "texture"); frame.texture.Create(textureName, immediate); if (!frame.texture.IsValid()) { Log::Error("Failed to load sprite resource from " + path + ", reason: failed to load texture " + textureName); delete resource; return NULL; } time += anim.frameTime; } else if (!strcmp(elemName, "event")) { SpriteResource::Event& ev = vector_add(anim.events); ev.time = time; ev.name = XMLNode_GetAttributeValue(elemNode, "name"); } } anim.totalTime = (float) anim.frames.size() * anim.frameTime; } resource->defaultAnimation = &resource->animations[defaultAnimationName]; SpriteResource_CheckCreated(resource); } // Create sprite from texture else { TextureObj* texture = Texture_Create(name, immediate); if (!texture) { Log::Error("Failed to create sprite resource from texture " + name); return NULL; } resource = new SpriteResource(); resource->state = ResourceState_CreationInProgress; resource->name = name; Resource_IncRefCount(resource); // Add simple animation with one animation frame SpriteResource::Animation& animation = map_add(resource->animations, resource->name); animation.frameTime = 1.0f; animation.totalTime = 1.0f; SpriteResource::Frame& frame = vector_add(animation.frames); Texture_SetHandle(texture, frame.texture); resource->defaultAnimation = &animation; SpriteResource_CheckCreated(resource); Texture_Destroy(texture); } if (!resource) return NULL; // Create sprite SpriteObj* sprite = new SpriteObj(); sprite->resource = resource; Sprite_PlayAnimation(sprite); return sprite; }
void Sprite_Update(SpriteObj* sprite, float dt) { std::vector<SpriteObj::AnimationInstance> animationInstancesCopy = sprite->animationInstances; sprite->animationInstances.clear(); bool doneAnim = false; SpriteObj::AnimationInstance* instWhenDone = NULL; for (std::vector<SpriteObj::AnimationInstance>::iterator it = animationInstancesCopy.begin(); it != animationInstancesCopy.end(); ++it) { const float prevInstTime = it->time; if (it->mode == Sprite::AnimationMode_OnceWhenDone || it->mode == Sprite::AnimationMode_LoopWhenDone) instWhenDone = &(*it); else it->time += dt; if (it->time >= it->animation->totalTime) { switch (it->mode) { case Sprite::AnimationMode_Loop: it->time = fmod(it->time, it->animation->totalTime); Sprite_FireAnimationEvents(sprite, it->animation, prevInstTime, it->time, dt); doneAnim = true; break; case Sprite::AnimationMode_Once: Sprite_FireAnimationEvents(sprite, it->animation, prevInstTime, it->animation->totalTime, dt); doneAnim = true; continue; case Sprite::AnimationMode_OnceAndFreeze: it->time = it->animation->totalTime; Sprite_FireAnimationEvents(sprite, it->animation, prevInstTime, it->time, dt); break; default: Assert(!"Unsupported sprite animation mode"); break; } } else Sprite_FireAnimationEvents(sprite, it->animation, prevInstTime, it->time, dt); it->weight += it->weightChangeSpeed * dt; if (it->weight <= 0.0f) continue; if (it->weight >= 1.0f) { it->weight = 1.0f; it->weightChangeSpeed = 0.0f; } sprite->animationInstances.push_back(*it); } // Kick off "when done" instance if ((doneAnim || sprite->animationInstances.size() == 1) && instWhenDone) { instWhenDone->mode = (instWhenDone->mode == Sprite::AnimationMode_OnceWhenDone) ? Sprite::AnimationMode_Once : Sprite::AnimationMode_Loop; instWhenDone->weight = 1.0f; SpriteObj::AnimationInstance instWhenDoneObj = *instWhenDone; sprite->animationInstances.clear(); sprite->animationInstances.push_back(instWhenDoneObj); } // Start default animation if there's no animations left if (!sprite->animationInstances.size()) Sprite_PlayAnimation(sprite); }