ソースを参照

Transform animations begin

Michael 7 年 前
コミット
a1ea7c5668

+ 13 - 0
Include/Rocket/Core/TransformPrimitive.h

@@ -94,6 +94,12 @@ class ResolvedValuesPrimitive : public Primitive
 		ResolvedValuesPrimitive(const NumericValue* values) throw()
 			{ for (size_t i = 0; i < N; ++i) this->values[i] = values[i].number; }
 
+		void InterpolateValues(const ResolvedValuesPrimitive<N>& other, float alpha)
+		{
+			for (size_t i = 0; i < N; i++)
+				values[i] = values[i]*(1.0f - alpha) + other.values[i] * alpha;
+		}
+
 	protected:
 		float values[N];
 };
@@ -105,6 +111,13 @@ class UnresolvedValuesPrimitive : public Primitive
 		UnresolvedValuesPrimitive(const NumericValue* values) throw()
 			{ memcpy(this->values, values, sizeof(this->values)); }
 
+		void InterpolateValues(const UnresolvedValuesPrimitive<N>& other, float alpha)
+		{
+			// TODO: Convert between different units?
+			for (size_t i = 0; i < N; i++)
+				values[i].number = values[i].number*(1.0f - alpha) + other.values[i].number * alpha;
+		}
+
 	protected:
 		NumericValue values[N];
 };

+ 11 - 4
Samples/basic/animation/data/animation.rml

@@ -19,6 +19,13 @@
 			display: inline-block;
 			width: 25px;
 		}
+		
+		#start_game 
+		{
+			opacity: 0.5;
+			transform: rotate(10);
+			transform-origin: 30% 80% 0;
+		}
 
 		#high_score {
 			margin-left: -100px;
@@ -27,10 +34,10 @@
 </head>
 
 <body template="window">
-	<button>Start Game</button><br />
-	<button id="high_score">High Scores</button><br />
-	<button>Options</button><br />
+	<button id="start_game">Start Game</button><br />
+	<button id="high_score" onkeydown="hello">High Scores</button><br />
+	<button id="options">Options</button><br />
 	<button id="help">Help</button><br />
-	<button id="exit">Exit</button>
+	<button id="exit" onclick="exit">Exit</button>
 </body>
 </rml>

+ 97 - 14
Samples/basic/animation/src/main.cpp

@@ -30,6 +30,7 @@
 #include <Rocket/Debugger.h>
 #include <Input.h>
 #include <Shell.h>
+#include <Rocket/Core/TransformPrimitive.h>
 
 #include <cmath>
 #include <sstream>
