blob: 875e9fc1d9fb4c653ebfeb5e14a875d18889c597 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cmath>
#include <memory>
#include <vector>
#include "flutter/fml/mapping.h"
#include "flutter/testing/testing.h"
#include "impeller/core/formats.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/constants.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/quaternion.h"
#include "impeller/geometry/vector.h"
#include "impeller/image/decompressed_image.h"
#include "impeller/playground/playground.h"
#include "impeller/playground/playground_test.h"
#include "impeller/scene/animation/animation_clip.h"
#include "impeller/scene/camera.h"
#include "impeller/scene/geometry.h"
#include "impeller/scene/importer/scene_flatbuffers.h"
#include "impeller/scene/material.h"
#include "impeller/scene/mesh.h"
#include "impeller/scene/scene.h"
#include "third_party/flatbuffers/include/flatbuffers/verifier.h"
#include "third_party/imgui/imgui.h"
namespace impeller {
namespace scene {
namespace testing {
using SceneTest = PlaygroundTest;
INSTANTIATE_PLAYGROUND_SUITE(SceneTest);
TEST_P(SceneTest, CuboidUnlit) {
auto scene_context = std::make_shared<SceneContext>(GetContext());
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
auto allocator = GetContext()->GetResourceAllocator();
auto scene = Scene(scene_context);
{
Mesh mesh;
auto material = Material::MakeUnlit();
material->SetColor(Color::Red());
Vector3 size(1, 1, 0);
mesh.AddPrimitive({Geometry::MakeCuboid(size), std::move(material)});
Node& root = scene.GetRoot();
root.SetLocalTransform(Matrix::MakeTranslation(-size / 2));
root.SetMesh(std::move(mesh));
}
// Face towards the +Z direction (+X right, +Y up).
auto camera = Camera::MakePerspective(
/* fov */ Radians(kPiOver4),
/* position */ {2, 2, -5})
.LookAt(
/* target */ Vector3(),
/* up */ {0, 1, 0});
scene.Render(render_target, camera);
return true;
};
OpenPlaygroundHere(callback);
}
TEST_P(SceneTest, FlutterLogo) {
auto allocator = GetContext()->GetResourceAllocator();
auto mapping =
flutter::testing::OpenFixtureAsMapping("flutter_logo_baked.glb.ipscene");
ASSERT_NE(mapping, nullptr);
flatbuffers::Verifier verifier(mapping->GetMapping(), mapping->GetSize());
ASSERT_TRUE(fb::VerifySceneBuffer(verifier));
std::shared_ptr<Node> gltf_scene =
Node::MakeFromFlatbuffer(*mapping, *allocator);
ASSERT_NE(gltf_scene, nullptr);
ASSERT_EQ(gltf_scene->GetChildren().size(), 1u);
ASSERT_EQ(gltf_scene->GetChildren()[0]->GetMesh().GetPrimitives().size(), 1u);
auto scene_context = std::make_shared<SceneContext>(GetContext());
auto scene = Scene(scene_context);
scene.GetRoot().AddChild(std::move(gltf_scene));
scene.GetRoot().SetLocalTransform(Matrix::MakeScale({3, 3, 3}));
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
Quaternion rotation({0, 1, 0}, -GetSecondsElapsed() * 0.5);
Vector3 start_position(-1, -1.5, -5);
// Face towards the +Z direction (+X right, +Y up).
auto camera = Camera::MakePerspective(
/* fov */ Degrees(60),
/* position */ rotation * start_position)
.LookAt(
/* target */ Vector3(),
/* up */ {0, 1, 0});
scene.Render(render_target, camera);
return true;
};
OpenPlaygroundHere(callback);
}
TEST_P(SceneTest, TwoTriangles) {
if (GetBackend() == PlaygroundBackend::kVulkan) {
GTEST_SKIP_("Temporarily disabled.");
}
auto allocator = GetContext()->GetResourceAllocator();
auto mapping =
flutter::testing::OpenFixtureAsMapping("two_triangles.glb.ipscene");
ASSERT_NE(mapping, nullptr);
std::shared_ptr<Node> gltf_scene =
Node::MakeFromFlatbuffer(*mapping, *allocator);
ASSERT_NE(gltf_scene, nullptr);
auto animation = gltf_scene->FindAnimationByName("Metronome");
ASSERT_NE(animation, nullptr);
AnimationClip* metronome_clip = gltf_scene->AddAnimation(animation);
ASSERT_NE(metronome_clip, nullptr);
metronome_clip->SetLoop(true);
metronome_clip->Play();
auto scene_context = std::make_shared<SceneContext>(GetContext());
auto scene = Scene(scene_context);
scene.GetRoot().AddChild(std::move(gltf_scene));
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
{
static Scalar playback_time_scale = 1;
static Scalar weight = 1;
static bool loop = true;
ImGui::SliderFloat("Playback time scale", &playback_time_scale, -5, 5);
ImGui::SliderFloat("Weight", &weight, -2, 2);
ImGui::Checkbox("Loop", &loop);
if (ImGui::Button("Play")) {
metronome_clip->Play();
}
if (ImGui::Button("Pause")) {
metronome_clip->Pause();
}
if (ImGui::Button("Stop")) {
metronome_clip->Stop();
}
metronome_clip->SetPlaybackTimeScale(playback_time_scale);
metronome_clip->SetWeight(weight);
metronome_clip->SetLoop(loop);
}
ImGui::End();
Node& node = *scene.GetRoot().GetChildren()[0];
node.SetLocalTransform(node.GetLocalTransform() *
Matrix::MakeRotation(0.02, {0, 1, 0, 0}));
static ImVec2 mouse_pos_prev = ImGui::GetMousePos();
ImVec2 mouse_pos = ImGui::GetMousePos();
Vector2 mouse_diff =
Vector2(mouse_pos.x - mouse_pos_prev.x, mouse_pos.y - mouse_pos_prev.y);
static Vector3 position(0, 1, -5);
static Vector3 cam_position = position;
auto strafe =
Vector3(ImGui::IsKeyDown(ImGuiKey_D) - ImGui::IsKeyDown(ImGuiKey_A),
ImGui::IsKeyDown(ImGuiKey_E) - ImGui::IsKeyDown(ImGuiKey_Q),
ImGui::IsKeyDown(ImGuiKey_W) - ImGui::IsKeyDown(ImGuiKey_S));
position += strafe * 0.5;
cam_position = cam_position.Lerp(position, 0.02);
// Face towards the +Z direction (+X right, +Y up).
auto camera = Camera::MakePerspective(
/* fov */ Degrees(60),
/* position */ cam_position)
.LookAt(
/* target */ cam_position + Vector3(0, 0, 1),
/* up */ {0, 1, 0});
scene.Render(render_target, camera);
return true;
};
OpenPlaygroundHere(callback);
}
TEST_P(SceneTest, Dash) {
auto allocator = GetContext()->GetResourceAllocator();
auto mapping = flutter::testing::OpenFixtureAsMapping("dash.glb.ipscene");
if (!mapping) {
// TODO(bdero): Just skip this playground is the dash asset isn't found. I
// haven't checked it in because it's way too big right now,
// but this is still useful to keep around for debugging
// purposes.
return;
}
ASSERT_NE(mapping, nullptr);
std::shared_ptr<Node> gltf_scene =
Node::MakeFromFlatbuffer(*mapping, *allocator);
ASSERT_NE(gltf_scene, nullptr);
auto walk_anim = gltf_scene->FindAnimationByName("Walk");
ASSERT_NE(walk_anim, nullptr);
AnimationClip* walk_clip = gltf_scene->AddAnimation(walk_anim);
ASSERT_NE(walk_clip, nullptr);
walk_clip->SetLoop(true);
walk_clip->Play();
auto run_anim = gltf_scene->FindAnimationByName("Run");
ASSERT_NE(walk_anim, nullptr);
AnimationClip* run_clip = gltf_scene->AddAnimation(run_anim);
ASSERT_NE(run_clip, nullptr);
run_clip->SetLoop(true);
run_clip->Play();
auto scene_context = std::make_shared<SceneContext>(GetContext());
auto scene = Scene(scene_context);
scene.GetRoot().AddChild(std::move(gltf_scene));
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
{
static Scalar playback_time_scale = 1;
static Scalar walk = 0.5;
static Scalar run = 0.5;
static bool loop = true;
ImGui::SliderFloat("Playback time scale", &playback_time_scale, -5, 5);
ImGui::SliderFloat("Walk weight", &walk, 0, 1);
ImGui::SliderFloat("Run weight", &run, 0, 1);
ImGui::Checkbox("Loop", &loop);
if (ImGui::Button("Play")) {
walk_clip->Play();
run_clip->Play();
}
if (ImGui::Button("Pause")) {
walk_clip->Pause();
run_clip->Pause();
}
if (ImGui::Button("Stop")) {
walk_clip->Stop();
run_clip->Stop();
}
walk_clip->SetPlaybackTimeScale(playback_time_scale);
walk_clip->SetWeight(walk);
walk_clip->SetLoop(loop);
run_clip->SetPlaybackTimeScale(playback_time_scale);
run_clip->SetWeight(run);
run_clip->SetLoop(loop);
}
ImGui::End();
Node& node = *scene.GetRoot().GetChildren()[0];
node.SetLocalTransform(node.GetLocalTransform() *
Matrix::MakeRotation(0.02, {0, 1, 0, 0}));
static ImVec2 mouse_pos_prev = ImGui::GetMousePos();
ImVec2 mouse_pos = ImGui::GetMousePos();
Vector2 mouse_diff =
Vector2(mouse_pos.x - mouse_pos_prev.x, mouse_pos.y - mouse_pos_prev.y);
static Vector3 position(0, 1, -5);
static Vector3 cam_position = position;
auto strafe =
Vector3(ImGui::IsKeyDown(ImGuiKey_D) - ImGui::IsKeyDown(ImGuiKey_A),
ImGui::IsKeyDown(ImGuiKey_E) - ImGui::IsKeyDown(ImGuiKey_Q),
ImGui::IsKeyDown(ImGuiKey_W) - ImGui::IsKeyDown(ImGuiKey_S));
position += strafe * 0.5;
cam_position = cam_position.Lerp(position, 0.02);
// Face towards the +Z direction (+X right, +Y up).
auto camera = Camera::MakePerspective(
/* fov */ Degrees(60),
/* position */ cam_position)
.LookAt(
/* target */ cam_position + Vector3(0, 0, 1),
/* up */ {0, 1, 0});
scene.Render(render_target, camera);
return true;
};
OpenPlaygroundHere(callback);
}
} // namespace testing
} // namespace scene
} // namespace impeller