Просмотр исходного кода

Add basic animation support to Sprite

Daniele Bartolini 11 лет назад
Родитель
Сommit
d9022345f3

+ 1 - 1
engine/renderers/RenderWorld.cpp

@@ -356,7 +356,7 @@ void RenderWorld::update(const Matrix4x4& view, const Matrix4x4& projection, uin
 	for (uint32_t s = 0; s < id_array::size(m_sprite); s++)
 	{
 		r->set_program(render_world_globals::default_texture_program());
-		// m_sprite[s]->update(dt);
+		m_sprite[s]->update(dt);
 		m_sprite[s]->render(*r, render_world_globals::u_albedo_0, dt);
 	}
 }

+ 33 - 4
engine/renderers/Sprite.cpp

@@ -45,7 +45,9 @@ Sprite::Sprite(RenderWorld& render_world, SceneGraph& sg, int32_t node, const Sp
 	, m_node(node)
 	, m_resource(sr)
 	, m_frame(0)
-	// , m_animator(this)
+	, m_animation(NULL)
+	, m_time(0)
+	, m_loop(false)
 {
 	m_vb = sr->vertex_buffer();
 	m_ib = sr->index_buffer();
@@ -125,19 +127,46 @@ void Sprite::set_frame(uint32_t i)
 //-----------------------------------------------------------------------------
 void Sprite::play_animation(const char* name, bool loop)
 {
-	// m_animator.play_animation(name, loop);
+	if (m_animation)
+		return;
+
+	m_animation = m_resource->get_animation(name);
+	m_time = 0;
+	m_loop = loop;
+	m_frame = m_resource->get_animation_frame(m_animation, m_animation->start_frame);
 }
 
 //-----------------------------------------------------------------------------
 void Sprite::stop_animation()
 {
-	// m_animator.stop_animation();
+	m_animation = NULL;
+	m_time = 0;
+	m_frame = 0;
 }
 
 //-----------------------------------------------------------------------------
 void Sprite::update(float dt)
 {
-	// m_animator.update(dt);
+	if (!m_animation)
+		return;
+
+	m_time += dt;
+
+	if (m_time >= m_animation->time)
+	{
+		if (m_loop)
+		{
+			m_time = 0;
+		}
+		else
+		{
+			stop_animation();
+			return;
+		}
+	}
+
+	uint32_t frame = m_animation->num_frames * (m_time / m_animation->time);
+	m_frame = m_resource->get_animation_frame(m_animation, frame);
 }
 
 //-----------------------------------------------------------------------------

+ 6 - 4
engine/renderers/Sprite.h

@@ -31,7 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Vector3.h"
 #include "Matrix4x4.h"
 #include "Quaternion.h"
-// #include "SpriteAnimator.h"
+#include "SpriteResource.h"
 
 namespace crown
 {
@@ -39,7 +39,6 @@ namespace crown
 class Renderer;
 class RenderWorld;
 class SceneGraph;
-struct SpriteResource;
 struct Unit;
 
 //-----------------------------------------------------------------------------
@@ -76,12 +75,15 @@ public:
 	int32_t					m_node;
 	const SpriteResource*	m_resource;
 
-	uint32_t				m_frame;
 	MaterialId				m_material;
 	VertexBufferId			m_vb;
 	IndexBufferId			m_ib;
 
-	// SpriteAnimator m_animator;
+	uint32_t m_frame;
+
+	const SpriteAnimation* m_animation;
+	float m_time;
+	bool m_loop;
 };
 
 } // namespace crown

+ 102 - 79
engine/resource/SpriteResource.cpp

@@ -35,46 +35,38 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "StringUtils.h"
 #include "Array.h"
 #include "Config.h"
+#include "ReaderWriter.h"
+#include <cfloat>
 
 namespace crown
 {
 namespace sprite_resource
 {
 
-//-----------------------------------------------------------------------------
-struct FrameData
+struct SpriteFrame
 {
-	float x0, y0;
-	float x1, y1;
-
-	float scale_x, scale_y;
-	float offset_x, offset_y;
+	StringId32 name;
+	Vector4 region;		// [x0, y0, x1, y1]
+	Vector2 scale;		// [Sx, Sy]
+	Vector2 offset;		// [Ox, Oy]
 };
 
 //-----------------------------------------------------------------------------
-void parse_frame(JSONElement frame, Array<StringId32>& names, Array<FrameData>& regions)
+void parse_frame(JSONElement e, SpriteFrame& frame)
 {
-	JSONElement name = frame.key("name");
-	JSONElement region = frame.key("region");
-	JSONElement offset = frame.key("offset");
-	JSONElement scale = frame.key("scale");
-
-	DynamicString frame_name;
-	name.to_string(frame_name);
-
-	StringId32 name_hash = string::murmur2_32(frame_name.c_str(), frame_name.length(), 0);
-	FrameData fd;
-	fd.x0 = region[0].to_float();
-	fd.y0 = region[1].to_float();
-	fd.x1 = region[2].to_float();
-	fd.y1 = region[3].to_float();
-	fd.offset_x = offset[0].to_float();
-	fd.offset_y = offset[1].to_float();
-	fd.scale_x = scale[0].to_float();
-	fd.scale_y = scale[1].to_float();
-
-	array::push_back(names, name_hash);
-	array::push_back(regions, fd);
+	frame.name   = e.key("name"  ).to_string_id();
+	frame.region = e.key("region").to_vector4();
+	frame.offset = e.key("offset").to_vector2();
+	frame.scale  = e.key("scale" ).to_vector2();
+}
+
+//-----------------------------------------------------------------------------
+void parse_animation(JSONElement e, SpriteAnimation& anim)
+{
+	anim.name = e.key("name").to_string_id();
+	anim.time = e.key("time").to_float();
+	anim.num_frames = 0;
+	anim.start_frame = 0;
 }
 
 //-----------------------------------------------------------------------------
@@ -86,77 +78,108 @@ void compile(Filesystem& fs, const char* resource_path, File* out_file)
 
 	JSONElement root = json.root();
 
-	float width;
-	float height;
-	Array<StringId32>		m_names(default_allocator());
-	Array<FrameData> 		m_regions(default_allocator());
-	Array<float>			m_vertices(default_allocator());
-	Array<uint16_t>			m_indices(default_allocator());
-
 	// Read width/height
-	width = root.key("width").to_float();
-	height = root.key("height").to_float();
+	const float width  = root.key("width" ).to_float();
+	const float height = root.key("height").to_float();
+	const uint32_t num_frames = root.key("frames").size();
+	const uint32_t num_animations = root.key("animations").size();
 
-	// Read frames
-	JSONElement frames = root.key("frames");
-	uint32_t num_frames = frames.size();
-	for (uint32_t i = 0; i < num_frames; i++)
-	{
-		parse_frame(frames[i], m_names, m_regions);
-	}
+	BinaryWriter bw(*out_file);
 
+	Array<float> vertices(default_allocator());
+	Array<uint16_t> indices(default_allocator());
 	uint32_t num_idx = 0;
 	for (uint32_t i = 0; i < num_frames; i++)
 	{
-		const FrameData& fd = m_regions[i];
+		JSONElement e(root.key("frames")[i]);
+
+		SpriteFrame frame;
+		parse_frame(e, frame);
+
+		const SpriteFrame& fd = frame;
 
 		// Compute uv coords
-		const float u0 = fd.x0 / width;
-		const float v0 = fd.y0 / height;
-		const float u1 = (fd.x0 + fd.x1) / width;
-		const float v1 = (fd.y0 + fd.y1) / height;
+		const float u0 = fd.region.x / width;
+		const float v0 = fd.region.y / height;
+		const float u1 = (fd.region.x + fd.region.z) / width;
+		const float v1 = (fd.region.y + fd.region.w) / height;
 
 		// Compute positions
-		const float w = fd.x1 / CE_PIXELS_PER_METER;
-		const float h = fd.y1 / CE_PIXELS_PER_METER;
+		const float w = fd.region.z / CE_PIXELS_PER_METER;
+		const float h = fd.region.w / CE_PIXELS_PER_METER;
+
+		const float x0 = fd.scale.x * (-w * 0.5) + fd.offset.x;
+		const float y0 = fd.scale.y * (-h * 0.5) + fd.offset.y;
+		const float x1 = fd.scale.x * ( w * 0.5) + fd.offset.x;
+		const float y1 = fd.scale.y * ( h * 0.5) + fd.offset.y;
 
-		const float x0 = fd.scale_x * (-w * 0.5) + fd.offset_x;
-		const float y0 = fd.scale_y * (-h * 0.5) + fd.offset_y;
-		const float x1 = fd.scale_x * ( w * 0.5) + fd.offset_x;
-		const float y1 = fd.scale_y * ( h * 0.5) + fd.offset_y;
+		CE_LOGD("%f %f %f %f", x0, y0, x1, y1);
 
-		array::push_back(m_vertices, x0); array::push_back(m_vertices, y0); // position
-		array::push_back(m_vertices, u0); array::push_back(m_vertices, v0); // uv
+		array::push_back(vertices, x0); array::push_back(vertices, y0); // position
+		array::push_back(vertices, u0); array::push_back(vertices, v0); // uv
 
-		array::push_back(m_vertices, x1); array::push_back(m_vertices, y0); // position
-		array::push_back(m_vertices, u1); array::push_back(m_vertices, v0); // uv
+		array::push_back(vertices, x1); array::push_back(vertices, y0); // position
+		array::push_back(vertices, u1); array::push_back(vertices, v0); // uv
 
-		array::push_back(m_vertices, x1); array::push_back(m_vertices, y1); // position
-		array::push_back(m_vertices, u1); array::push_back(m_vertices, v1); // uv
+		array::push_back(vertices, x1); array::push_back(vertices, y1); // position
+		array::push_back(vertices, u1); array::push_back(vertices, v1); // uv
 
-		array::push_back(m_vertices, x0); array::push_back(m_vertices, y1); // position
-		array::push_back(m_vertices, u0); array::push_back(m_vertices, v1); // uv
+		array::push_back(vertices, x0); array::push_back(vertices, y1); // position
+		array::push_back(vertices, u0); array::push_back(vertices, v1); // uv
 
-		array::push_back(m_indices, uint16_t(num_idx)); array::push_back(m_indices, uint16_t(num_idx + 1)); array::push_back(m_indices, uint16_t(num_idx + 2));
-		array::push_back(m_indices, uint16_t(num_idx)); array::push_back(m_indices, uint16_t(num_idx + 2)); array::push_back(m_indices, uint16_t(num_idx + 3));
+		array::push_back(indices, uint16_t(num_idx)); array::push_back(indices, uint16_t(num_idx + 1)); array::push_back(indices, uint16_t(num_idx + 2));
+		array::push_back(indices, uint16_t(num_idx)); array::push_back(indices, uint16_t(num_idx + 2)); array::push_back(indices, uint16_t(num_idx + 3));
 		num_idx += 4;
 	}
 
-	SpriteHeader h;
-	h.num_frames = array::size(m_names);
-	h.num_vertices = array::size(m_vertices) / 4; // 4 components per vertex
-	h.num_indices = array::size(m_indices);
+	const uint32_t num_vertices = array::size(vertices) / 4; // 4 components per vertex
+	const uint32_t num_indices = array::size(indices);
+
+	// Write animations
+	Array<SpriteAnimation> animations(default_allocator());
+	Array<uint32_t> frames(default_allocator());
+
+	for (uint32_t i = 0; i < num_animations; i++)
+	{
+		JSONElement e(root.key("animations")[i]);
+
+		SpriteAnimation anim;
+		parse_animation(e, anim);
+
+		// Read frames
+		const uint32_t num_frames = e.key("frames").size();
+
+		anim.num_frames = num_frames;
+		anim.start_frame = array::size(frames); // Relative offset
+
+		for (uint32_t ff = 0; ff < num_frames; ff++)
+			array::push_back(frames, (uint32_t) e.key("frames")[ff].to_int());
+
+		array::push_back(animations, anim);
+	}
+
+	// Write header
+	bw.write(uint32_t(0)); // vb
+	bw.write(uint32_t(0)); // ib
+	bw.write(num_animations); uint32_t offt = sizeof(SpriteHeader);
+	bw.write(offt);
+	bw.write(num_vertices); offt += sizeof(SpriteAnimation) * array::size(animations) + sizeof(uint32_t) * array::size(frames);
+	bw.write(offt);
+	bw.write(num_indices); offt += sizeof(float) * array::size(vertices);
+	bw.write(offt);
+
+	if (array::size(animations))
+		bw.write(array::begin(animations), sizeof(SpriteAnimation) * array::size(animations));
+
+	if (array::size(frames))
+		bw.write(array::begin(frames), sizeof(uint32_t) * array::size(frames));
 
-	uint32_t offt = sizeof(SpriteHeader);
-	/*h.frame_names_offset    = offt*/; offt += sizeof(StringId32) * h.num_frames;
-	h.vertices_offset = offt; offt += sizeof(float) * array::size(m_vertices);
-	h.indices_offset = offt; offt += sizeof(uint16_t) * array::size(m_indices);
+	if (array::size(vertices))
+		bw.write(array::begin(vertices), sizeof(float) * array::size(vertices));
 
-	out_file->write((char*) &h, sizeof(SpriteHeader));
-	out_file->write((char*) array::begin(m_names), sizeof(StringId32) * array::size(m_names));
-	out_file->write((char*) array::begin(m_vertices), sizeof(float) * array::size(m_vertices));
-	out_file->write((char*) array::begin(m_indices), sizeof(uint16_t) * array::size(m_indices));
+	if (array::size(indices))
+		bw.write(array::begin(indices), sizeof(uint16_t) * array::size(indices));
 }
 
 } // namespace sprite_resource
-} // namespace crown
+} // namespace crown