@@ -39,26 +40,35 @@ class DemoWindow
 public:
 	DemoWindow(const Rocket::Core::String &title, const Rocket::Core::Vector2f &position, Rocket::Core::Context *context)
 	{
+		using namespace Rocket::Core;
 		document = context->LoadDocument("basic/animation/data/animation.rml");
 		if (document != NULL)
 		{
 			document->GetElementById("title")->SetInnerRML(title);
-			document->SetProperty("left", Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
-			document->SetProperty("top", Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
+			document->SetProperty("left", Property(position.x, Property::PX));
+			document->SetProperty("top", Property(position.y, Property::PX));
+			document->Animate("opacity", Property(0.6f, Property::NUMBER), 0.5f, -1, true);
 
 			auto el = document->GetElementById("high_score");
-			el->Animate("margin-left", Rocket::Core::Property(0.f, Rocket::Core::Property::PX), 0.3f, 10, true);
-			el->Animate("margin-left", Rocket::Core::Property(100.f, Rocket::Core::Property::PX), 0.6f);
+			el->Animate("margin-left", Property(0.f, Property::PX), 0.3f, 10, true);
+			el->Animate("margin-left", Property(100.f, Property::PX), 0.6f);
 
 			el = document->GetElementById("exit");
-			el->Animate("margin-left", Rocket::Core::Property(100.f, Rocket::Core::Property::PX), 8.0f, -1, true);
+			el->Animate("margin-left", Property(100.f, Property::PX), 8.0f, -1, true);
+
+			el = document->GetElementById("start_game");
+			auto transform = new Transform;
+			auto value = Transforms::NumericValue(370.f, Property::DEG);
+			transform->AddPrimitive(Transforms::Rotate2D{ &value });
+			TransformRef tref{ transform };
+			el->Animate("transform", Property(tref, Property::TRANSFORM), 0.8f, -1, false);
 
 			el = document->GetElementById("help");
-			el->Animate("image-color", Rocket::Core::Property(Rocket::Core::Colourb(128, 255, 255, 255), Rocket::Core::Property::COLOUR), 0.3f, -1, false);
-			el->Animate("image-color", Rocket::Core::Property(Rocket::Core::Colourb(128, 128, 255, 255), Rocket::Core::Property::COLOUR), 0.3f);
-			el->Animate("image-color", Rocket::Core::Property(Rocket::Core::Colourb(0, 128, 128, 255), Rocket::Core::Property::COLOUR), 0.3f);
-			el->Animate("image-color", Rocket::Core::Property(Rocket::Core::Colourb(64, 128, 255, 0), Rocket::Core::Property::COLOUR), 0.9f);
-			el->Animate("image-color", Rocket::Core::Property(Rocket::Core::Colourb(255, 255, 255, 255), Rocket::Core::Property::COLOUR), 0.3f);
+			el->Animate("image-color", Property(Colourb(128, 255, 255, 255), Property::COLOUR), 0.3f, -1, false);
+			el->Animate("image-color", Property(Colourb(128, 128, 255, 255), Property::COLOUR), 0.3f);
+			el->Animate("image-color", Property(Colourb(0, 128, 128, 255), Property::COLOUR), 0.3f);
+			el->Animate("image-color", Property(Colourb(64, 128, 255, 0), Property::COLOUR), 0.9f);
+			el->Animate("image-color", Property(Colourb(255, 255, 255, 255), Property::COLOUR), 0.3f);
 
 			document->Show();
 		}
@@ -86,13 +96,21 @@ Rocket::Core::Context* context = NULL;
 ShellRenderInterfaceExtensions *shell_renderer;
 DemoWindow* window = NULL;
 
+bool pause_loop = false;
+bool single_loop = false;
+
 void GameLoop()
 {
-	context->Update();
+	if(!pause_loop || single_loop)
+	{
+		context->Update();
 
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
+		shell_renderer->PrepareRenderBuffer();
+		context->Render();
+		shell_renderer->PresentRenderBuffer();
+
+		single_loop = false;
+	}
 
 	//auto el = window->GetDocument()->GetElementById("exit");
 	//auto f = el->GetProperty<int>("margin-left");
@@ -103,6 +121,64 @@ void GameLoop()
 	//	Rocket::Core::Log::Message(Rocket::Core::Log::LT_INFO, "Animation f = %d,  df = %d", f, df);
 }
 
+
+
+class Event : public Rocket::Core::EventListener
+{
+public:
+	Event(const Rocket::Core::String& value) : value(value) {}
+
+	void ProcessEvent(Rocket::Core::Event& event) override
+	{
+		if(value == "exit")
+			Shell::RequestExit();
+
+		if (event == "keydown" ||
+			event == "keyup")
+		{
+			bool key_down = event == "keydown";
+			Rocket::Core::Input::KeyIdentifier key_identifier = (Rocket::Core::Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0);
+
+			if (key_identifier == Rocket::Core::Input::KI_SPACE && key_down)
+			{
+				pause_loop = !pause_loop;
+			}
+			else if (key_identifier == Rocket::Core::Input::KI_RETURN && key_down)
+			{
+				pause_loop = true;
+				single_loop = true;
+			}
+			else if (key_identifier == Rocket::Core::Input::KI_ESCAPE)
+			{
+				Shell::RequestExit();
+			}
+		}
+	}
+
+	void OnDetach(Rocket::Core::Element* element) override { delete this; }
+
+private:
+	Rocket::Core::String value;
+};
+
+
+class EventInstancer : public Rocket::Core::EventListenerInstancer
+{
+public:
+
+	/// Instances a new event handle for Invaders.
+	Rocket::Core::EventListener* InstanceEventListener(const Rocket::Core::String& value, Rocket::Core::Element* element) override
+	{
+		return new Event(value);
+	}
+
+	/// Destroys the instancer.
+	void Release() override { delete this; }
+};
+
+
+
+
 #if defined ROCKET_PLATFORM_WIN32
 #include <windows.h>
 int APIENTRY WinMain(HINSTANCE ROCKET_UNUSED_PARAMETER(instance_handle), HINSTANCE ROCKET_UNUSED_PARAMETER(previous_instance_handle), char* ROCKET_UNUSED_PARAMETER(command_line), int ROCKET_UNUSED_PARAMETER(command_show))
@@ -154,9 +230,16 @@ int main(int ROCKET_UNUSED_PARAMETER(argc), char** ROCKET_UNUSED_PARAMETER(argv)
 	Input::SetContext(context);
 	shell_renderer->SetContext(context);
 
+
+	EventInstancer* event_instancer = new EventInstancer();
+	Rocket::Core::Factory::RegisterEventListenerInstancer(event_instancer);
+	event_instancer->RemoveReference();
+
 	Shell::LoadFonts("assets/");
 
 	window = new DemoWindow("Animation sample", Rocket::Core::Vector2f(81, 200), context);
+	window->GetDocument()->AddEventListener("keydown", new Event("hello"));
+	window->GetDocument()->AddEventListener("keyup", new Event("hello"));
 
 
 	Shell::EventLoop(GameLoop);

+ 3 - 1
Source/Core/Element.cpp

@@ -907,7 +907,9 @@ void Element::Animate(const String & property_name, const Property & target_valu
 	if (!animation)
 	{
 		float time = Clock::GetElapsedTime();
-		auto property = GetProperty(property_name);
+		const Property* property = GetProperty(property_name);
+		if (!property) return;
+
 		ElementAnimation new_animation{ property_name, *property, time, duration, num_iterations, alternate_direction };
 		animations.push_back(new_animation);
 		animation = &animations.back();

+ 94 - 14
Source/Core/ElementAnimation.cpp

@@ -28,6 +28,7 @@
 #include "precompiled.h"
 #include "ElementAnimation.h"
 #include "../../Include/Rocket/Core/Element.h"
+#include "../../Include/Rocket/Core/TransformPrimitive.h"
 
 namespace Rocket {
 namespace Core {
@@ -54,37 +55,116 @@ static Colourb ColourFromLinearSpace(Colourf c)
 	return result;
 }
 
-static Variant InterpolateValues(const Variant & from, const Variant & to, float alpha)
+template<size_t N>
+static bool TryInterpolatePrimitive(Rocket::Core::Transforms::Primitive* p_inout, const Rocket::Core::Transforms::Primitive* p1, float alpha)
 {
-	auto type = from.GetType();
-	auto type_to = to.GetType();
-	if (type != type_to)
+	using namespace Rocket::Core::Transforms;
+	bool result = false;
+	if (auto values0 = dynamic_cast<UnresolvedValuesPrimitive< N >*>(p_inout))
 	{
-		Log::Message(Log::LT_WARNING, "Interpolating properties must be of same unit. Got types: '%c' and '%c'.", type, type_to);
-		return from;
+		auto values1 = dynamic_cast<const UnresolvedValuesPrimitive< N >*>(p1);
+		if (values1) {
+			values0->InterpolateValues(*values1, alpha);
+			result = true;
+		}
+	}
+	return result;
+}
+template<size_t N>
+static bool TryInterpolateResolvedPrimitive(Rocket::Core::Transforms::Primitive* p_inout, const Rocket::Core::Transforms::Primitive* p1, float alpha)
+{
+	using namespace Rocket::Core::Transforms;
+	bool result = false;
+	if (auto values0 = dynamic_cast<ResolvedValuesPrimitive< N >*>(p_inout))
+	{
+		auto values1 = dynamic_cast<const ResolvedValuesPrimitive< N >*>(p1);
+		if (values1) {
+			values0->InterpolateValues(*values1, alpha);
+			result = true;
+		}
+	}
+	return result;
+}
+
+static Variant InterpolateValues(const Variant & v0, const Variant & v1, float alpha)
+{
+	auto type0 = v0.GetType();
+	auto type1 = v1.GetType();
+	if (type0 != type1)
+	{
+		Log::Message(Log::LT_WARNING, "Interpolating properties must be of same unit. Got types: '%c' and '%c'.", type0, type1);
+		return v0;
 	}
 
-	switch (type)
+	switch (type0)
 	{
 	case Variant::FLOAT:
 	{
-		float f0 = from.Get<float>();
-		float f1 = to.Get<float>();
+		float f0 = v0.Get<float>();
+		float f1 = v1.Get<float>();
 		float f = (1.0f - alpha) * f0 + alpha * f1;
 		return Variant(f);
 	}
 	case Variant::COLOURB:
 	{
-		Colourf c0 = ColourToLinearSpace(from.Get<Colourb>());
-		Colourf c1 = ColourToLinearSpace(to.Get<Colourb>());
+		Colourf c0 = ColourToLinearSpace(v0.Get<Colourb>());
+		Colourf c1 = ColourToLinearSpace(v1.Get<Colourb>());
 		Colourf c = c0 * (1.0f - alpha) + c1 * alpha;
 		return Variant(ColourFromLinearSpace(c));
 	}
+	case Variant::TRANSFORMREF:
+	{
+		using namespace Rocket::Core::Transforms;
+
+		auto t0 = v0.Get<TransformRef>();
+		auto t1 = v1.Get<TransformRef>();
+		Primitive* p0 = t0->GetPrimitive(0).Clone();
+		const Primitive* p1 = &t1->GetPrimitive(0);
+
+
+		bool success = false;
+
+		// Todo: Check carefully for memory leaks
+		// Todo: Lots of dynamic dispatch, not good!
+		if (TryInterpolateResolvedPrimitive<1>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolateResolvedPrimitive<2>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolateResolvedPrimitive<3>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolateResolvedPrimitive<4>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolateResolvedPrimitive<6>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolateResolvedPrimitive<16>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolatePrimitive<1>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolatePrimitive<2>(p0, p1, alpha))
+			success = true;
+		else if (TryInterpolatePrimitive<3>(p0, p1, alpha))
+			success = true;
+
+
+		if(success)
+		{
+			auto transform = new Transform;
+			transform->AddPrimitive(*p0);
+			TransformRef tref{ transform };
+			delete p0;
+			return Variant(tref);
+		}
+		else
+		{
+			delete p0;
+		}
+		Log::Message(Log::LT_WARNING, "Could not decode transform for interpolation.");
+	}
 	}
 
-	Log::Message(Log::LT_WARNING, "Currently, only float and color values can be interpolated. Got types of: '%c'.", type);
+	Log::Message(Log::LT_WARNING, "Currently, only float and color values can be interpolated. Got types of: '%c'.", type0);
 
-	return from;
+	return v0;
 }
 
 
@@ -109,7 +189,7 @@ Property ElementAnimation::UpdateAndGetProperty(float time)
 	if (animation_complete || time - last_update_time <= 0.0f)
 		return result;
 
-	const float dt = time - last_update_time;
+	const float dt = 0.01f;// time - last_update_time;
 
 	last_update_time = time;
 	time_since_iteration_start += dt;

+ 1 - 1
Source/Core/StyleSheetSpecification.cpp

@@ -244,7 +244,7 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 	RegisterProperty(COLOR, "white", true, false).AddParser(COLOR);
 
 	RegisterProperty(IMAGE_COLOR, "white", false, false).AddParser(COLOR);
-	RegisterProperty(OPACITY, "1", false, false).AddParser("number");
+	RegisterProperty(OPACITY, "1", true, false).AddParser("number");
 
 	RegisterProperty(FONT_FAMILY, "", true, true).AddParser("string");
 	RegisterProperty(FONT_CHARSET, "U+0020-007E", true, false).AddParser("string");