💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
5.0 KiB

/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/scene/billboard.hpp>
#include <engine/config.hpp>
#include <engine/render/vertex-attribute.hpp>
#include <engine/geom/projection.hpp>
#include <engine/scene/camera.hpp>
namespace scene {
billboard::billboard()
{
const float vertex_data[] =
{
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
const std::size_t vertex_size = 8;
const std::size_t vertex_stride = sizeof(float) * vertex_size;
const std::size_t vertex_count = 6;
m_vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, sizeof(float) * vertex_size * vertex_count, std::as_bytes(std::span{vertex_data}));
std::size_t attribute_offset = 0;
// Define position vertex attribute
gl::vertex_attribute position_attribute;
position_attribute.buffer = m_vbo.get();
position_attribute.offset = attribute_offset;
position_attribute.stride = vertex_stride;
position_attribute.type = gl::vertex_attribute_type::float_32;
position_attribute.components = 3;
attribute_offset += position_attribute.components * sizeof(float);
// Define UV vertex attribute
gl::vertex_attribute uv_attribute;
uv_attribute.buffer = m_vbo.get();
uv_attribute.offset = attribute_offset;
uv_attribute.stride = vertex_stride;
uv_attribute.type = gl::vertex_attribute_type::float_32;
uv_attribute.components = 2;
attribute_offset += uv_attribute.components * sizeof(float);
// Define barycentric vertex attribute
gl::vertex_attribute barycentric_attribute;
barycentric_attribute.buffer = m_vbo.get();
barycentric_attribute.offset = attribute_offset;
barycentric_attribute.stride = vertex_stride;
barycentric_attribute.type = gl::vertex_attribute_type::float_32;
barycentric_attribute.components = 3;
//attribute_offset += barycentric_attribute.components * sizeof(float);
// Bind vertex attributes to VAO
m_vao = std::make_unique<gl::vertex_array>();
m_vao->bind(render::vertex_attribute::position, position_attribute);
m_vao->bind(render::vertex_attribute::uv, uv_attribute);
m_vao->bind(render::vertex_attribute::barycentric, barycentric_attribute);
// Init render operation
m_render_op.vertex_array = m_vao.get();
m_render_op.drawing_mode = gl::drawing_mode::triangles;
m_render_op.start_index = 0;
m_render_op.index_count = 6;
m_render_op.transform = float4x4::identity();
}
void billboard::render(render::context& ctx) const
{
// Align billboard
switch (m_billboard_type)
{
case scene::billboard_type::spherical:
{
auto transform = get_transform();
transform.rotation = math::normalize(math::look_rotation(ctx.camera->get_forward(), ctx.camera->get_up()) * transform.rotation);
m_render_op.transform = math::matrix_cast(transform);
break;
}
case scene::billboard_type::cylindrical:
{
auto transform = get_transform();
auto look = math::normalize(geom::project_on_plane(transform.translation - ctx.camera->get_translation(), {0.0f, 0.0f, 0.0f}, m_alignment_axis));
const auto right = math::normalize(math::cross(m_alignment_axis, look));
look = math::cross(right, m_alignment_axis);
const auto up = math::cross(look, right);
transform.rotation = math::normalize(math::look_rotation(look, up) * transform.rotation);
m_render_op.transform = math::matrix_cast(transform);
break;
}
case scene::billboard_type::flat:
break;
default:
break;
}
m_render_op.depth = ctx.camera->get_view_frustum().near().distance(get_translation());
ctx.operations.emplace_back(&m_render_op);
}
void billboard::set_material(std::shared_ptr<render::material> material)
{
m_render_op.material = material;
}
void billboard::set_billboard_type(billboard_type type)
{
m_billboard_type = type;
if (m_billboard_type == scene::billboard_type::flat)
{
m_render_op.transform = math::matrix_cast(get_transform());
}
}
void billboard::transformed()
{
m_bounds = {get_translation() - get_scale(), get_translation() + get_scale()};
if (m_billboard_type == scene::billboard_type::flat)
{
m_render_op.transform = math::matrix_cast(get_transform());
}
}
} // namespace scene