+ 31 - 8
engine/resource/SpriteResource.h

@@ -42,26 +42,31 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include "Renderer.h"
 #include "TextureResource.h"
 
-#define MAX_SPRITE_ANIM_FRAMES 60
-#define SPRITE_FRAME_SIZE 4 * 4 * 4
-
 namespace crown
 {
 
 const uint32_t SPRITE_VERSION = 1;
 
-//-----------------------------------------------------------------------------
 struct SpriteHeader
 {
 	VertexBufferId 	vb;
 	IndexBufferId 	ib;
-	uint32_t 		num_frames;
+	uint32_t		num_animations;
+	uint32_t		animations_offset;
 	uint32_t		num_vertices;
 	uint32_t		vertices_offset;
 	uint32_t		num_indices;
 	uint32_t		indices_offset;
 };
 
+struct SpriteAnimation
+{
+	StringId32 name;
+	float time;
+	uint32_t num_frames;
+	uint32_t start_frame;
+};
+
 //-----------------------------------------------------------------------------
 struct SpriteResource
 {
@@ -111,9 +116,27 @@ struct SpriteResource
 	}
 
 	//-----------------------------------------------------------------------------
-	uint32_t num_frames() const
+	const SpriteAnimation* get_animation(const char* name) const
+	{
+		SpriteHeader* h = (SpriteHeader*) this;
+		SpriteAnimation* begin = (SpriteAnimation*) (((char*) this) + h->animations_offset);
+
+		const StringId32 name_hash = string::murmur2_32(name, string::strlen(name));
+		const uint32_t num = h->num_animations;
+		for (uint32_t i = 0; i < num; i++)
+		{
+			if (begin[i].name == name_hash)
+				return &begin[i];
+		}
+
+		return NULL;
+	}
+
+	uint32_t get_animation_frame(const SpriteAnimation* a, uint32_t frame) const
 	{
-		return ((SpriteHeader*) this)->num_frames;
+		SpriteHeader* h = (SpriteHeader*) this;
+		uint32_t* begin = (uint32_t*) (((char*) this) + h->animations_offset + sizeof(SpriteAnimation) * h->num_animations);
+		return begin[a->start_frame + frame];
 	}
 
 	//-----------------------------------------------------------------------------
@@ -134,4 +157,4 @@ private:
 	SpriteResource();
 };
 
-} // namespace crown
+} // namespace crown

+ 2 - 2
engine/world/Unit.cpp

@@ -569,13 +569,13 @@ bool Unit::is_a(const char* name)
 //-----------------------------------------------------------------------------
 void Unit::play_sprite_animation(const char* name, bool loop)
 {
-	// sprite((uint32_t) 0)->play_animation(name, loop);
+	sprite(0u)->play_animation(name, loop);
 }
 
 //-----------------------------------------------------------------------------
 void Unit::stop_sprite_animation()
 {
-	// sprite((uint32_t) 0)->stop_animation();
+	sprite(0u)->stop_animation();
 }
 
 //-----------------------------------------------------------------------------