| // Copyright 2016 The Fuchsia 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 "garnet/examples/escher/waterfall/scenes/ring_tricks2.h" |
| |
| #include "lib/escher/geometry/clip_planes.h" |
| #include "lib/escher/geometry/tessellation.h" |
| #include "lib/escher/geometry/types.h" |
| #include "lib/escher/material/material.h" |
| #include "lib/escher/renderer/batch_gpu_uploader.h" |
| #include "lib/escher/scene/model.h" |
| #include "lib/escher/scene/stage.h" |
| #include "lib/escher/shape/modifier_wobble.h" |
| #include "lib/escher/util/stopwatch.h" |
| #include "lib/escher/vk/image.h" |
| #include "lib/escher/vk/texture.h" |
| #include "lib/escher/vk/vulkan_context.h" |
| |
| using escher::MeshAttribute; |
| using escher::MeshSpec; |
| using escher::Object; |
| using escher::RoundedRectSpec; |
| using escher::ShapeModifier; |
| using escher::vec2; |
| using escher::vec3; |
| |
| RingTricks2::RingTricks2(Demo* demo) |
| : Scene(demo), factory_(demo->GetEscherWeakPtr()) {} |
| |
| void RingTricks2::Init(escher::Stage* stage) { |
| red_ = fxl::MakeRefCounted<escher::Material>(); |
| bg_ = fxl::MakeRefCounted<escher::Material>(); |
| color1_ = fxl::MakeRefCounted<escher::Material>(); |
| color2_ = fxl::MakeRefCounted<escher::Material>(); |
| red_->set_color(vec3(0.98f, 0.15f, 0.15f)); |
| bg_->set_color(vec3(0.8f, 0.8f, 0.8f)); |
| color1_->set_color(vec3(63.f / 255.f, 138.f / 255.f, 153.f / 255.f)); |
| color2_->set_color(vec3(143.f / 255.f, 143.f / 255.f, 143.f / 255.f)); |
| |
| gradient_ = fxl::MakeRefCounted<escher::Material>(); |
| gradient_->SetTexture(escher()->NewTexture( |
| escher()->NewGradientImage(128, 128), vk::Filter::eLinear)); |
| gradient_->set_color(vec3(0.98f, 0.15f, 0.15f)); |
| |
| auto gpu_uploader = escher::BatchGpuUploader::New(escher()->GetWeakPtr()); |
| // Create meshes for fancy wobble effect. |
| { |
| MeshSpec spec{MeshAttribute::kPosition2D | MeshAttribute::kPositionOffset | |
| MeshAttribute::kPerimeterPos | MeshAttribute::kUV}; |
| ring_mesh1_ = escher::NewRingMesh(escher(), spec, 8, vec2(0.f, 0.f), 285.f, |
| 265.f, 18.f, -15.f); |
| } |
| |
| // Create rounded rectangles. |
| { |
| // Work in progress. The "#if 1" variant works with both the Waterfall and |
| // Waterfall2 demos, but the "#if 0" variant works only with the Waterfall2 |
| // demo. This is because the way ModelRenderer VkPipelines are built is |
| // extremely fiddly and manual, and not worth fixing since they'll soon be |
| // deleted. |
| #if 1 |
| MeshSpec mesh_spec{MeshAttribute::kPosition2D | MeshAttribute::kUV}; |
| #else |
| MeshSpec mesh_spec{{MeshAttribute::kPosition2D, MeshAttribute::kUV}}; |
| #endif |
| rounded_rect1_ = |
| factory_.NewRoundedRect(RoundedRectSpec(200, 400, 90, 20, 20, 50), |
| mesh_spec, gpu_uploader.get()); |
| } |
| |
| // Create sphere. |
| { |
| MeshSpec spec{MeshAttribute::kPosition3D | MeshAttribute::kUV}; |
| sphere_ = escher::NewSphereMesh(escher(), spec, 3, vec3(0, 0, 0), 100); |
| } |
| |
| // Upload mesh data to the GPU. |
| gpu_uploader->Submit(); |
| } |
| |
| RingTricks2::~RingTricks2() {} |
| |
| escher::Model* RingTricks2::Update(const escher::Stopwatch& stopwatch, |
| uint64_t frame_count, escher::Stage* stage, |
| escher::PaperRenderer2* renderer) { |
| float current_time_sec = stopwatch.GetElapsedSeconds(); |
| |
| float screen_width = stage->viewing_volume().width(); |
| float screen_height = stage->viewing_volume().height(); |
| float min_elevation = 5.f; |
| float max_elevation = 95.f; |
| float mid_elevation = 0.5f * (min_elevation + max_elevation); |
| float elevation_range = max_elevation - min_elevation; |
| |
| std::vector<Object> objects; |
| |
| // Orbiting circle1. |
| float circle1_orbit_radius = 275.f; |
| vec3 circle1_pos(sin(current_time_sec * 1.f) * circle1_orbit_radius + |
| (screen_width * 0.5f), |
| cos(current_time_sec * 1.f) * circle1_orbit_radius + |
| (screen_height * 0.5f), |
| mid_elevation + 10.f); |
| Object circle1(Object::NewCircle(circle1_pos, 60.f, red_)); |
| objects.push_back(circle1); |
| |
| // Orbiting circle2. |
| float circle2_orbit_radius = 120.f; |
| vec2 circle2_offset(sin(current_time_sec * 2.f) * circle2_orbit_radius, |
| cos(current_time_sec * 2.f) * circle2_orbit_radius); |
| |
| float circle2_elevation = |
| (cos(current_time_sec * 1.5f) * 0.5 + 0.5) * elevation_range + |
| min_elevation; |
| vec3 circle2_pos(vec2(circle1_pos) + circle2_offset, circle2_elevation); |
| Object circle2(Object::NewCircle(circle2_pos, 30.f, color1_)); |
| objects.push_back(circle2); |
| |
| // Create the ring that will do the fancy trick. |
| vec3 inner_ring_pos(screen_width * 0.5f, screen_height * 0.5f, mid_elevation); |
| Object inner_ring(inner_ring_pos, ring_mesh1_, color2_); |
| objects.push_back(inner_ring); |
| |
| // Create our background plane. |
| Object bg_plane( |
| Object::NewRect(vec3(0, 0, 0), vec2(screen_width, screen_height), bg_)); |
| objects.push_back(bg_plane); |
| |
| // Stack of circles. |
| Object circle4(Object::NewCircle(vec2(100, 100), 90.f, 35.f, red_)); |
| objects.push_back(circle4); |
| |
| Object circle5(Object::NewCircle(vec2(100, 100), 80.f, 45.f, color2_)); |
| objects.push_back(circle5); |
| |
| Object circle6(Object::NewCircle(vec2(100, 100), 70.f, 55.f, color1_)); |
| objects.push_back(circle6); |
| |
| Object circle7(Object::NewCircle(vec2(100, 100), 60.f, 65.f, red_)); |
| objects.push_back(circle7); |
| |
| Object circle8(Object::NewCircle(vec2(100, 100), 50.f, 75.f, color2_)); |
| objects.push_back(circle8); |
| |
| Object circle9(Object::NewCircle(vec2(100, 100), 40.f, 85.f, color1_)); |
| objects.push_back(circle9); |
| |
| // Rounded rect. |
| Object round_rect1(vec3(300, 700, 30.f), rounded_rect1_, gradient_); |
| objects.push_back(round_rect1); |
| |
| // Sphere. |
| Object sphere(vec3(800, 300, 0.f), sphere_, color1_); |
| objects.push_back(sphere); |
| |
| // Create the Model |
| model_ = std::unique_ptr<escher::Model>(new escher::Model(objects)); |
| model_->set_time(current_time_sec); |
| |
| // The following code allows the scene to be rendered in both the Waterfall |
| // and Waterfall2 demos. In the near-ish future, only Waterfall2 will remain, |
| // and this method signature will be changed to no longer return a Model. |
| // Therefore it will no longer be necessary to collect these objects in a |
| // vector. |
| if (renderer) { |
| renderer->DrawLegacyObject(circle1); |
| renderer->DrawLegacyObject(circle2); |
| renderer->DrawLegacyObject(inner_ring); |
| renderer->DrawLegacyObject(bg_plane); |
| renderer->DrawLegacyObject(round_rect1); |
| renderer->DrawLegacyObject(sphere); |
| renderer->DrawLegacyObject(circle4); |
| renderer->DrawLegacyObject(circle5); |
| renderer->DrawLegacyObject(circle6); |
| renderer->DrawLegacyObject(circle7); |
| renderer->DrawLegacyObject(circle8); |
| renderer->DrawLegacyObject(circle9); |
| } |
| |
| return model_.get(); |
| } |