22auto to_bx(
const math::vec3& data) -> bx::Vec3
24 return {data.x, data.y, data.z};
27auto from_bx(
const bx::Vec3& data) -> math::vec3
29 return {data.x, data.y, data.z};
38bool is_position_in_selection_area(
const math::vec3& world_position,
39 const camera& pick_camera,
40 const math::vec2& pick_position,
41 const math::vec2& pick_area)
44 math::vec3 screen_pos = pick_camera.world_to_viewport(world_position);
48 screen_pos.x >= pick_position.x - pick_area.x * 0.5f && screen_pos.x <= pick_position.x + pick_area.x * 0.5f &&
49 screen_pos.y >= pick_position.y - pick_area.y * 0.5f && screen_pos.y <= pick_position.y + pick_area.y * 0.5f);
53bool are_corners_in_selection_area(hpp::span<const math::vec3> corners,
54 const camera& pick_camera,
55 const math::vec2& pick_position,
56 const math::vec2& pick_area)
59 bool all_corners_in_selection =
true;
60 for(
int i = 0;
i < 8; ++
i)
63 math::vec3 screen_pos = pick_camera.world_to_viewport(corners[i]);
66 bool corner_in_selection = (screen_pos.x >= pick_position.x - pick_area.x * 0.5f &&
67 screen_pos.x <= pick_position.x + pick_area.x * 0.5f &&
68 screen_pos.y >= pick_position.y - pick_area.y * 0.5f &&
69 screen_pos.y <= pick_position.y + pick_area.y * 0.5f);
71 all_corners_in_selection &= corner_in_selection;
74 return all_corners_in_selection;
78bool are_local_bounds_in_selection_area(
const math::bbox& local_bounds,
80 const camera& pick_camera,
81 const math::vec2& pick_position,
82 const math::vec2& pick_area)
85 math::vec3 corners[8] = {
87 world_transform.
transform_coord({local_bounds.max.x, local_bounds.min.y, local_bounds.min.z}),
89 world_transform.
transform_coord({local_bounds.max.x, local_bounds.max.y, local_bounds.min.z}),
91 world_transform.
transform_coord({local_bounds.max.x, local_bounds.min.y, local_bounds.max.z}),
93 world_transform.
transform_coord({local_bounds.max.x, local_bounds.max.y, local_bounds.max.z})};
95 return are_corners_in_selection_area(corners, pick_camera, pick_position, pick_area);
99bool are_global_bounds_in_selection_area(
const math::bbox& world_bounds,
100 const camera& pick_camera,
101 const math::vec2& pick_position,
102 const math::vec2& pick_area)
105 math::vec3 corners[8] = {{world_bounds.
min.x, world_bounds.
min.y, world_bounds.
min.z},
106 {world_bounds.
max.x, world_bounds.
min.y, world_bounds.
min.z},
107 {world_bounds.
min.x, world_bounds.
max.y, world_bounds.
min.z},
108 {world_bounds.
max.x, world_bounds.
max.y, world_bounds.
min.z},
109 {world_bounds.
min.x, world_bounds.
min.y, world_bounds.
max.z},
110 {world_bounds.
max.x, world_bounds.
min.y, world_bounds.
max.z},
111 {world_bounds.
min.x, world_bounds.
max.y, world_bounds.
max.z},
112 {world_bounds.
max.x, world_bounds.
max.y, world_bounds.
max.z}};
114 return are_corners_in_selection_area(corners, pick_camera, pick_position, pick_area);
129 scene* target_scene = em.get_active_scene(ctx);
136 if(pick_area_.x > 0.0f && pick_area_.y > 0.0f && pick_camera_)
138 const auto& pick_camera = *pick_camera_;
140 auto on_pick_failed = [&](
auto e)
142 auto ue = target_scene->create_handle(e);
146 auto on_pick_success = [&](
auto e)
148 auto id = ENTT_ID_TYPE(e);
149 process_pick_result(ctx, target_scene,
id);
155 [&](
auto e,
auto&& transform_comp,
auto&& active)
157 const auto& world_transform = transform_comp.get_transform_global();
158 const auto& world_position = world_transform.
get_position();
207 if(!pick_camera.get_frustum().test_point(world_position))
214 if(!is_position_in_selection_area(world_position, pick_camera, pick_position_, pick_area_))
223 pick_camera_.reset();
234 const auto& pick_camera = *pick_camera_;
236 const auto& pick_view = pick_camera.get_view();
237 const auto& pick_proj = pick_camera.get_projection();
241 pass.
clear(BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000ff, 1.0f, 0);
243 pass.
bind(surface_.get());
245 bool anything_picked =
false;
251 [&](
auto e,
auto&& transform_comp,
auto&& model_comp,
auto&& active)
253 auto&
model = model_comp.get_model();
259 const auto& world_transform = transform_comp.get_transform_global();
267 const auto&
mesh = lod.get();
271 if(!pick_camera.test_obb(bounds, world_transform))
274 auto id = ENTT_ID_TYPE(e);
275 std::uint32_t rr = (id) & 0xff;
276 std::uint32_t gg = (
id >> 8) & 0xff;
277 std::uint32_t bb = (
id >> 16) & 0xff;
278 std::uint32_t aa = (
id >> 24) & 0xff;
280 math::vec4 color_id = {rr / 255.0f, gg / 255.0f, bb / 255.0f, aa / 255.0f};
282 anything_picked =
true;
283 const auto& submesh_transforms = model_comp.get_submesh_transforms();
284 const auto& bone_transforms = model_comp.get_bone_transforms();
285 const auto& skinning_transforms = model_comp.get_skinning_transforms();
290 auto& prog = submit_params.skinned ? program_skinned_ : program_;
296 auto& prog = submit_params.skinned ? program_skinned_ : program_;
298 prog->set_uniform(
"u_id", math::value_ptr(color_id));
303 auto& prog = submit_params.
skinned ? program_skinned_ : program_;
310 auto& prog = submit_params.
skinned ? program_skinned_ : program_;
315 model.
submit(world_transform, submesh_transforms, bone_transforms, skinning_transforms, 0, callbacks);
325 [&](
auto e,
auto&& transform_comp,
auto&& text_comp,
auto&& active)
327 if(!text_comp.can_be_rendered())
331 const auto& world_transform = transform_comp.get_transform_global();
332 auto bbox = text_comp.get_bounds();
334 if(!pick_camera.test_obb(bbox, world_transform))
339 auto id = ENTT_ID_TYPE(e);
347 aabb.min =
to_bx(bbox.min);
348 aabb.max =
to_bx(bbox.max);
353 if(em.show_icon_gizmos)
355 program_gizmos_->begin();
358 auto& scn = *target_scene;
366 using type_t =
typename std::decay_t<
decltype(
tag)>
::type;
368 scn.registry->view<type_t>().each(
369 [&](
auto e,
auto&& comp)
371 auto entity = scn.create_handle(e);
375 anything_picked =
true;
377 auto id = ENTT_ID_TYPE(e);
382 auto& transform_comp =
entity.template get<transform_component>();
383 const auto& world_transform = transform_comp.get_transform_global();
388 if(!pick_camera.test_billboard(em.billboard_data.size, world_transform))
392 icon->native_handle(),
394 to_bx(pick_camera.get_position()),
395 to_bx(pick_camera.z_unit_axis()),
396 em.billboard_data.size);
402 program_gizmos_->end();
406 pick_camera_.reset();
407 start_readback_ = anything_picked;
409 if(!anything_picked && !pick_callback_)
417 if((reading_ == 0u) && start_readback_)
421 if(blit_support ==
false)
423 APPLOG_WARNING(
"Texture blitting is not supported. Picking will not work");
424 start_readback_ =
false;
431 gfx::blit(pass.
id, blit_tex_->native_handle(), 0, 0, surface_->get_texture()->native_handle());
433 start_readback_ =
false;
436 if(reading_ && reading_ <= render_frame)
439 std::map<std::uint32_t, std::uint32_t> ids;
440 std::uint32_t max_amount = 0;
441 for(std::uint8_t*
x = &blit_data_.front();
x < &blit_data_.back();)
443 std::uint8_t rr = *
x++;
444 std::uint8_t gg = *
x++;
445 std::uint8_t bb = *
x++;
446 std::uint8_t aa = *
x++;
454 auto hash_key =
static_cast<std::uint32_t
>(rr + (gg << 8) + (bb << 16) + (aa << 24));
455 std::uint32_t amount = 1;
456 auto map_iter = ids.find(hash_key);
457 if(map_iter != ids.end())
459 amount = map_iter->second + 1;
463 ids[hash_key] = amount;
464 max_amount = max_amount > amount ? max_amount : amount;
467 ENTT_ID_TYPE id_key = 0;
470 for(
auto& pair : ids)
472 if(pair.second == max_amount)
475 process_pick_result(ctx, target_scene, id_key);
486 process_pick_result(ctx, target_scene, id_key);
499void picking_manager::process_pick_result(
rtti::context& ctx,
scene* target_scene, ENTT_ID_TYPE id_key)
502 auto entity = entt::entity(id_key);
503 entt::handle picked_entity;
515 auto callback = pick_callback_;
516 callback(picked_entity, pick_position_);
524 em.select(picked_entity, pick_mode_);
550 std::make_shared<gfx::texture>(tex_id_dim,
554 gfx::texture_format::RGBA8,
555 0 | BGFX_TEXTURE_RT | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT |
556 BGFX_SAMPLER_MIP_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
558 auto picking_rt_depth =
559 std::make_shared<gfx::texture>(tex_id_dim,
563 gfx::texture_format::D24S8,
564 0 | BGFX_TEXTURE_RT | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT |
565 BGFX_SAMPLER_MIP_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
567 std::vector<std::shared_ptr<gfx::texture>> textures{picking_rt, picking_rt_depth};
568 surface_ = std::make_shared<gfx::frame_buffer>(textures);
574 blit_tex_ = std::make_shared<gfx::texture>(
579 gfx::texture_format::RGBA8,
580 0 | BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_READ_BACK | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT |
581 BGFX_SAMPLER_MIP_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
583 auto vs = am.get_asset<
gfx::shader>(
"editor:/data/shaders/vs_picking_id.sc");
584 auto vs_skinned = am.get_asset<
gfx::shader>(
"editor:/data/shaders/vs_picking_id_skinned.sc");
585 auto fs = am.get_asset<
gfx::shader>(
"editor:/data/shaders/fs_picking_id.sc");
587 program_ = std::make_unique<gpu_program>(vs,
fs);
588 program_skinned_ = std::make_unique<gpu_program>(vs_skinned,
fs);
590 auto vs_gizmos = am.get_asset<
gfx::shader>(
"editor:/data/shaders/vs_picking_debugdraw_fill_texture.sc");
591 auto fs_gizmos = am.get_asset<
gfx::shader>(
"editor:/data/shaders/fs_picking_debugdraw_fill_texture.sc");
592 program_gizmos_ = std::make_unique<gpu_program>(vs_gizmos, fs_gizmos);
602void picking_manager::setup_pick_camera(
const camera& cam, math::vec2 pos, math::vec2 area)
606 if(area.x > 0.0f && area.y > 0.0f)
632 pick_camera.
look_at(pick_eye, pick_at, pick_up);
635 pick_camera_ = pick_camera;
636 pick_position_ = pos;
639 start_readback_ =
true;
644 pick_camera_.reset();
648 start_readback_ =
false;
656 setup_pick_camera(cam, pos, area);
659 if(area.x > 0.0f && area.y > 0.0f)
676 setup_pick_camera(cam, pos);
677 pick_callback_ = callback;
682 return pick_camera_.has_value() || reading_ != 0;
Manages assets, including loading, unloading, and storage.
Class that contains core data for audio sources.
Class that contains core camera data, used for rendering and other purposes.
Class representing a camera. Contains functionality for manipulating and updating a camera....
auto get_far_clip() const -> float
Retrieves the distance from the camera to the far clip plane.
auto viewport_to_world(const math::vec2 &point, const math::plane &plane, math::vec3 &position_out, bool clip) const -> bool
Converts a screen position into a world space position on the specified plane.
void set_fov(float degrees)
Sets the field of view angle of this camera (perspective only).
void look_at(const math::vec3 &eye, const math::vec3 &at)
Sets the camera to look at a specified target.
void set_far_clip(float distance)
Sets the far plane distance.
auto y_unit_axis() const -> math::vec3
Retrieves the y-axis unit vector of the camera's local coordinate system.
void set_aspect_ratio(float aspect, bool locked=false)
Sets the aspect ratio to be used for generating the horizontal FOV angle (perspective only).
void set_near_clip(float distance)
Sets the near plane distance.
auto get_frustum() const -> const math::frustum &
Retrieves the current camera object frustum.
auto get_near_clip() const -> float
Retrieves the distance from the camera to the near clip plane.
Class that contains core light data, used for rendering and other purposes.
Base class for materials used in rendering.
Main class representing a 3D mesh with support for different LODs, submeshes, and skinning.
auto get_bounds() const -> const math::bbox &
Gets the local bounding box for this mesh.
Class that contains core data for meshes.
Structure describing a LOD group (set of meshes), LOD transitions, and their materials.
auto get_lod(uint32_t lod) const -> asset_handle< mesh >
Gets the LOD (Level of Detail) mesh for the specified level.
auto is_valid() const -> bool
Checks if the model is valid.
void submit(const math::mat4 &world_transform, const pose_mat4 &submesh_transforms, const pose_mat4 &bone_transforms, const std::vector< pose_mat4 > &skinning_matrices, unsigned int lod, const submit_callbacks &callbacks) const
Submits the model for rendering.
Component that wraps particle system emitter functionality.
void query_pick(math::vec2 pos, const camera &cam, pick_callback callback, bool force=false)
std::function< void(entt::handle entity, const math::vec2 &screen_pos)> pick_callback
auto init(rtti::context &ctx) -> bool
void request_pick(const camera &cam, editing_manager::select_mode mode, math::vec2 pos, math::vec2 area={})
static constexpr int tex_id_dim
auto is_picking() const -> bool
void on_frame_render(rtti::context &ctx, delta_t dt)
void on_frame_pick(rtti::context &ctx, delta_t dt)
auto get_pick_texture() const -> const std::shared_ptr< gfx::texture > &
auto deinit(rtti::context &ctx) -> bool
Class that contains core reflection probe data, used for rendering and other purposes.
std::chrono::duration< float > delta_t
#define APPLOG_WARNING(...)
void submit(view_id _id, program_handle _handle, int32_t _depth, bool _preserveState)
uint32_t read_texture(texture_handle _handle, void *_data, uint8_t _mip)
void set_state(uint64_t _state, uint32_t _rgba)
auto is_supported(uint64_t flag) -> bool
void draw_billboard(DebugDrawEncoder &dd, bgfx::TextureHandle icon_texture, const bx::Vec3 &icon_center, const bx::Vec3 &camera_pos, const bx::Vec3 &camera_look_dir, float half_size)
void blit(view_id _id, texture_handle _dst, uint16_t _dstX, uint16_t _dstY, texture_handle _src, uint16_t _srcX, uint16_t _srcY, uint16_t _width, uint16_t _height)
void discard(uint8_t _flags)
uint32_t get_render_frame()
Hash specialization for batch_key to enable use in std::unordered_map.
auto to_bx(const glm::vec3 &data) -> bx::Vec3
void draw(const bx::Aabb &_aabb)
void setColor(uint32_t _abgr)
void setState(bool _depthTest, bool _depthWrite, bool _clockwise, bool _alphaWrite=false, bool _alphaBlend=true)
void pushTransform(const void *_mtx)
void pushProgram(bgfx::ProgramHandle _handle)
void set_view_proj(const float *v, const float *p)
void clear(uint16_t _flags, uint32_t _rgba=0x000000ff, float _depth=1.0f, uint8_t _stencil=0) const
void bind(const frame_buffer *fb=nullptr) const
Storage for box vector values and wraps up common functionality.
vec3 max
The maximum vector value of the bounding box.
vec3 min
The minimum vector value of the bounding box.
hpp::event< void(rtti::context &, delta_t)> on_frame_render
Parameters for the submit callbacks.
bool skinned
Indicates if the model is skinned.
Callbacks for submitting the model for rendering.
std::function< void(const params &info, const material &)> setup_params_per_submesh
Callback for setting up per submesh.
std::function< void(const params &info)> setup_begin
Callback for setup begin.
std::function< void(const params &info)> setup_params_per_instance
Callback for setting up per instance.
std::function< void(const params &info)> setup_end
Callback for setup end.
Represents a scene in the ACE framework, managing entities and their relationships.
auto create_handle(entt::entity e) -> entt::handle
Creates an entity in the scene.