mirror of
https://github.com/godotengine/godot.git
synced 2025-11-01 06:01:14 +00:00
Merge pull request #58141 from lawnjelly/occluder_shared_resources
This commit is contained in:
commit
2dd545b512
20 changed files with 728 additions and 386 deletions
|
|
@ -28,7 +28,7 @@
|
||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="spheres" type="Array" setter="set_spheres" getter="get_spheres" default="[ ]">
|
<member name="spheres" type="Array" setter="set_spheres" getter="get_spheres" default="[ Plane( 0, 0, 0, 1 ) ]">
|
||||||
The sphere data can be accessed as an array of [Plane]s. The position of each sphere is stored in the [code]normal[/code], and the radius is stored in the [code]d[/code] value of the plane.
|
The sphere data can be accessed as an array of [Plane]s. The position of each sphere is stored in the [code]normal[/code], and the radius is stored in the [code]d[/code] value of the plane.
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,6 @@
|
||||||
|
|
||||||
void Occluder::resource_changed(RES res) {
|
void Occluder::resource_changed(RES res) {
|
||||||
update_gizmo();
|
update_gizmo();
|
||||||
|
|
||||||
if (_shape.is_valid()) {
|
|
||||||
_shape->update_shape_to_visual_server();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Occluder::set_shape(const Ref<OccluderShape> &p_shape) {
|
void Occluder::set_shape(const Ref<OccluderShape> &p_shape) {
|
||||||
|
|
@ -52,16 +48,9 @@ void Occluder::set_shape(const Ref<OccluderShape> &p_shape) {
|
||||||
if (_shape.is_valid()) {
|
if (_shape.is_valid()) {
|
||||||
_shape->register_owner(this);
|
_shape->register_owner(this);
|
||||||
|
|
||||||
// Especially in the editor, the shape can be added AFTER the occluder
|
|
||||||
// is added to the world. This means the shape scenario will not be set.
|
|
||||||
// To remedy this we make sure the scenario etc is refreshed as soon as
|
|
||||||
// a shape is set on the occluder.
|
|
||||||
if (is_inside_world() && get_world().is_valid()) {
|
if (is_inside_world() && get_world().is_valid()) {
|
||||||
_shape->notification_enter_world(get_world()->get_scenario());
|
if (_occluder_instance.is_valid()) {
|
||||||
_shape->update_shape_to_visual_server();
|
VisualServer::get_singleton()->occluder_instance_link_resource(_occluder_instance, p_shape->get_rid());
|
||||||
if (is_inside_tree()) {
|
|
||||||
_shape->update_active_to_visual_server(is_visible_in_tree());
|
|
||||||
_shape->update_transform_to_visual_server(get_global_transform());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,12 +104,16 @@ void Occluder::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_ENTER_WORLD: {
|
case NOTIFICATION_ENTER_WORLD: {
|
||||||
ERR_FAIL_COND(get_world().is_null());
|
ERR_FAIL_COND(get_world().is_null());
|
||||||
if (_shape.is_valid()) {
|
|
||||||
_shape->notification_enter_world(get_world()->get_scenario());
|
if (_occluder_instance.is_valid()) {
|
||||||
_shape->update_active_to_visual_server(is_visible_in_tree());
|
VisualServer::get_singleton()->occluder_instance_set_scenario(_occluder_instance, get_world()->get_scenario());
|
||||||
_shape->update_shape_to_visual_server();
|
if (get_shape().is_valid()) {
|
||||||
_shape->update_transform_to_visual_server(get_global_transform());
|
VisualServer::get_singleton()->occluder_instance_link_resource(_occluder_instance, get_shape()->get_rid());
|
||||||
|
}
|
||||||
|
VisualServer::get_singleton()->occluder_instance_set_active(_occluder_instance, is_visible_in_tree());
|
||||||
|
VisualServer::get_singleton()->occluder_instance_set_transform(_occluder_instance, get_global_transform());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
set_process_internal(true);
|
set_process_internal(true);
|
||||||
|
|
@ -128,8 +121,8 @@ void Occluder::_notification(int p_what) {
|
||||||
#endif
|
#endif
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_EXIT_WORLD: {
|
case NOTIFICATION_EXIT_WORLD: {
|
||||||
if (_shape.is_valid()) {
|
if (_occluder_instance.is_valid()) {
|
||||||
_shape->notification_exit_world();
|
VisualServer::get_singleton()->occluder_instance_set_scenario(_occluder_instance, RID());
|
||||||
}
|
}
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
|
@ -138,14 +131,13 @@ void Occluder::_notification(int p_what) {
|
||||||
#endif
|
#endif
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||||
if (_shape.is_valid() && is_inside_tree()) {
|
if (_occluder_instance.is_valid() && is_inside_tree()) {
|
||||||
_shape->update_active_to_visual_server(is_visible_in_tree());
|
VisualServer::get_singleton()->occluder_instance_set_active(_occluder_instance, is_visible_in_tree());
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||||
if (_shape.is_valid()) {
|
if (_occluder_instance.is_valid()) {
|
||||||
_shape->update_transform_to_visual_server(get_global_transform());
|
VisualServer::get_singleton()->occluder_instance_set_transform(_occluder_instance, get_global_transform());
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
update_configuration_warning();
|
update_configuration_warning();
|
||||||
|
|
@ -171,10 +163,15 @@ void Occluder::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Occluder::Occluder() {
|
Occluder::Occluder() {
|
||||||
|
_occluder_instance = RID_PRIME(VisualServer::get_singleton()->occluder_instance_create());
|
||||||
set_notify_transform(true);
|
set_notify_transform(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Occluder::~Occluder() {
|
Occluder::~Occluder() {
|
||||||
|
if (_occluder_instance != RID()) {
|
||||||
|
VisualServer::get_singleton()->free(_occluder_instance);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_shape.is_null()) {
|
if (!_shape.is_null()) {
|
||||||
_shape->unregister_owner(this);
|
_shape->unregister_owner(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ class Occluder : public Spatial {
|
||||||
friend class OccluderSpatialGizmo;
|
friend class OccluderSpatialGizmo;
|
||||||
friend class OccluderEditorPlugin;
|
friend class OccluderEditorPlugin;
|
||||||
|
|
||||||
|
RID _occluder_instance;
|
||||||
Ref<OccluderShape> _shape;
|
Ref<OccluderShape> _shape;
|
||||||
|
|
||||||
void resource_changed(RES res);
|
void resource_changed(RES res);
|
||||||
|
|
|
||||||
|
|
@ -41,28 +41,16 @@
|
||||||
void OccluderShape::_bind_methods() {
|
void OccluderShape::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
OccluderShape::OccluderShape(RID p_shape) {
|
OccluderShape::OccluderShape() {
|
||||||
_shape = p_shape;
|
_shape = RID_PRIME(VisualServer::get_singleton()->occluder_resource_create());
|
||||||
}
|
}
|
||||||
|
|
||||||
OccluderShape::~OccluderShape() {
|
OccluderShape::~OccluderShape() {
|
||||||
if (_shape != RID()) {
|
if (_shape.is_valid()) {
|
||||||
VisualServer::get_singleton()->free(_shape);
|
VisualServer::get_singleton()->free(_shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OccluderShape::update_transform_to_visual_server(const Transform &p_global_xform) {
|
|
||||||
VisualServer::get_singleton()->occluder_set_transform(get_shape(), p_global_xform);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OccluderShape::update_active_to_visual_server(bool p_active) {
|
|
||||||
VisualServer::get_singleton()->occluder_set_active(get_shape(), p_active);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OccluderShape::notification_exit_world() {
|
|
||||||
VisualServer::get_singleton()->occluder_set_scenario(_shape, RID(), VisualServer::OCCLUDER_TYPE_UNDEFINED);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
AABB OccluderShape::get_fallback_gizmo_aabb() const {
|
AABB OccluderShape::get_fallback_gizmo_aabb() const {
|
||||||
return AABB(Vector3(-0.5, -0.5, -0.5), Vector3(1, 1, 1));
|
return AABB(Vector3(-0.5, -0.5, -0.5), Vector3(1, 1, 1));
|
||||||
|
|
@ -105,7 +93,7 @@ AABB OccluderShapeSphere::get_fallback_gizmo_aabb() const {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OccluderShapeSphere::update_shape_to_visual_server() {
|
void OccluderShapeSphere::update_shape_to_visual_server() {
|
||||||
VisualServer::get_singleton()->occluder_spheres_update(get_shape(), _spheres);
|
VisualServer::get_singleton()->occluder_resource_spheres_update(get_shape(), _spheres);
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform OccluderShapeSphere::center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap) {
|
Transform OccluderShapeSphere::center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap) {
|
||||||
|
|
@ -189,10 +177,6 @@ Transform OccluderShapeSphere::center_node(const Transform &p_global_xform, cons
|
||||||
return new_local_xform;
|
return new_local_xform;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OccluderShapeSphere::notification_enter_world(RID p_scenario) {
|
|
||||||
VisualServer::get_singleton()->occluder_set_scenario(get_shape(), p_scenario, VisualServer::OCCLUDER_TYPE_SPHERE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OccluderShapeSphere::set_spheres(const Vector<Plane> &p_spheres) {
|
void OccluderShapeSphere::set_spheres(const Vector<Plane> &p_spheres) {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
// try and detect special circumstance of adding a new sphere in the editor
|
// try and detect special circumstance of adding a new sphere in the editor
|
||||||
|
|
@ -221,6 +205,7 @@ void OccluderShapeSphere::set_spheres(const Vector<Plane> &p_spheres) {
|
||||||
_update_aabb();
|
_update_aabb();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,6 +217,7 @@ void OccluderShapeSphere::set_sphere_position(int p_idx, const Vector3 &p_positi
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
_update_aabb();
|
_update_aabb();
|
||||||
#endif
|
#endif
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -244,10 +230,18 @@ void OccluderShapeSphere::set_sphere_radius(int p_idx, real_t p_radius) {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
_update_aabb();
|
_update_aabb();
|
||||||
#endif
|
#endif
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OccluderShapeSphere::OccluderShapeSphere() :
|
OccluderShapeSphere::OccluderShapeSphere() {
|
||||||
OccluderShape(RID_PRIME(VisualServer::get_singleton()->occluder_create())) {
|
if (get_shape().is_valid()) {
|
||||||
|
VisualServer::get_singleton()->occluder_resource_prepare(get_shape(), VisualServer::OCCLUDER_TYPE_SPHERE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a default sphere
|
||||||
|
Vector<Plane> planes;
|
||||||
|
planes.push_back(Plane(Vector3(0, 0, 0), 1));
|
||||||
|
set_spheres(planes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,17 +45,12 @@ protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
RID get_shape() const { return _shape; }
|
RID get_shape() const { return _shape; }
|
||||||
OccluderShape(RID p_shape);
|
OccluderShape();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual RID get_rid() const { return _shape; }
|
virtual RID get_rid() const { return _shape; }
|
||||||
~OccluderShape();
|
~OccluderShape();
|
||||||
|
|
||||||
virtual void notification_enter_world(RID p_scenario) = 0;
|
|
||||||
virtual void update_shape_to_visual_server() = 0;
|
|
||||||
void update_transform_to_visual_server(const Transform &p_global_xform);
|
|
||||||
void update_active_to_visual_server(bool p_active);
|
|
||||||
void notification_exit_world();
|
|
||||||
virtual Transform center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap) = 0;
|
virtual Transform center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap) = 0;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
@ -87,8 +82,7 @@ public:
|
||||||
void set_sphere_position(int p_idx, const Vector3 &p_position);
|
void set_sphere_position(int p_idx, const Vector3 &p_position);
|
||||||
void set_sphere_radius(int p_idx, real_t p_radius);
|
void set_sphere_radius(int p_idx, real_t p_radius);
|
||||||
|
|
||||||
virtual void notification_enter_world(RID p_scenario);
|
void update_shape_to_visual_server();
|
||||||
virtual void update_shape_to_visual_server();
|
|
||||||
virtual Transform center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap);
|
virtual Transform center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap);
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ void OccluderShapePolygon::set_polygon_point(int p_idx, const Vector2 &p_point)
|
||||||
|
|
||||||
_poly_pts_local_raw.set(p_idx, p_point);
|
_poly_pts_local_raw.set(p_idx, p_point);
|
||||||
_sanitize_points();
|
_sanitize_points();
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,18 +119,21 @@ void OccluderShapePolygon::set_hole_point(int p_idx, const Vector2 &p_point) {
|
||||||
|
|
||||||
_hole_pts_local_raw.set(p_idx, p_point);
|
_hole_pts_local_raw.set(p_idx, p_point);
|
||||||
_sanitize_points();
|
_sanitize_points();
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OccluderShapePolygon::set_polygon_points(const PoolVector<Vector2> &p_points) {
|
void OccluderShapePolygon::set_polygon_points(const PoolVector<Vector2> &p_points) {
|
||||||
_poly_pts_local_raw = p_points;
|
_poly_pts_local_raw = p_points;
|
||||||
_sanitize_points();
|
_sanitize_points();
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OccluderShapePolygon::set_hole_points(const PoolVector<Vector2> &p_points) {
|
void OccluderShapePolygon::set_hole_points(const PoolVector<Vector2> &p_points) {
|
||||||
_hole_pts_local_raw = p_points;
|
_hole_pts_local_raw = p_points;
|
||||||
_sanitize_points();
|
_sanitize_points();
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,10 +145,6 @@ PoolVector<Vector2> OccluderShapePolygon::get_hole_points() const {
|
||||||
return _hole_pts_local_raw;
|
return _hole_pts_local_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OccluderShapePolygon::notification_enter_world(RID p_scenario) {
|
|
||||||
VisualServer::get_singleton()->occluder_set_scenario(get_shape(), p_scenario, VisualServer::OCCLUDER_TYPE_MESH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OccluderShapePolygon::update_shape_to_visual_server() {
|
void OccluderShapePolygon::update_shape_to_visual_server() {
|
||||||
if (_poly_pts_local.size() < 3)
|
if (_poly_pts_local.size() < 3)
|
||||||
return;
|
return;
|
||||||
|
|
@ -179,11 +179,12 @@ void OccluderShapePolygon::update_shape_to_visual_server() {
|
||||||
|
|
||||||
face.plane = Plane(Vector3(0, 0, 0), Vector3(0, 0, -1));
|
face.plane = Plane(Vector3(0, 0, 0), Vector3(0, 0, -1));
|
||||||
|
|
||||||
VisualServer::get_singleton()->occluder_mesh_update(get_shape(), md);
|
VisualServer::get_singleton()->occluder_resource_mesh_update(get_shape(), md);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OccluderShapePolygon::set_two_way(bool p_two_way) {
|
void OccluderShapePolygon::set_two_way(bool p_two_way) {
|
||||||
_settings_two_way = p_two_way;
|
_settings_two_way = p_two_way;
|
||||||
|
update_shape_to_visual_server();
|
||||||
notify_change_to_owners();
|
notify_change_to_owners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,8 +222,11 @@ void OccluderShapePolygon::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "hole_points"), "set_hole_points", "get_hole_points");
|
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "hole_points"), "set_hole_points", "get_hole_points");
|
||||||
}
|
}
|
||||||
|
|
||||||
OccluderShapePolygon::OccluderShapePolygon() :
|
OccluderShapePolygon::OccluderShapePolygon() {
|
||||||
OccluderShape(RID_PRIME(VisualServer::get_singleton()->occluder_create())) {
|
if (get_shape().is_valid()) {
|
||||||
|
VisualServer::get_singleton()->occluder_resource_prepare(get_shape(), VisualServer::OCCLUDER_TYPE_MESH);
|
||||||
|
}
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
PoolVector<Vector2> points;
|
PoolVector<Vector2> points;
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,7 @@ public:
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
virtual void notification_enter_world(RID p_scenario);
|
void update_shape_to_visual_server();
|
||||||
virtual void update_shape_to_visual_server();
|
|
||||||
virtual Transform center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap);
|
virtual Transform center_node(const Transform &p_global_xform, const Transform &p_parent_xform, real_t p_snap);
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
#include "core/math/aabb.h"
|
#include "core/math/aabb.h"
|
||||||
#include "core/project_settings.h"
|
#include "core/project_settings.h"
|
||||||
#include "portal_renderer.h"
|
#include "portal_renderer.h"
|
||||||
|
#include "servers/visual/visual_server_globals.h"
|
||||||
|
#include "servers/visual/visual_server_scene.h"
|
||||||
|
|
||||||
#define _log(a, b) ;
|
#define _log(a, b) ;
|
||||||
//#define _log_prepare(a) log(a, 0)
|
//#define _log_prepare(a) log(a, 0)
|
||||||
|
|
@ -275,10 +277,12 @@ void PortalOcclusionCuller::prepare_generic(PortalRenderer &p_portal_renderer, c
|
||||||
uint32_t polycount = 0;
|
uint32_t polycount = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const PortalResources &resources = VSG::scene->get_portal_resources();
|
||||||
|
|
||||||
// find occluders
|
// find occluders
|
||||||
for (unsigned int o = 0; o < p_occluder_pool_ids.size(); o++) {
|
for (unsigned int o = 0; o < p_occluder_pool_ids.size(); o++) {
|
||||||
int id = p_occluder_pool_ids[o];
|
int id = p_occluder_pool_ids[o];
|
||||||
VSOccluder &occ = p_portal_renderer.get_pool_occluder(id);
|
VSOccluder_Instance &occ = p_portal_renderer.get_pool_occluder_instance(id);
|
||||||
|
|
||||||
// is it active?
|
// is it active?
|
||||||
// in the case of rooms, they will always be active, as inactive
|
// in the case of rooms, they will always be active, as inactive
|
||||||
|
|
@ -290,9 +294,9 @@ void PortalOcclusionCuller::prepare_generic(PortalRenderer &p_portal_renderer, c
|
||||||
// TODO : occlusion cull spheres AGAINST themselves.
|
// TODO : occlusion cull spheres AGAINST themselves.
|
||||||
// i.e. a sphere that is occluded by another occluder is no
|
// i.e. a sphere that is occluded by another occluder is no
|
||||||
// use as an occluder...
|
// use as an occluder...
|
||||||
if (occ.type == VSOccluder::OT_SPHERE) {
|
if (occ.type == VSOccluder_Instance::OT_SPHERE) {
|
||||||
// make sure world space spheres are up to date
|
// make sure world space spheres are up to date
|
||||||
p_portal_renderer.occluder_ensure_up_to_date_sphere(occ);
|
p_portal_renderer.occluder_ensure_up_to_date_sphere(resources, occ);
|
||||||
|
|
||||||
// cull entire AABB
|
// cull entire AABB
|
||||||
if (is_aabb_culled(occ.aabb, p_planes)) {
|
if (is_aabb_culled(occ.aabb, p_planes)) {
|
||||||
|
|
@ -301,7 +305,7 @@ void PortalOcclusionCuller::prepare_generic(PortalRenderer &p_portal_renderer, c
|
||||||
|
|
||||||
// multiple spheres
|
// multiple spheres
|
||||||
for (int n = 0; n < occ.list_ids.size(); n++) {
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
const Occlusion::Sphere &occluder_sphere = p_portal_renderer.get_pool_occluder_sphere(occ.list_ids[n]).world;
|
const Occlusion::Sphere &occluder_sphere = p_portal_renderer.get_pool_occluder_world_sphere(occ.list_ids[n]);
|
||||||
|
|
||||||
// is the occluder sphere culled?
|
// is the occluder sphere culled?
|
||||||
if (is_sphere_culled(occluder_sphere.pos, occluder_sphere.radius, p_planes)) {
|
if (is_sphere_culled(occluder_sphere.pos, occluder_sphere.radius, p_planes)) {
|
||||||
|
|
@ -358,14 +362,14 @@ void PortalOcclusionCuller::prepare_generic(PortalRenderer &p_portal_renderer, c
|
||||||
}
|
}
|
||||||
} // sphere
|
} // sphere
|
||||||
|
|
||||||
if (occ.type == VSOccluder::OT_MESH) {
|
if (occ.type == VSOccluder_Instance::OT_MESH) {
|
||||||
// make sure world space spheres are up to date
|
// make sure world space spheres are up to date
|
||||||
p_portal_renderer.occluder_ensure_up_to_date_polys(occ);
|
p_portal_renderer.occluder_ensure_up_to_date_polys(resources, occ);
|
||||||
|
|
||||||
// multiple polys
|
// multiple polys
|
||||||
for (int n = 0; n < occ.list_ids.size(); n++) {
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
const VSOccluder_Mesh &opoly = p_portal_renderer.get_pool_occluder_mesh(occ.list_ids[n]);
|
const VSOccluder_Poly &opoly = p_portal_renderer.get_pool_occluder_world_poly(occ.list_ids[n]);
|
||||||
const Occlusion::PolyPlane &poly = opoly.poly_world;
|
const Occlusion::PolyPlane &poly = opoly.poly;
|
||||||
|
|
||||||
// backface cull
|
// backface cull
|
||||||
bool faces_camera = poly.plane.is_point_over(pt_camera);
|
bool faces_camera = poly.plane.is_point_over(pt_camera);
|
||||||
|
|
@ -507,21 +511,21 @@ void PortalOcclusionCuller::precalc_poly_edge_planes(const Vector3 &p_pt_camera)
|
||||||
// holes
|
// holes
|
||||||
if (sortpoly.flags & SortPoly::SPF_HAS_HOLES) {
|
if (sortpoly.flags & SortPoly::SPF_HAS_HOLES) {
|
||||||
// get the mesh poly and the holes
|
// get the mesh poly and the holes
|
||||||
const VSOccluder_Mesh &mesh = _portal_renderer->get_pool_occluder_mesh(sortpoly.mesh_source_id);
|
const VSOccluder_Poly &mesh = _portal_renderer->get_pool_occluder_world_poly(sortpoly.mesh_source_id);
|
||||||
|
|
||||||
dpoly.num_holes = mesh.num_holes;
|
dpoly.num_holes = mesh.num_holes;
|
||||||
|
|
||||||
for (int h = 0; h < mesh.num_holes; h++) {
|
for (int h = 0; h < mesh.num_holes; h++) {
|
||||||
uint32_t hid = mesh.hole_pool_ids[h];
|
uint32_t hid = mesh.hole_pool_ids[h];
|
||||||
const VSOccluder_Hole &hole = _portal_renderer->get_pool_occluder_hole(hid);
|
const VSOccluder_Hole &hole = _portal_renderer->get_pool_occluder_world_hole(hid);
|
||||||
|
|
||||||
// copy the verts to the precalced poly,
|
// copy the verts to the precalced poly,
|
||||||
// we will need these later for whittling polys.
|
// we will need these later for whittling polys.
|
||||||
// We could alternatively link back to the original verts, but that gets messy.
|
// We could alternatively link back to the original verts, but that gets messy.
|
||||||
dpoly.hole_polys[h] = hole.poly_world;
|
dpoly.hole_polys[h] = hole;
|
||||||
|
|
||||||
int hole_num_verts = hole.poly_world.num_verts;
|
int hole_num_verts = hole.num_verts;
|
||||||
const Vector3 *hverts = hole.poly_world.verts;
|
const Vector3 *hverts = hole.verts;
|
||||||
|
|
||||||
// number of planes equals number of verts forming edges
|
// number of planes equals number of verts forming edges
|
||||||
dpoly.hole_edge_planes[h].num_planes = hole_num_verts;
|
dpoly.hole_edge_planes[h].num_planes = hole_num_verts;
|
||||||
|
|
@ -671,7 +675,7 @@ void PortalOcclusionCuller::whittle_polys() {
|
||||||
// order polys by distance to camera / area? NYI
|
// order polys by distance to camera / area? NYI
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PortalOcclusionCuller::calculate_poly_goodness_of_fit(const VSOccluder_Mesh &p_opoly, real_t &r_fit) {
|
bool PortalOcclusionCuller::calculate_poly_goodness_of_fit(const VSOccluder_Poly &p_opoly, real_t &r_fit) {
|
||||||
// transform each of the poly points, find the area in screen space
|
// transform each of the poly points, find the area in screen space
|
||||||
|
|
||||||
// The points must be homogeneous coordinates, i.e. BEFORE
|
// The points must be homogeneous coordinates, i.e. BEFORE
|
||||||
|
|
@ -679,11 +683,11 @@ bool PortalOcclusionCuller::calculate_poly_goodness_of_fit(const VSOccluder_Mesh
|
||||||
// divide applied after clipping, to calculate the area.
|
// divide applied after clipping, to calculate the area.
|
||||||
// We therefore store them as planes to store the w coordinate as d.
|
// We therefore store them as planes to store the w coordinate as d.
|
||||||
Plane xpoints[Occlusion::PolyPlane::MAX_POLY_VERTS];
|
Plane xpoints[Occlusion::PolyPlane::MAX_POLY_VERTS];
|
||||||
int num_verts = p_opoly.poly_world.num_verts;
|
int num_verts = p_opoly.poly.num_verts;
|
||||||
|
|
||||||
for (int n = 0; n < num_verts; n++) {
|
for (int n = 0; n < num_verts; n++) {
|
||||||
// source and dest in homogeneous coords
|
// source and dest in homogeneous coords
|
||||||
Plane source(p_opoly.poly_world.verts[n], 1.0f);
|
Plane source(p_opoly.poly.verts[n], 1.0f);
|
||||||
Plane &dest = xpoints[n];
|
Plane &dest = xpoints[n];
|
||||||
|
|
||||||
dest = _matrix_camera.xform4(source);
|
dest = _matrix_camera.xform4(source);
|
||||||
|
|
|
||||||
|
|
@ -161,14 +161,10 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool calculate_poly_goodness_of_fit(const VSOccluder_Mesh &p_opoly, real_t &r_fit);
|
bool calculate_poly_goodness_of_fit(const VSOccluder_Poly &p_opoly, real_t &r_fit);
|
||||||
void whittle_polys();
|
void whittle_polys();
|
||||||
void precalc_poly_edge_planes(const Vector3 &p_pt_camera);
|
void precalc_poly_edge_planes(const Vector3 &p_pt_camera);
|
||||||
|
|
||||||
bool is_vso_poly_culled(const VSOccluder_Mesh &p_opoly, const LocalVector<Plane> &p_planes) const {
|
|
||||||
return is_poly_culled(p_opoly.poly_world, p_planes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all the points of the poly are beyond one of the planes (e.g. frustum), it is completely culled.
|
// If all the points of the poly are beyond one of the planes (e.g. frustum), it is completely culled.
|
||||||
bool is_poly_culled(const Occlusion::PolyPlane &p_opoly, const LocalVector<Plane> &p_planes) const {
|
bool is_poly_culled(const Occlusion::PolyPlane &p_opoly, const LocalVector<Plane> &p_planes) const {
|
||||||
for (unsigned int p = 0; p < p_planes.size(); p++) {
|
for (unsigned int p = 0; p < p_planes.size(); p++) {
|
||||||
|
|
|
||||||
|
|
@ -117,10 +117,13 @@ void PortalRenderer::_rghost_remove_from_rooms(uint32_t p_pool_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalRenderer::_occluder_remove_from_rooms(uint32_t p_pool_id) {
|
void PortalRenderer::_occluder_remove_from_rooms(uint32_t p_pool_id) {
|
||||||
VSOccluder &occ = _occluder_pool[p_pool_id];
|
VSOccluder_Instance &occ = _occluder_instance_pool[p_pool_id];
|
||||||
if (_loaded && (occ.room_id != -1)) {
|
if (_loaded && (occ.room_id != -1)) {
|
||||||
VSRoom &room = get_room(occ.room_id);
|
VSRoom &room = get_room(occ.room_id);
|
||||||
room.remove_occluder(p_pool_id);
|
bool res = room.remove_occluder(p_pool_id);
|
||||||
|
if (!res) {
|
||||||
|
WARN_PRINT_ONCE("OccluderInstance was not present in Room");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -467,22 +470,38 @@ void PortalRenderer::rghost_destroy(RGhostHandle p_handle) {
|
||||||
_rghost_pool.free(p_handle);
|
_rghost_pool.free(p_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
OccluderHandle PortalRenderer::occluder_create(VSOccluder::Type p_type) {
|
OccluderInstanceHandle PortalRenderer::occluder_instance_create() {
|
||||||
uint32_t pool_id = 0;
|
uint32_t pool_id = 0;
|
||||||
VSOccluder *occ = _occluder_pool.request(pool_id);
|
VSOccluder_Instance *occ = _occluder_instance_pool.request(pool_id);
|
||||||
occ->create();
|
occ->create();
|
||||||
|
|
||||||
// specific type
|
OccluderInstanceHandle handle = pool_id + 1;
|
||||||
occ->type = p_type;
|
|
||||||
CRASH_COND(p_type == VSOccluder::OT_UNDEFINED);
|
|
||||||
|
|
||||||
OccluderHandle handle = pool_id + 1;
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalRenderer::occluder_set_active(OccluderHandle p_handle, bool p_active) {
|
void PortalRenderer::occluder_instance_link(OccluderInstanceHandle p_handle, OccluderResourceHandle p_resource_handle) {
|
||||||
p_handle--;
|
p_handle--;
|
||||||
VSOccluder &occ = _occluder_pool[p_handle];
|
VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
|
||||||
|
|
||||||
|
// Unlink with any already linked, and destroy world resources
|
||||||
|
if (occ.resource_pool_id != UINT32_MAX) {
|
||||||
|
// Watch for bugs in future with the room within, this is not changed here,
|
||||||
|
// but could potentially be removed and re-added in future if we use sprawling.
|
||||||
|
occluder_instance_destroy(p_handle + 1, false);
|
||||||
|
occ.resource_pool_id = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_resource_handle--;
|
||||||
|
VSOccluder_Resource &res = VSG::scene->get_portal_resources().get_pool_occluder_resource(p_resource_handle);
|
||||||
|
|
||||||
|
occ.resource_pool_id = p_resource_handle;
|
||||||
|
occ.type = res.type;
|
||||||
|
occ.revision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalRenderer::occluder_instance_set_active(OccluderInstanceHandle p_handle, bool p_active) {
|
||||||
|
p_handle--;
|
||||||
|
VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
|
||||||
|
|
||||||
if (occ.active == p_active) {
|
if (occ.active == p_active) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -493,18 +512,23 @@ void PortalRenderer::occluder_set_active(OccluderHandle p_handle, bool p_active)
|
||||||
occluder_refresh_room_within(p_handle);
|
occluder_refresh_room_within(p_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalRenderer::occluder_set_transform(OccluderHandle p_handle, const Transform &p_xform) {
|
void PortalRenderer::occluder_instance_set_transform(OccluderInstanceHandle p_handle, const Transform &p_xform) {
|
||||||
p_handle--;
|
p_handle--;
|
||||||
VSOccluder &occ = _occluder_pool[p_handle];
|
VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
|
||||||
occ.xform = p_xform;
|
occ.xform = p_xform;
|
||||||
|
|
||||||
// mark as dirty as the world space spheres will be out of date
|
// mark as dirty as the world space spheres will be out of date
|
||||||
occ.dirty = true;
|
occ.revision = 0;
|
||||||
|
|
||||||
|
// The room within is based on the xform, rather than the AABB so this
|
||||||
|
// should still work even though the world space transform is deferred.
|
||||||
|
// N.B. Occluders are a single room based on the center of the Occluder transform,
|
||||||
|
// this may need to be improved at a later date.
|
||||||
occluder_refresh_room_within(p_handle);
|
occluder_refresh_room_within(p_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalRenderer::occluder_refresh_room_within(uint32_t p_occluder_pool_id) {
|
void PortalRenderer::occluder_refresh_room_within(uint32_t p_occluder_pool_id) {
|
||||||
VSOccluder &occ = _occluder_pool[p_occluder_pool_id];
|
VSOccluder_Instance &occ = _occluder_instance_pool[p_occluder_pool_id];
|
||||||
|
|
||||||
// if we aren't loaded, the room within can't be valid
|
// if we aren't loaded, the room within can't be valid
|
||||||
if (!_loaded) {
|
if (!_loaded) {
|
||||||
|
|
@ -547,156 +571,47 @@ void PortalRenderer::occluder_refresh_room_within(uint32_t p_occluder_pool_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalRenderer::occluder_update_mesh(OccluderHandle p_handle, const Geometry::OccluderMeshData &p_mesh_data) {
|
void PortalRenderer::occluder_instance_destroy(OccluderInstanceHandle p_handle, bool p_free) {
|
||||||
p_handle--;
|
p_handle--;
|
||||||
VSOccluder &occ = _occluder_pool[p_handle];
|
|
||||||
ERR_FAIL_COND(occ.type != VSOccluder::OT_MESH);
|
|
||||||
|
|
||||||
// needs world points updating next time
|
if (p_free) {
|
||||||
occ.dirty = true;
|
_occluder_remove_from_rooms(p_handle);
|
||||||
|
|
||||||
const LocalVectori<Geometry::OccluderMeshData::Face> &faces = p_mesh_data.faces;
|
|
||||||
const LocalVectori<Vector3> &vertices = p_mesh_data.vertices;
|
|
||||||
|
|
||||||
// first deal with the situation where the number of polys has changed (rare)
|
|
||||||
if (occ.list_ids.size() != faces.size()) {
|
|
||||||
// not the most efficient, but works...
|
|
||||||
// remove existing
|
|
||||||
for (int n = 0; n < occ.list_ids.size(); n++) {
|
|
||||||
uint32_t id = occ.list_ids[n];
|
|
||||||
_occluder_mesh_pool.free(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
occ.list_ids.clear();
|
|
||||||
// create new
|
|
||||||
for (int n = 0; n < faces.size(); n++) {
|
|
||||||
uint32_t id;
|
|
||||||
VSOccluder_Mesh *poly = _occluder_mesh_pool.request(id);
|
|
||||||
poly->create();
|
|
||||||
occ.list_ids.push_back(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// new data
|
|
||||||
for (int n = 0; n < occ.list_ids.size(); n++) {
|
|
||||||
uint32_t id = occ.list_ids[n];
|
|
||||||
|
|
||||||
VSOccluder_Mesh &opoly = _occluder_mesh_pool[id];
|
|
||||||
Occlusion::PolyPlane &poly = opoly.poly_local;
|
|
||||||
|
|
||||||
// source face
|
|
||||||
const Geometry::OccluderMeshData::Face &face = faces[n];
|
|
||||||
opoly.two_way = face.two_way;
|
|
||||||
|
|
||||||
// make sure the number of holes is correct
|
|
||||||
if (face.holes.size() != opoly.num_holes) {
|
|
||||||
// slow but hey ho
|
|
||||||
// delete existing holes
|
|
||||||
for (int i = 0; i < opoly.num_holes; i++) {
|
|
||||||
_occluder_hole_pool.free(opoly.hole_pool_ids[i]);
|
|
||||||
opoly.hole_pool_ids[i] = UINT32_MAX;
|
|
||||||
}
|
|
||||||
// create any new holes
|
|
||||||
opoly.num_holes = face.holes.size();
|
|
||||||
for (int i = 0; i < opoly.num_holes; i++) {
|
|
||||||
uint32_t hole_id;
|
|
||||||
VSOccluder_Hole *hole = _occluder_hole_pool.request(hole_id);
|
|
||||||
opoly.hole_pool_ids[i] = hole_id;
|
|
||||||
hole->create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
poly.plane = face.plane;
|
|
||||||
|
|
||||||
poly.num_verts = MIN(face.indices.size(), Occlusion::PolyPlane::MAX_POLY_VERTS);
|
|
||||||
|
|
||||||
// make sure the world poly also has the correct num verts
|
|
||||||
opoly.poly_world.num_verts = poly.num_verts;
|
|
||||||
|
|
||||||
for (int c = 0; c < poly.num_verts; c++) {
|
|
||||||
int vert_index = face.indices[c];
|
|
||||||
|
|
||||||
if (vert_index < vertices.size()) {
|
|
||||||
poly.verts[c] = vertices[vert_index];
|
|
||||||
} else {
|
|
||||||
WARN_PRINT_ONCE("occluder_update_mesh : poly index out of range");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// holes
|
|
||||||
for (int h = 0; h < opoly.num_holes; h++) {
|
|
||||||
VSOccluder_Hole &dhole = get_pool_occluder_hole(opoly.hole_pool_ids[h]);
|
|
||||||
const Geometry::OccluderMeshData::Hole &shole = face.holes[h];
|
|
||||||
|
|
||||||
dhole.poly_local.num_verts = shole.indices.size();
|
|
||||||
dhole.poly_local.num_verts = MIN(dhole.poly_local.num_verts, Occlusion::Poly::MAX_POLY_VERTS);
|
|
||||||
dhole.poly_world.num_verts = dhole.poly_local.num_verts;
|
|
||||||
|
|
||||||
for (int c = 0; c < dhole.poly_local.num_verts; c++) {
|
|
||||||
int vert_index = shole.indices[c];
|
|
||||||
if (vert_index < vertices.size()) {
|
|
||||||
dhole.poly_local.verts[c] = vertices[vert_index];
|
|
||||||
} else {
|
|
||||||
WARN_PRINT_ONCE("occluder_update_mesh : hole index out of range");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortalRenderer::occluder_update_spheres(OccluderHandle p_handle, const Vector<Plane> &p_spheres) {
|
|
||||||
p_handle--;
|
|
||||||
VSOccluder &occ = _occluder_pool[p_handle];
|
|
||||||
ERR_FAIL_COND(occ.type != VSOccluder::OT_SPHERE);
|
|
||||||
|
|
||||||
// first deal with the situation where the number of spheres has changed (rare)
|
|
||||||
if (occ.list_ids.size() != p_spheres.size()) {
|
|
||||||
// not the most efficient, but works...
|
|
||||||
// remove existing
|
|
||||||
for (int n = 0; n < occ.list_ids.size(); n++) {
|
|
||||||
uint32_t id = occ.list_ids[n];
|
|
||||||
_occluder_sphere_pool.free(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
occ.list_ids.clear();
|
|
||||||
// create new
|
|
||||||
for (int n = 0; n < p_spheres.size(); n++) {
|
|
||||||
uint32_t id;
|
|
||||||
VSOccluder_Sphere *sphere = _occluder_sphere_pool.request(id);
|
|
||||||
sphere->create();
|
|
||||||
occ.list_ids.push_back(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// new positions
|
|
||||||
for (int n = 0; n < occ.list_ids.size(); n++) {
|
|
||||||
uint32_t id = occ.list_ids[n];
|
|
||||||
VSOccluder_Sphere &sphere = _occluder_sphere_pool[id];
|
|
||||||
sphere.local.from_plane(p_spheres[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark as dirty as the world space spheres will be out of date
|
|
||||||
occ.dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortalRenderer::occluder_destroy(OccluderHandle p_handle) {
|
|
||||||
p_handle--;
|
|
||||||
|
|
||||||
// depending on the occluder type, remove the spheres etc
|
// depending on the occluder type, remove the spheres etc
|
||||||
VSOccluder &occ = _occluder_pool[p_handle];
|
VSOccluder_Instance &occ = _occluder_instance_pool[p_handle];
|
||||||
switch (occ.type) {
|
switch (occ.type) {
|
||||||
case VSOccluder::OT_SPHERE: {
|
case VSOccluder_Instance::OT_SPHERE: {
|
||||||
occluder_update_spheres(p_handle + 1, Vector<Plane>());
|
// free any spheres owned by the occluder
|
||||||
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
|
uint32_t id = occ.list_ids[n];
|
||||||
|
_occluder_world_sphere_pool.free(id);
|
||||||
|
}
|
||||||
|
occ.list_ids.clear();
|
||||||
} break;
|
} break;
|
||||||
case VSOccluder::OT_MESH: {
|
case VSOccluder_Instance::OT_MESH: {
|
||||||
occluder_update_mesh(p_handle + 1, Geometry::OccluderMeshData());
|
// free any polys owned by the occluder
|
||||||
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
|
uint32_t id = occ.list_ids[n];
|
||||||
|
VSOccluder_Poly &poly = _occluder_world_poly_pool[id];
|
||||||
|
|
||||||
|
// free any holes owned by the poly
|
||||||
|
for (int h = 0; h < poly.num_holes; h++) {
|
||||||
|
_occluder_world_hole_pool.free(poly.hole_pool_ids[h]);
|
||||||
|
}
|
||||||
|
// blanks
|
||||||
|
poly.create();
|
||||||
|
_occluder_world_poly_pool.free(id);
|
||||||
|
}
|
||||||
|
occ.list_ids.clear();
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_occluder_remove_from_rooms(p_handle);
|
if (p_free) {
|
||||||
_occluder_pool.free(p_handle);
|
_occluder_instance_pool.free(p_handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rooms
|
// Rooms
|
||||||
|
|
@ -1047,9 +962,9 @@ void PortalRenderer::_load_finalize_roaming() {
|
||||||
rghost_update(_rghost_pool.get_active_id(n) + 1, aabb, true);
|
rghost_update(_rghost_pool.get_active_id(n) + 1, aabb, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int n = 0; n < _occluder_pool.active_size(); n++) {
|
for (unsigned int n = 0; n < _occluder_instance_pool.active_size(); n++) {
|
||||||
VSOccluder &occ = _occluder_pool.get_active(n);
|
VSOccluder_Instance &occ = _occluder_instance_pool.get_active(n);
|
||||||
int occluder_id = _occluder_pool.get_active_id(n);
|
int occluder_id = _occluder_instance_pool.get_active_id(n);
|
||||||
|
|
||||||
// make sure occluder is in the correct room
|
// make sure occluder is in the correct room
|
||||||
occ.room_id = find_room_within(occ.pt_center, -1);
|
occ.room_id = find_room_within(occ.pt_center, -1);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include "core/vector.h"
|
#include "core/vector.h"
|
||||||
#include "portal_gameplay_monitor.h"
|
#include "portal_gameplay_monitor.h"
|
||||||
#include "portal_pvs.h"
|
#include "portal_pvs.h"
|
||||||
|
#include "portal_resources.h"
|
||||||
#include "portal_rooms_bsp.h"
|
#include "portal_rooms_bsp.h"
|
||||||
#include "portal_tracer.h"
|
#include "portal_tracer.h"
|
||||||
#include "portal_types.h"
|
#include "portal_types.h"
|
||||||
|
|
@ -187,12 +188,11 @@ public:
|
||||||
void rghost_destroy(RGhostHandle p_handle);
|
void rghost_destroy(RGhostHandle p_handle);
|
||||||
|
|
||||||
// occluders
|
// occluders
|
||||||
OccluderHandle occluder_create(VSOccluder::Type p_type);
|
OccluderInstanceHandle occluder_instance_create();
|
||||||
void occluder_update_spheres(OccluderHandle p_handle, const Vector<Plane> &p_spheres);
|
void occluder_instance_link(OccluderInstanceHandle p_handle, OccluderResourceHandle p_resource_handle);
|
||||||
void occluder_update_mesh(OccluderHandle p_handle, const Geometry::OccluderMeshData &p_mesh_data);
|
void occluder_instance_set_transform(OccluderInstanceHandle p_handle, const Transform &p_xform);
|
||||||
void occluder_set_transform(OccluderHandle p_handle, const Transform &p_xform);
|
void occluder_instance_set_active(OccluderInstanceHandle p_handle, bool p_active);
|
||||||
void occluder_set_active(OccluderHandle p_handle, bool p_active);
|
void occluder_instance_destroy(OccluderInstanceHandle p_handle, bool p_free = true);
|
||||||
void occluder_destroy(OccluderHandle p_handle);
|
|
||||||
|
|
||||||
// editor only .. slow
|
// editor only .. slow
|
||||||
Geometry::MeshData occlusion_debug_get_current_polys() const { return _tracer.get_occlusion_culler().debug_get_current_polys(); }
|
Geometry::MeshData occlusion_debug_get_current_polys() const { return _tracer.get_occlusion_culler().debug_get_current_polys(); }
|
||||||
|
|
@ -216,13 +216,13 @@ public:
|
||||||
|
|
||||||
int cull_convex_implementation(const Vector3 &p_point, const Vector3 &p_cam_dir, const CameraMatrix &p_cam_matrix, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_result_max, uint32_t p_mask, int32_t &r_previous_room_id_hint);
|
int cull_convex_implementation(const Vector3 &p_point, const Vector3 &p_cam_dir, const CameraMatrix &p_cam_matrix, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_result_max, uint32_t p_mask, int32_t &r_previous_room_id_hint);
|
||||||
|
|
||||||
bool occlusion_is_active() const { return _occluder_pool.active_size() && use_occlusion_culling; }
|
bool occlusion_is_active() const { return _occluder_instance_pool.active_size() && use_occlusion_culling; }
|
||||||
|
|
||||||
// special function for occlusion culling only that does not use portals / rooms,
|
// special function for occlusion culling only that does not use portals / rooms,
|
||||||
// but allows using occluders with the main scene
|
// but allows using occluders with the main scene
|
||||||
int occlusion_cull(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_num_results) {
|
int occlusion_cull(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const Vector<Plane> &p_convex, VSInstance **p_result_array, int p_num_results) {
|
||||||
// inactive?
|
// inactive?
|
||||||
if (!_occluder_pool.active_size() || !use_occlusion_culling) {
|
if (!_occluder_instance_pool.active_size() || !use_occlusion_culling) {
|
||||||
return p_num_results;
|
return p_num_results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,14 +257,6 @@ public:
|
||||||
RGhost &get_pool_rghost(uint32_t p_pool_id) { return _rghost_pool[p_pool_id]; }
|
RGhost &get_pool_rghost(uint32_t p_pool_id) { return _rghost_pool[p_pool_id]; }
|
||||||
const RGhost &get_pool_rghost(uint32_t p_pool_id) const { return _rghost_pool[p_pool_id]; }
|
const RGhost &get_pool_rghost(uint32_t p_pool_id) const { return _rghost_pool[p_pool_id]; }
|
||||||
|
|
||||||
const LocalVector<uint32_t, uint32_t> &get_occluders_active_list() const { return _occluder_pool.get_active_list(); }
|
|
||||||
const VSOccluder &get_pool_occluder(uint32_t p_pool_id) const { return _occluder_pool[p_pool_id]; }
|
|
||||||
VSOccluder &get_pool_occluder(uint32_t p_pool_id) { return _occluder_pool[p_pool_id]; }
|
|
||||||
const VSOccluder_Sphere &get_pool_occluder_sphere(uint32_t p_pool_id) const { return _occluder_sphere_pool[p_pool_id]; }
|
|
||||||
const VSOccluder_Mesh &get_pool_occluder_mesh(uint32_t p_pool_id) const { return _occluder_mesh_pool[p_pool_id]; }
|
|
||||||
const VSOccluder_Hole &get_pool_occluder_hole(uint32_t p_pool_id) const { return _occluder_hole_pool[p_pool_id]; }
|
|
||||||
VSOccluder_Hole &get_pool_occluder_hole(uint32_t p_pool_id) { return _occluder_hole_pool[p_pool_id]; }
|
|
||||||
|
|
||||||
VSStaticGhost &get_static_ghost(uint32_t p_id) { return _static_ghosts[p_id]; }
|
VSStaticGhost &get_static_ghost(uint32_t p_id) { return _static_ghosts[p_id]; }
|
||||||
|
|
||||||
VSRoomGroup &get_roomgroup(uint32_t p_pool_id) { return _roomgroup_pool[p_pool_id]; }
|
VSRoomGroup &get_roomgroup(uint32_t p_pool_id) { return _roomgroup_pool[p_pool_id]; }
|
||||||
|
|
@ -274,6 +266,15 @@ public:
|
||||||
|
|
||||||
bool get_cull_using_pvs() const { return _cull_using_pvs; }
|
bool get_cull_using_pvs() const { return _cull_using_pvs; }
|
||||||
|
|
||||||
|
// occluders
|
||||||
|
const LocalVector<uint32_t, uint32_t> &get_occluders_active_list() const { return _occluder_instance_pool.get_active_list(); }
|
||||||
|
const VSOccluder_Instance &get_pool_occluder_instance(uint32_t p_pool_id) const { return _occluder_instance_pool[p_pool_id]; }
|
||||||
|
VSOccluder_Instance &get_pool_occluder_instance(uint32_t p_pool_id) { return _occluder_instance_pool[p_pool_id]; }
|
||||||
|
const VSOccluder_Sphere &get_pool_occluder_world_sphere(uint32_t p_pool_id) const { return _occluder_world_sphere_pool[p_pool_id]; }
|
||||||
|
const VSOccluder_Poly &get_pool_occluder_world_poly(uint32_t p_pool_id) const { return _occluder_world_poly_pool[p_pool_id]; }
|
||||||
|
const VSOccluder_Hole &get_pool_occluder_world_hole(uint32_t p_pool_id) const { return _occluder_world_hole_pool[p_pool_id]; }
|
||||||
|
VSOccluder_Hole &get_pool_occluder_world_hole(uint32_t p_pool_id) { return _occluder_world_hole_pool[p_pool_id]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int find_room_within(const Vector3 &p_pos, int p_previous_room_id = -1) {
|
int find_room_within(const Vector3 &p_pos, int p_previous_room_id = -1) {
|
||||||
return _rooms_lookup_bsp.find_room_within(*this, p_pos, p_previous_room_id);
|
return _rooms_lookup_bsp.find_room_within(*this, p_pos, p_previous_room_id);
|
||||||
|
|
@ -318,10 +319,10 @@ private:
|
||||||
LocalVector<uint32_t, int32_t> _moving_list_roaming;
|
LocalVector<uint32_t, int32_t> _moving_list_roaming;
|
||||||
|
|
||||||
// occluders
|
// occluders
|
||||||
TrackedPooledList<VSOccluder> _occluder_pool;
|
TrackedPooledList<VSOccluder_Instance> _occluder_instance_pool;
|
||||||
TrackedPooledList<VSOccluder_Sphere, uint32_t, true> _occluder_sphere_pool;
|
TrackedPooledList<VSOccluder_Sphere, uint32_t, true> _occluder_world_sphere_pool;
|
||||||
TrackedPooledList<VSOccluder_Mesh, uint32_t, true> _occluder_mesh_pool;
|
TrackedPooledList<VSOccluder_Poly, uint32_t, true> _occluder_world_poly_pool;
|
||||||
TrackedPooledList<VSOccluder_Hole, uint32_t, true> _occluder_hole_pool;
|
TrackedPooledList<VSOccluder_Hole, uint32_t, true> _occluder_world_hole_pool;
|
||||||
|
|
||||||
PVS _pvs;
|
PVS _pvs;
|
||||||
|
|
||||||
|
|
@ -353,16 +354,47 @@ public:
|
||||||
static String _rid_to_string(RID p_rid);
|
static String _rid_to_string(RID p_rid);
|
||||||
static String _addr_to_string(const void *p_addr);
|
static String _addr_to_string(const void *p_addr);
|
||||||
|
|
||||||
void occluder_ensure_up_to_date_sphere(VSOccluder &r_occluder);
|
void occluder_ensure_up_to_date_sphere(const PortalResources &p_resources, VSOccluder_Instance &r_occluder);
|
||||||
void occluder_ensure_up_to_date_polys(VSOccluder &r_occluder);
|
void occluder_ensure_up_to_date_polys(const PortalResources &p_resources, VSOccluder_Instance &r_occluder);
|
||||||
void occluder_refresh_room_within(uint32_t p_occluder_pool_id);
|
void occluder_refresh_room_within(uint32_t p_occluder_pool_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void PortalRenderer::occluder_ensure_up_to_date_sphere(VSOccluder &r_occluder) {
|
inline void PortalRenderer::occluder_ensure_up_to_date_sphere(const PortalResources &p_resources, VSOccluder_Instance &r_occluder) {
|
||||||
if (!r_occluder.dirty) {
|
// occluder is not bound to a resource, cannot be used
|
||||||
|
if (r_occluder.resource_pool_id == UINT32_MAX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
r_occluder.dirty = false;
|
|
||||||
|
// get the resource
|
||||||
|
const VSOccluder_Resource &res = p_resources.get_pool_occluder_resource(r_occluder.resource_pool_id);
|
||||||
|
|
||||||
|
// dirty?
|
||||||
|
if (r_occluder.revision == res.revision) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r_occluder.revision = res.revision;
|
||||||
|
|
||||||
|
// must be same type, if not an error has occurred
|
||||||
|
ERR_FAIL_COND(res.type != r_occluder.type);
|
||||||
|
|
||||||
|
// first make sure the instance has the correct number of world space spheres
|
||||||
|
if (r_occluder.list_ids.size() != res.list_ids.size()) {
|
||||||
|
// not the most efficient, but works...
|
||||||
|
// remove existing
|
||||||
|
for (int n = 0; n < r_occluder.list_ids.size(); n++) {
|
||||||
|
uint32_t id = r_occluder.list_ids[n];
|
||||||
|
_occluder_world_sphere_pool.free(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
r_occluder.list_ids.clear();
|
||||||
|
// create new
|
||||||
|
for (int n = 0; n < res.list_ids.size(); n++) {
|
||||||
|
uint32_t id;
|
||||||
|
VSOccluder_Sphere *sphere = _occluder_world_sphere_pool.request(id);
|
||||||
|
sphere->create();
|
||||||
|
r_occluder.list_ids.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Transform &tr = r_occluder.xform;
|
const Transform &tr = r_occluder.xform;
|
||||||
|
|
||||||
|
|
@ -375,15 +407,16 @@ inline void PortalRenderer::occluder_ensure_up_to_date_sphere(VSOccluder &r_occl
|
||||||
|
|
||||||
// transform spheres
|
// transform spheres
|
||||||
for (int n = 0; n < r_occluder.list_ids.size(); n++) {
|
for (int n = 0; n < r_occluder.list_ids.size(); n++) {
|
||||||
uint32_t pool_id = r_occluder.list_ids[n];
|
uint32_t world_pool_id = r_occluder.list_ids[n];
|
||||||
VSOccluder_Sphere &osphere = _occluder_sphere_pool[pool_id];
|
VSOccluder_Sphere &world_osphere = _occluder_world_sphere_pool[world_pool_id];
|
||||||
|
const VSOccluder_Sphere &local_osphere = p_resources.get_pool_occluder_local_sphere(res.list_ids[n]);
|
||||||
|
|
||||||
osphere.world.pos = tr.xform(osphere.local.pos);
|
world_osphere.pos = tr.xform(local_osphere.pos);
|
||||||
osphere.world.radius = osphere.local.radius * scale;
|
world_osphere.radius = local_osphere.radius * scale;
|
||||||
|
|
||||||
Vector3 bradius = Vector3(osphere.world.radius, osphere.world.radius, osphere.world.radius);
|
Vector3 bradius = Vector3(world_osphere.radius, world_osphere.radius, world_osphere.radius);
|
||||||
Vector3 bmin = osphere.world.pos - bradius;
|
Vector3 bmin = world_osphere.pos - bradius;
|
||||||
Vector3 bmax = osphere.world.pos + bradius;
|
Vector3 bmax = world_osphere.pos + bradius;
|
||||||
|
|
||||||
bb_min.x = MIN(bb_min.x, bmin.x);
|
bb_min.x = MIN(bb_min.x, bmin.x);
|
||||||
bb_min.y = MIN(bb_min.y, bmin.y);
|
bb_min.y = MIN(bb_min.y, bmin.y);
|
||||||
|
|
@ -397,33 +430,91 @@ inline void PortalRenderer::occluder_ensure_up_to_date_sphere(VSOccluder &r_occl
|
||||||
r_occluder.aabb.size = bb_max - bb_min;
|
r_occluder.aabb.size = bb_max - bb_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PortalRenderer::occluder_ensure_up_to_date_polys(VSOccluder &r_occluder) {
|
inline void PortalRenderer::occluder_ensure_up_to_date_polys(const PortalResources &p_resources, VSOccluder_Instance &r_occluder) {
|
||||||
if (!r_occluder.dirty) {
|
// occluder is not bound to a resource, cannot be used
|
||||||
|
if (r_occluder.resource_pool_id == UINT32_MAX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
r_occluder.dirty = false;
|
|
||||||
|
// get the resource
|
||||||
|
const VSOccluder_Resource &res = p_resources.get_pool_occluder_resource(r_occluder.resource_pool_id);
|
||||||
|
|
||||||
|
// dirty?
|
||||||
|
if (r_occluder.revision == res.revision) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r_occluder.revision = res.revision;
|
||||||
|
|
||||||
|
// must be same type, if not an error has occurred
|
||||||
|
ERR_FAIL_COND(res.type != r_occluder.type);
|
||||||
|
|
||||||
|
// first make sure the instance has the correct number of world space spheres
|
||||||
|
if (r_occluder.list_ids.size() != res.list_ids.size()) {
|
||||||
|
// not the most efficient, but works...
|
||||||
|
// remove existing
|
||||||
|
for (int n = 0; n < r_occluder.list_ids.size(); n++) {
|
||||||
|
uint32_t id = r_occluder.list_ids[n];
|
||||||
|
_occluder_world_poly_pool.free(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
r_occluder.list_ids.clear();
|
||||||
|
// create new
|
||||||
|
for (int n = 0; n < res.list_ids.size(); n++) {
|
||||||
|
uint32_t id;
|
||||||
|
VSOccluder_Poly *poly = _occluder_world_poly_pool.request(id);
|
||||||
|
poly->create();
|
||||||
|
r_occluder.list_ids.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Transform &tr = r_occluder.xform;
|
const Transform &tr = r_occluder.xform;
|
||||||
|
|
||||||
for (int n = 0; n < r_occluder.list_ids.size(); n++) {
|
for (int n = 0; n < r_occluder.list_ids.size(); n++) {
|
||||||
uint32_t pool_id = r_occluder.list_ids[n];
|
uint32_t world_pool_id = r_occluder.list_ids[n];
|
||||||
|
uint32_t local_pool_id = res.list_ids[n];
|
||||||
|
|
||||||
VSOccluder_Mesh &opoly = _occluder_mesh_pool[pool_id];
|
VSOccluder_Poly &world_opoly = _occluder_world_poly_pool[world_pool_id];
|
||||||
|
const VSOccluder_Poly &local_opoly = p_resources._occluder_local_poly_pool[local_pool_id];
|
||||||
|
|
||||||
for (int i = 0; i < opoly.poly_local.num_verts; i++) {
|
world_opoly.poly.num_verts = local_opoly.poly.num_verts;
|
||||||
opoly.poly_world.verts[i] = tr.xform(opoly.poly_local.verts[i]);
|
world_opoly.two_way = local_opoly.two_way;
|
||||||
|
|
||||||
|
for (int i = 0; i < local_opoly.poly.num_verts; i++) {
|
||||||
|
world_opoly.poly.verts[i] = tr.xform(local_opoly.poly.verts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
opoly.poly_world.plane = tr.xform(opoly.poly_local.plane);
|
world_opoly.poly.plane = tr.xform(local_opoly.poly.plane);
|
||||||
|
|
||||||
|
// number of holes must be correct for each poly
|
||||||
|
if (world_opoly.num_holes != local_opoly.num_holes) {
|
||||||
|
// remove existing
|
||||||
|
for (int h = 0; h < world_opoly.num_holes; h++) {
|
||||||
|
uint32_t id = world_opoly.hole_pool_ids[h];
|
||||||
|
_occluder_world_hole_pool.free(id);
|
||||||
|
// not strictly necessary
|
||||||
|
world_opoly.hole_pool_ids[h] = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
world_opoly.num_holes = local_opoly.num_holes;
|
||||||
|
for (int h = 0; h < world_opoly.num_holes; h++) {
|
||||||
|
uint32_t id;
|
||||||
|
VSOccluder_Hole *hole = _occluder_world_hole_pool.request(id);
|
||||||
|
hole->create();
|
||||||
|
world_opoly.hole_pool_ids[h] = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// holes
|
// holes
|
||||||
for (int h = 0; h < opoly.num_holes; h++) {
|
for (int h = 0; h < world_opoly.num_holes; h++) {
|
||||||
uint32_t hid = opoly.hole_pool_ids[h];
|
uint32_t world_hid = world_opoly.hole_pool_ids[h];
|
||||||
|
uint32_t local_hid = local_opoly.hole_pool_ids[h];
|
||||||
|
VSOccluder_Hole &world_hole = _occluder_world_hole_pool[world_hid];
|
||||||
|
const VSOccluder_Hole &local_hole = p_resources._occluder_local_hole_pool[local_hid];
|
||||||
|
|
||||||
VSOccluder_Hole &hole = _occluder_hole_pool[hid];
|
world_hole.num_verts = local_hole.num_verts;
|
||||||
|
|
||||||
for (int i = 0; i < hole.poly_local.num_verts; i++) {
|
for (int i = 0; i < world_hole.num_verts; i++) {
|
||||||
hole.poly_world.verts[i] = tr.xform(hole.poly_local.verts[i]);
|
world_hole.verts[i] = tr.xform(local_hole.verts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
216
servers/visual/portals/portal_resources.cpp
Normal file
216
servers/visual/portals/portal_resources.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* portal_resources.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#include "portal_resources.h"
|
||||||
|
|
||||||
|
OccluderResourceHandle PortalResources::occluder_resource_create() {
|
||||||
|
uint32_t pool_id = 0;
|
||||||
|
VSOccluder_Resource *occ = _occluder_resource_pool.request(pool_id);
|
||||||
|
occ->create();
|
||||||
|
|
||||||
|
OccluderResourceHandle handle = pool_id + 1;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalResources::occluder_resource_destroy(OccluderResourceHandle p_handle) {
|
||||||
|
p_handle--;
|
||||||
|
|
||||||
|
// Depending on the occluder resource type, remove the spheres, polys, holes etc
|
||||||
|
// We can reuse the update methods for this.
|
||||||
|
VSOccluder_Resource &occ = _occluder_resource_pool[p_handle];
|
||||||
|
switch (occ.type) {
|
||||||
|
case VSOccluder_Instance::OT_SPHERE: {
|
||||||
|
occluder_resource_update_spheres(p_handle + 1, Vector<Plane>());
|
||||||
|
} break;
|
||||||
|
case VSOccluder_Instance::OT_MESH: {
|
||||||
|
occluder_resource_update_mesh(p_handle + 1, Geometry::OccluderMeshData());
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This also clears the occluder
|
||||||
|
occ.create();
|
||||||
|
|
||||||
|
_occluder_resource_pool.free(p_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalResources::occluder_resource_prepare(OccluderResourceHandle p_handle, VSOccluder_Instance::Type p_type) {
|
||||||
|
p_handle--;
|
||||||
|
|
||||||
|
// depending on the occluder type, remove the spheres etc
|
||||||
|
VSOccluder_Resource &occ = _occluder_resource_pool[p_handle];
|
||||||
|
|
||||||
|
if (occ.type != VSOccluder_Instance::OT_UNDEFINED) {
|
||||||
|
ERR_PRINT_ONCE("occluder_resource_prepare should be called only once.");
|
||||||
|
}
|
||||||
|
|
||||||
|
occ.type = p_type;
|
||||||
|
ERR_FAIL_COND(p_type == VSOccluder_Instance::OT_UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalResources::occluder_resource_update_spheres(OccluderResourceHandle p_handle, const Vector<Plane> &p_spheres) {
|
||||||
|
p_handle--;
|
||||||
|
VSOccluder_Resource &occ = _occluder_resource_pool[p_handle];
|
||||||
|
ERR_FAIL_COND(occ.type != VSOccluder_Resource::OT_SPHERE);
|
||||||
|
|
||||||
|
// first deal with the situation where the number of spheres has changed (rare)
|
||||||
|
if (occ.list_ids.size() != p_spheres.size()) {
|
||||||
|
// not the most efficient, but works...
|
||||||
|
// remove existing
|
||||||
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
|
uint32_t id = occ.list_ids[n];
|
||||||
|
_occluder_local_sphere_pool.free(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
occ.list_ids.clear();
|
||||||
|
// create new
|
||||||
|
for (int n = 0; n < p_spheres.size(); n++) {
|
||||||
|
uint32_t id;
|
||||||
|
VSOccluder_Sphere *sphere = _occluder_local_sphere_pool.request(id);
|
||||||
|
sphere->create();
|
||||||
|
occ.list_ids.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new positions
|
||||||
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
|
uint32_t id = occ.list_ids[n];
|
||||||
|
VSOccluder_Sphere &sphere = _occluder_local_sphere_pool[id];
|
||||||
|
sphere.from_plane(p_spheres[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark as dirty as the world space spheres will be out of date next time this resource is used
|
||||||
|
occ.revision += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalResources::occluder_resource_update_mesh(OccluderResourceHandle p_handle, const Geometry::OccluderMeshData &p_mesh_data) {
|
||||||
|
p_handle--;
|
||||||
|
VSOccluder_Resource &occ = _occluder_resource_pool[p_handle];
|
||||||
|
ERR_FAIL_COND(occ.type != VSOccluder_Resource::OT_MESH);
|
||||||
|
|
||||||
|
// mark as dirty, needs world points updating next time this resource is used
|
||||||
|
occ.revision += 1;
|
||||||
|
|
||||||
|
const LocalVectori<Geometry::OccluderMeshData::Face> &faces = p_mesh_data.faces;
|
||||||
|
const LocalVectori<Vector3> &vertices = p_mesh_data.vertices;
|
||||||
|
|
||||||
|
// first deal with the situation where the number of polys has changed (rare)
|
||||||
|
if (occ.list_ids.size() != faces.size()) {
|
||||||
|
// not the most efficient, but works...
|
||||||
|
// remove existing
|
||||||
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
|
uint32_t id = occ.list_ids[n];
|
||||||
|
|
||||||
|
// must also free the holes
|
||||||
|
VSOccluder_Poly &opoly = _occluder_local_poly_pool[id];
|
||||||
|
for (int h = 0; h < opoly.num_holes; h++) {
|
||||||
|
_occluder_local_hole_pool.free(opoly.hole_pool_ids[h]);
|
||||||
|
|
||||||
|
// perhaps debug only
|
||||||
|
opoly.hole_pool_ids[h] = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
_occluder_local_poly_pool.free(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
occ.list_ids.clear();
|
||||||
|
// create new
|
||||||
|
for (int n = 0; n < faces.size(); n++) {
|
||||||
|
uint32_t id;
|
||||||
|
VSOccluder_Poly *poly = _occluder_local_poly_pool.request(id);
|
||||||
|
poly->create();
|
||||||
|
occ.list_ids.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new data
|
||||||
|
for (int n = 0; n < occ.list_ids.size(); n++) {
|
||||||
|
uint32_t id = occ.list_ids[n];
|
||||||
|
|
||||||
|
VSOccluder_Poly &opoly = _occluder_local_poly_pool[id];
|
||||||
|
Occlusion::PolyPlane &poly = opoly.poly;
|
||||||
|
|
||||||
|
// source face
|
||||||
|
const Geometry::OccluderMeshData::Face &face = faces[n];
|
||||||
|
opoly.two_way = face.two_way;
|
||||||
|
|
||||||
|
// make sure the number of holes is correct
|
||||||
|
if (face.holes.size() != opoly.num_holes) {
|
||||||
|
// slow but hey ho
|
||||||
|
// delete existing holes
|
||||||
|
for (int i = 0; i < opoly.num_holes; i++) {
|
||||||
|
_occluder_local_hole_pool.free(opoly.hole_pool_ids[i]);
|
||||||
|
opoly.hole_pool_ids[i] = UINT32_MAX;
|
||||||
|
}
|
||||||
|
// create any new holes
|
||||||
|
opoly.num_holes = face.holes.size();
|
||||||
|
for (int i = 0; i < opoly.num_holes; i++) {
|
||||||
|
uint32_t hole_id;
|
||||||
|
VSOccluder_Hole *hole = _occluder_local_hole_pool.request(hole_id);
|
||||||
|
opoly.hole_pool_ids[i] = hole_id;
|
||||||
|
hole->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up the poly basics, plane and verts
|
||||||
|
poly.plane = face.plane;
|
||||||
|
poly.num_verts = MIN(face.indices.size(), Occlusion::PolyPlane::MAX_POLY_VERTS);
|
||||||
|
|
||||||
|
for (int c = 0; c < poly.num_verts; c++) {
|
||||||
|
int vert_index = face.indices[c];
|
||||||
|
|
||||||
|
if (vert_index < vertices.size()) {
|
||||||
|
poly.verts[c] = vertices[vert_index];
|
||||||
|
} else {
|
||||||
|
WARN_PRINT_ONCE("occluder_update_mesh : poly index out of range");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up any holes that are present
|
||||||
|
for (int h = 0; h < opoly.num_holes; h++) {
|
||||||
|
VSOccluder_Hole &dhole = get_pool_occluder_local_hole(opoly.hole_pool_ids[h]);
|
||||||
|
const Geometry::OccluderMeshData::Hole &shole = face.holes[h];
|
||||||
|
|
||||||
|
dhole.num_verts = shole.indices.size();
|
||||||
|
dhole.num_verts = MIN(dhole.num_verts, Occlusion::Poly::MAX_POLY_VERTS);
|
||||||
|
|
||||||
|
for (int c = 0; c < dhole.num_verts; c++) {
|
||||||
|
int vert_index = shole.indices[c];
|
||||||
|
if (vert_index < vertices.size()) {
|
||||||
|
dhole.verts[c] = vertices[vert_index];
|
||||||
|
} else {
|
||||||
|
WARN_PRINT_ONCE("occluder_update_mesh : hole index out of range");
|
||||||
|
}
|
||||||
|
} // for c through hole verts
|
||||||
|
} // for h through holes
|
||||||
|
|
||||||
|
} // for n through occluders
|
||||||
|
}
|
||||||
68
servers/visual/portals/portal_resources.h
Normal file
68
servers/visual/portals/portal_resources.h
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* portal_resources.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PORTAL_RESOURCES_H
|
||||||
|
#define PORTAL_RESOURCES_H
|
||||||
|
|
||||||
|
#include "core/math/geometry.h"
|
||||||
|
#include "portal_types.h"
|
||||||
|
|
||||||
|
// Although the portal renderer is owned by a scenario,
|
||||||
|
// resources are not associated with a scenario and can be shared
|
||||||
|
// potentially across multiple scenarios. They must therefore be held in
|
||||||
|
// some form of global.
|
||||||
|
|
||||||
|
class PortalResources {
|
||||||
|
friend class PortalRenderer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OccluderResourceHandle occluder_resource_create();
|
||||||
|
void occluder_resource_prepare(OccluderResourceHandle p_handle, VSOccluder_Instance::Type p_type);
|
||||||
|
void occluder_resource_update_spheres(OccluderResourceHandle p_handle, const Vector<Plane> &p_spheres);
|
||||||
|
void occluder_resource_update_mesh(OccluderResourceHandle p_handle, const Geometry::OccluderMeshData &p_mesh_data);
|
||||||
|
void occluder_resource_destroy(OccluderResourceHandle p_handle);
|
||||||
|
|
||||||
|
const VSOccluder_Resource &get_pool_occluder_resource(uint32_t p_pool_id) const { return _occluder_resource_pool[p_pool_id]; }
|
||||||
|
VSOccluder_Resource &get_pool_occluder_resource(uint32_t p_pool_id) { return _occluder_resource_pool[p_pool_id]; }
|
||||||
|
|
||||||
|
// Local space is shared resources
|
||||||
|
const VSOccluder_Sphere &get_pool_occluder_local_sphere(uint32_t p_pool_id) const { return _occluder_local_sphere_pool[p_pool_id]; }
|
||||||
|
const VSOccluder_Poly &get_pool_occluder_local_poly(uint32_t p_pool_id) const { return _occluder_local_poly_pool[p_pool_id]; }
|
||||||
|
const VSOccluder_Hole &get_pool_occluder_local_hole(uint32_t p_pool_id) const { return _occluder_local_hole_pool[p_pool_id]; }
|
||||||
|
VSOccluder_Hole &get_pool_occluder_local_hole(uint32_t p_pool_id) { return _occluder_local_hole_pool[p_pool_id]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TrackedPooledList<VSOccluder_Resource> _occluder_resource_pool;
|
||||||
|
TrackedPooledList<VSOccluder_Sphere, uint32_t, true> _occluder_local_sphere_pool;
|
||||||
|
TrackedPooledList<VSOccluder_Poly, uint32_t, true> _occluder_local_poly_pool;
|
||||||
|
TrackedPooledList<VSOccluder_Hole, uint32_t, true> _occluder_local_hole_pool;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PORTAL_RESOURCES_H
|
||||||
|
|
@ -55,7 +55,8 @@ typedef uint32_t RoomHandle;
|
||||||
typedef uint32_t RoomGroupHandle;
|
typedef uint32_t RoomGroupHandle;
|
||||||
typedef uint32_t OcclusionHandle;
|
typedef uint32_t OcclusionHandle;
|
||||||
typedef uint32_t RGhostHandle;
|
typedef uint32_t RGhostHandle;
|
||||||
typedef uint32_t OccluderHandle;
|
typedef uint32_t OccluderInstanceHandle;
|
||||||
|
typedef uint32_t OccluderResourceHandle;
|
||||||
|
|
||||||
struct VSPortal {
|
struct VSPortal {
|
||||||
enum ClipResult {
|
enum ClipResult {
|
||||||
|
|
@ -380,12 +381,12 @@ struct VSRoom {
|
||||||
LocalVector<uint32_t, int32_t> _roomgroup_ids;
|
LocalVector<uint32_t, int32_t> _roomgroup_ids;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VSOccluder {
|
// Possibly shared data, in local space
|
||||||
|
struct VSOccluder_Resource {
|
||||||
void create() {
|
void create() {
|
||||||
type = OT_UNDEFINED;
|
type = OT_UNDEFINED;
|
||||||
room_id = -1;
|
revision = 0;
|
||||||
dirty = false;
|
list_ids.clear();
|
||||||
active = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// these should match the values in VisualServer::OccluderType
|
// these should match the values in VisualServer::OccluderType
|
||||||
|
|
@ -396,6 +397,28 @@ struct VSOccluder {
|
||||||
OT_NUM_TYPES,
|
OT_NUM_TYPES,
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
|
// If the revision of the instance and the resource don't match,
|
||||||
|
// then the local versions have been updated and need transforming
|
||||||
|
// to world space in the instance (i.e. it is dirty)
|
||||||
|
uint32_t revision;
|
||||||
|
|
||||||
|
// ids of multiple objects in the appropriate occluder pool:
|
||||||
|
// local space for resources, and world space for occluder instances
|
||||||
|
LocalVector<uint32_t, int32_t> list_ids;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VSOccluder_Instance : public VSOccluder_Resource {
|
||||||
|
void create() {
|
||||||
|
VSOccluder_Resource::create();
|
||||||
|
room_id = -1;
|
||||||
|
active = true;
|
||||||
|
resource_pool_id = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Occluder instance can be bound to one resource (which will include data in local space)
|
||||||
|
// This should be set back to NULL if the resource is deleted
|
||||||
|
uint32_t resource_pool_id;
|
||||||
|
|
||||||
// which is the primary room this group of occluders is in
|
// which is the primary room this group of occluders is in
|
||||||
// (it may sprawl into multiple rooms)
|
// (it may sprawl into multiple rooms)
|
||||||
int32_t room_id;
|
int32_t room_id;
|
||||||
|
|
@ -409,14 +432,8 @@ struct VSOccluder {
|
||||||
// global xform
|
// global xform
|
||||||
Transform xform;
|
Transform xform;
|
||||||
|
|
||||||
// whether world space need calculating
|
|
||||||
bool dirty;
|
|
||||||
|
|
||||||
// controlled by the visible flag on the occluder
|
// controlled by the visible flag on the occluder
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
// ids of multiple objects in the appropriate occluder pool
|
|
||||||
LocalVector<uint32_t, int32_t> list_ids;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Occlusion {
|
namespace Occlusion {
|
||||||
|
|
@ -472,42 +489,27 @@ struct PolyPlane : public Poly {
|
||||||
|
|
||||||
} // namespace Occlusion
|
} // namespace Occlusion
|
||||||
|
|
||||||
struct VSOccluder_Sphere {
|
struct VSOccluder_Sphere : public Occlusion::Sphere {
|
||||||
void create() {
|
|
||||||
local.create();
|
|
||||||
world.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
Occlusion::Sphere local;
|
|
||||||
Occlusion::Sphere world;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VSOccluder_Mesh {
|
struct VSOccluder_Poly {
|
||||||
static const int MAX_POLY_HOLES = PortalDefines::OCCLUSION_POLY_MAX_HOLES;
|
static const int MAX_POLY_HOLES = PortalDefines::OCCLUSION_POLY_MAX_HOLES;
|
||||||
void create() {
|
void create() {
|
||||||
poly_local.create();
|
poly.create();
|
||||||
poly_world.create();
|
|
||||||
num_holes = 0;
|
num_holes = 0;
|
||||||
two_way = false;
|
two_way = false;
|
||||||
for (int n = 0; n < MAX_POLY_HOLES; n++) {
|
for (int n = 0; n < MAX_POLY_HOLES; n++) {
|
||||||
hole_pool_ids[n] = UINT32_MAX;
|
hole_pool_ids[n] = UINT32_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Occlusion::PolyPlane poly_local;
|
Occlusion::PolyPlane poly;
|
||||||
Occlusion::PolyPlane poly_world;
|
|
||||||
bool two_way;
|
bool two_way;
|
||||||
|
|
||||||
int num_holes;
|
int num_holes;
|
||||||
uint32_t hole_pool_ids[MAX_POLY_HOLES];
|
uint32_t hole_pool_ids[MAX_POLY_HOLES];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VSOccluder_Hole {
|
struct VSOccluder_Hole : public Occlusion::Poly {
|
||||||
void create() {
|
|
||||||
poly_local.create();
|
|
||||||
poly_world.create();
|
|
||||||
}
|
|
||||||
Occlusion::Poly poly_local;
|
|
||||||
Occlusion::Poly poly_world;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -603,12 +603,16 @@ public:
|
||||||
BIND2(roomgroup_add_room, RID, RID)
|
BIND2(roomgroup_add_room, RID, RID)
|
||||||
|
|
||||||
// Occluders
|
// Occluders
|
||||||
BIND0R(RID, occluder_create)
|
BIND0R(RID, occluder_instance_create)
|
||||||
BIND3(occluder_set_scenario, RID, RID, OccluderType)
|
BIND2(occluder_instance_set_scenario, RID, RID)
|
||||||
BIND2(occluder_spheres_update, RID, const Vector<Plane> &)
|
BIND2(occluder_instance_link_resource, RID, RID)
|
||||||
BIND2(occluder_mesh_update, RID, const Geometry::OccluderMeshData &)
|
BIND2(occluder_instance_set_transform, RID, const Transform &)
|
||||||
BIND2(occluder_set_transform, RID, const Transform &)
|
BIND2(occluder_instance_set_active, RID, bool)
|
||||||
BIND2(occluder_set_active, RID, bool)
|
|
||||||
|
BIND0R(RID, occluder_resource_create)
|
||||||
|
BIND2(occluder_resource_prepare, RID, OccluderType)
|
||||||
|
BIND2(occluder_resource_spheres_update, RID, const Vector<Plane> &)
|
||||||
|
BIND2(occluder_resource_mesh_update, RID, const Geometry::OccluderMeshData &)
|
||||||
BIND1(set_use_occlusion_culling, bool)
|
BIND1(set_use_occlusion_culling, bool)
|
||||||
BIND1RC(Geometry::MeshData, occlusion_debug_get_current_polys, RID)
|
BIND1RC(Geometry::MeshData, occlusion_debug_get_current_polys, RID)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1517,65 +1517,88 @@ void VisualServerScene::roomgroup_add_room(RID p_roomgroup, RID p_room) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Occluders
|
// Occluders
|
||||||
RID VisualServerScene::occluder_create() {
|
RID VisualServerScene::occluder_instance_create() {
|
||||||
Occluder *ro = memnew(Occluder);
|
OccluderInstance *ro = memnew(OccluderInstance);
|
||||||
ERR_FAIL_COND_V(!ro, RID());
|
ERR_FAIL_COND_V(!ro, RID());
|
||||||
RID occluder_rid = occluder_owner.make_rid(ro);
|
RID occluder_rid = occluder_instance_owner.make_rid(ro);
|
||||||
return occluder_rid;
|
return occluder_rid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::occluder_set_scenario(RID p_occluder, RID p_scenario, VisualServer::OccluderType p_type) {
|
void VisualServerScene::occluder_instance_link_resource(RID p_occluder_instance, RID p_occluder_resource) {
|
||||||
Occluder *ro = occluder_owner.getornull(p_occluder);
|
OccluderInstance *oi = occluder_instance_owner.getornull(p_occluder_instance);
|
||||||
ERR_FAIL_COND(!ro);
|
ERR_FAIL_COND(!oi);
|
||||||
|
ERR_FAIL_COND(!oi->scenario);
|
||||||
|
|
||||||
|
OccluderResource *res = occluder_resource_owner.getornull(p_occluder_resource);
|
||||||
|
ERR_FAIL_COND(!res);
|
||||||
|
|
||||||
|
oi->scenario->_portal_renderer.occluder_instance_link(oi->scenario_occluder_id, res->occluder_resource_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualServerScene::occluder_instance_set_scenario(RID p_occluder_instance, RID p_scenario) {
|
||||||
|
OccluderInstance *oi = occluder_instance_owner.getornull(p_occluder_instance);
|
||||||
|
ERR_FAIL_COND(!oi);
|
||||||
Scenario *scenario = scenario_owner.getornull(p_scenario);
|
Scenario *scenario = scenario_owner.getornull(p_scenario);
|
||||||
|
|
||||||
// noop?
|
// noop?
|
||||||
if (ro->scenario == scenario) {
|
if (oi->scenario == scenario) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the portal is in a scenario already, remove it
|
// if the portal is in a scenario already, remove it
|
||||||
if (ro->scenario) {
|
if (oi->scenario) {
|
||||||
ro->scenario->_portal_renderer.occluder_destroy(ro->scenario_occluder_id);
|
oi->scenario->_portal_renderer.occluder_instance_destroy(oi->scenario_occluder_id);
|
||||||
ro->scenario = nullptr;
|
oi->scenario = nullptr;
|
||||||
ro->scenario_occluder_id = 0;
|
oi->scenario_occluder_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create when entering the world
|
// create when entering the world
|
||||||
if (scenario) {
|
if (scenario) {
|
||||||
ro->scenario = scenario;
|
oi->scenario = scenario;
|
||||||
|
oi->scenario_occluder_id = scenario->_portal_renderer.occluder_instance_create();
|
||||||
// defer the actual creation to here
|
|
||||||
ro->scenario_occluder_id = scenario->_portal_renderer.occluder_create((VSOccluder::Type)p_type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::occluder_set_active(RID p_occluder, bool p_active) {
|
void VisualServerScene::occluder_instance_set_active(RID p_occluder_instance, bool p_active) {
|
||||||
Occluder *ro = occluder_owner.getornull(p_occluder);
|
OccluderInstance *oi = occluder_instance_owner.getornull(p_occluder_instance);
|
||||||
ERR_FAIL_COND(!ro);
|
ERR_FAIL_COND(!oi);
|
||||||
ERR_FAIL_COND(!ro->scenario);
|
ERR_FAIL_COND(!oi->scenario);
|
||||||
ro->scenario->_portal_renderer.occluder_set_active(ro->scenario_occluder_id, p_active);
|
oi->scenario->_portal_renderer.occluder_instance_set_active(oi->scenario_occluder_id, p_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::occluder_set_transform(RID p_occluder, const Transform &p_xform) {
|
void VisualServerScene::occluder_instance_set_transform(RID p_occluder_instance, const Transform &p_xform) {
|
||||||
Occluder *ro = occluder_owner.getornull(p_occluder);
|
OccluderInstance *oi = occluder_instance_owner.getornull(p_occluder_instance);
|
||||||
ERR_FAIL_COND(!ro);
|
ERR_FAIL_COND(!oi);
|
||||||
ERR_FAIL_COND(!ro->scenario);
|
ERR_FAIL_COND(!oi->scenario);
|
||||||
ro->scenario->_portal_renderer.occluder_set_transform(ro->scenario_occluder_id, p_xform);
|
oi->scenario->_portal_renderer.occluder_instance_set_transform(oi->scenario_occluder_id, p_xform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::occluder_spheres_update(RID p_occluder, const Vector<Plane> &p_spheres) {
|
RID VisualServerScene::occluder_resource_create() {
|
||||||
Occluder *ro = occluder_owner.getornull(p_occluder);
|
OccluderResource *res = memnew(OccluderResource);
|
||||||
ERR_FAIL_COND(!ro);
|
ERR_FAIL_COND_V(!res, RID());
|
||||||
ERR_FAIL_COND(!ro->scenario);
|
|
||||||
ro->scenario->_portal_renderer.occluder_update_spheres(ro->scenario_occluder_id, p_spheres);
|
res->occluder_resource_id = _portal_resources.occluder_resource_create();
|
||||||
|
|
||||||
|
RID occluder_resource_rid = occluder_resource_owner.make_rid(res);
|
||||||
|
return occluder_resource_rid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::occluder_mesh_update(RID p_occluder, const Geometry::OccluderMeshData &p_mesh_data) {
|
void VisualServerScene::occluder_resource_prepare(RID p_occluder_resource, VisualServer::OccluderType p_type) {
|
||||||
Occluder *ro = occluder_owner.getornull(p_occluder);
|
OccluderResource *res = occluder_resource_owner.getornull(p_occluder_resource);
|
||||||
ERR_FAIL_COND(!ro);
|
ERR_FAIL_COND(!res);
|
||||||
ERR_FAIL_COND(!ro->scenario);
|
_portal_resources.occluder_resource_prepare(res->occluder_resource_id, (VSOccluder_Instance::Type)p_type);
|
||||||
ro->scenario->_portal_renderer.occluder_update_mesh(ro->scenario_occluder_id, p_mesh_data);
|
}
|
||||||
|
|
||||||
|
void VisualServerScene::occluder_resource_spheres_update(RID p_occluder_resource, const Vector<Plane> &p_spheres) {
|
||||||
|
OccluderResource *res = occluder_resource_owner.getornull(p_occluder_resource);
|
||||||
|
ERR_FAIL_COND(!res);
|
||||||
|
_portal_resources.occluder_resource_update_spheres(res->occluder_resource_id, p_spheres);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualServerScene::occluder_resource_mesh_update(RID p_occluder_resource, const Geometry::OccluderMeshData &p_mesh_data) {
|
||||||
|
OccluderResource *res = occluder_resource_owner.getornull(p_occluder_resource);
|
||||||
|
ERR_FAIL_COND(!res);
|
||||||
|
_portal_resources.occluder_resource_update_mesh(res->occluder_resource_id, p_mesh_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::set_use_occlusion_culling(bool p_enable) {
|
void VisualServerScene::set_use_occlusion_culling(bool p_enable) {
|
||||||
|
|
@ -4505,10 +4528,15 @@ bool VisualServerScene::free(RID p_rid) {
|
||||||
RoomGroup *roomgroup = roomgroup_owner.get(p_rid);
|
RoomGroup *roomgroup = roomgroup_owner.get(p_rid);
|
||||||
roomgroup_owner.free(p_rid);
|
roomgroup_owner.free(p_rid);
|
||||||
memdelete(roomgroup);
|
memdelete(roomgroup);
|
||||||
} else if (occluder_owner.owns(p_rid)) {
|
} else if (occluder_instance_owner.owns(p_rid)) {
|
||||||
Occluder *ro = occluder_owner.get(p_rid);
|
OccluderInstance *occ_inst = occluder_instance_owner.get(p_rid);
|
||||||
occluder_owner.free(p_rid);
|
occluder_instance_owner.free(p_rid);
|
||||||
memdelete(ro);
|
memdelete(occ_inst);
|
||||||
|
} else if (occluder_resource_owner.owns(p_rid)) {
|
||||||
|
OccluderResource *occ_res = occluder_resource_owner.get(p_rid);
|
||||||
|
occ_res->destroy(_portal_resources);
|
||||||
|
occluder_resource_owner.free(p_rid);
|
||||||
|
memdelete(occ_res);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -729,29 +729,47 @@ public:
|
||||||
virtual void roomgroup_add_room(RID p_roomgroup, RID p_room);
|
virtual void roomgroup_add_room(RID p_roomgroup, RID p_room);
|
||||||
|
|
||||||
// Occluders
|
// Occluders
|
||||||
struct Occluder : RID_Data {
|
struct OccluderInstance : RID_Data {
|
||||||
uint32_t scenario_occluder_id = 0;
|
uint32_t scenario_occluder_id = 0;
|
||||||
Scenario *scenario = nullptr;
|
Scenario *scenario = nullptr;
|
||||||
virtual ~Occluder() {
|
virtual ~OccluderInstance() {
|
||||||
if (scenario) {
|
if (scenario) {
|
||||||
scenario->_portal_renderer.occluder_destroy(scenario_occluder_id);
|
scenario->_portal_renderer.occluder_instance_destroy(scenario_occluder_id);
|
||||||
scenario = nullptr;
|
scenario = nullptr;
|
||||||
scenario_occluder_id = 0;
|
scenario_occluder_id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
RID_Owner<Occluder> occluder_owner;
|
RID_Owner<OccluderInstance> occluder_instance_owner;
|
||||||
|
|
||||||
virtual RID occluder_create();
|
struct OccluderResource : RID_Data {
|
||||||
virtual void occluder_set_scenario(RID p_occluder, RID p_scenario, VisualServer::OccluderType p_type);
|
uint32_t occluder_resource_id = 0;
|
||||||
virtual void occluder_spheres_update(RID p_occluder, const Vector<Plane> &p_spheres);
|
void destroy(PortalResources &r_portal_resources) {
|
||||||
virtual void occluder_mesh_update(RID p_occluder, const Geometry::OccluderMeshData &p_mesh_data);
|
r_portal_resources.occluder_resource_destroy(occluder_resource_id);
|
||||||
virtual void occluder_set_transform(RID p_occluder, const Transform &p_xform);
|
occluder_resource_id = 0;
|
||||||
virtual void occluder_set_active(RID p_occluder, bool p_active);
|
}
|
||||||
|
virtual ~OccluderResource() {
|
||||||
|
DEV_ASSERT(occluder_resource_id == 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
RID_Owner<OccluderResource> occluder_resource_owner;
|
||||||
|
|
||||||
|
virtual RID occluder_instance_create();
|
||||||
|
virtual void occluder_instance_set_scenario(RID p_occluder_instance, RID p_scenario);
|
||||||
|
virtual void occluder_instance_link_resource(RID p_occluder_instance, RID p_occluder_resource);
|
||||||
|
virtual void occluder_instance_set_transform(RID p_occluder_instance, const Transform &p_xform);
|
||||||
|
virtual void occluder_instance_set_active(RID p_occluder_instance, bool p_active);
|
||||||
|
|
||||||
|
virtual RID occluder_resource_create();
|
||||||
|
virtual void occluder_resource_prepare(RID p_occluder_resource, VisualServer::OccluderType p_type);
|
||||||
|
virtual void occluder_resource_spheres_update(RID p_occluder_resource, const Vector<Plane> &p_spheres);
|
||||||
|
virtual void occluder_resource_mesh_update(RID p_occluder_resource, const Geometry::OccluderMeshData &p_mesh_data);
|
||||||
virtual void set_use_occlusion_culling(bool p_enable);
|
virtual void set_use_occlusion_culling(bool p_enable);
|
||||||
|
|
||||||
// editor only .. slow
|
// editor only .. slow
|
||||||
virtual Geometry::MeshData occlusion_debug_get_current_polys(RID p_scenario) const;
|
virtual Geometry::MeshData occlusion_debug_get_current_polys(RID p_scenario) const;
|
||||||
|
const PortalResources &get_portal_resources() const { return _portal_resources; }
|
||||||
|
PortalResources &get_portal_resources() { return _portal_resources; }
|
||||||
|
|
||||||
// Rooms
|
// Rooms
|
||||||
struct Room : RID_Data {
|
struct Room : RID_Data {
|
||||||
|
|
@ -876,6 +894,7 @@ public:
|
||||||
private:
|
private:
|
||||||
bool _use_bvh;
|
bool _use_bvh;
|
||||||
VisualServerCallbacks *_visual_server_callbacks;
|
VisualServerCallbacks *_visual_server_callbacks;
|
||||||
|
PortalResources _portal_resources;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VisualServerScene();
|
VisualServerScene();
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,8 @@ void VisualServerWrapMT::finish() {
|
||||||
roomgroup_free_cached_ids();
|
roomgroup_free_cached_ids();
|
||||||
portal_free_cached_ids();
|
portal_free_cached_ids();
|
||||||
ghost_free_cached_ids();
|
ghost_free_cached_ids();
|
||||||
occluder_free_cached_ids();
|
occluder_instance_free_cached_ids();
|
||||||
|
occluder_resource_free_cached_ids();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerWrapMT::set_use_vsync_callback(bool p_enable) {
|
void VisualServerWrapMT::set_use_vsync_callback(bool p_enable) {
|
||||||
|
|
|
||||||
|
|
@ -518,12 +518,16 @@ public:
|
||||||
FUNC2(roomgroup_add_room, RID, RID)
|
FUNC2(roomgroup_add_room, RID, RID)
|
||||||
|
|
||||||
// Occluders
|
// Occluders
|
||||||
FUNCRID(occluder)
|
FUNCRID(occluder_instance)
|
||||||
FUNC3(occluder_set_scenario, RID, RID, OccluderType)
|
FUNC2(occluder_instance_set_scenario, RID, RID)
|
||||||
FUNC2(occluder_spheres_update, RID, const Vector<Plane> &)
|
FUNC2(occluder_instance_link_resource, RID, RID)
|
||||||
FUNC2(occluder_mesh_update, RID, const Geometry::OccluderMeshData &)
|
FUNC2(occluder_instance_set_transform, RID, const Transform &)
|
||||||
FUNC2(occluder_set_transform, RID, const Transform &)
|
FUNC2(occluder_instance_set_active, RID, bool)
|
||||||
FUNC2(occluder_set_active, RID, bool)
|
|
||||||
|
FUNCRID(occluder_resource)
|
||||||
|
FUNC2(occluder_resource_prepare, RID, OccluderType)
|
||||||
|
FUNC2(occluder_resource_spheres_update, RID, const Vector<Plane> &)
|
||||||
|
FUNC2(occluder_resource_mesh_update, RID, const Geometry::OccluderMeshData &)
|
||||||
FUNC1(set_use_occlusion_culling, bool)
|
FUNC1(set_use_occlusion_culling, bool)
|
||||||
FUNC1RC(Geometry::MeshData, occlusion_debug_get_current_polys, RID)
|
FUNC1RC(Geometry::MeshData, occlusion_debug_get_current_polys, RID)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -917,12 +917,17 @@ public:
|
||||||
OCCLUDER_TYPE_NUM_TYPES,
|
OCCLUDER_TYPE_NUM_TYPES,
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual RID occluder_create() = 0;
|
virtual RID occluder_instance_create() = 0;
|
||||||
virtual void occluder_set_scenario(RID p_occluder, RID p_scenario, VisualServer::OccluderType p_type) = 0;
|
virtual void occluder_instance_set_scenario(RID p_occluder_instance, RID p_scenario) = 0;
|
||||||
virtual void occluder_spheres_update(RID p_occluder, const Vector<Plane> &p_spheres) = 0;
|
virtual void occluder_instance_link_resource(RID p_occluder_instance, RID p_occluder_resource) = 0;
|
||||||
virtual void occluder_mesh_update(RID p_occluder, const Geometry::OccluderMeshData &p_mesh_data) = 0;
|
virtual void occluder_instance_set_transform(RID p_occluder_instance, const Transform &p_xform) = 0;
|
||||||
virtual void occluder_set_transform(RID p_occluder, const Transform &p_xform) = 0;
|
virtual void occluder_instance_set_active(RID p_occluder_instance, bool p_active) = 0;
|
||||||
virtual void occluder_set_active(RID p_occluder, bool p_active) = 0;
|
|
||||||
|
virtual RID occluder_resource_create() = 0;
|
||||||
|
virtual void occluder_resource_prepare(RID p_occluder_resource, VisualServer::OccluderType p_type) = 0;
|
||||||
|
virtual void occluder_resource_spheres_update(RID p_occluder_resource, const Vector<Plane> &p_spheres) = 0;
|
||||||
|
virtual void occluder_resource_mesh_update(RID p_occluder_resource, const Geometry::OccluderMeshData &p_mesh_data) = 0;
|
||||||
|
|
||||||
virtual void set_use_occlusion_culling(bool p_enable) = 0;
|
virtual void set_use_occlusion_culling(bool p_enable) = 0;
|
||||||
virtual Geometry::MeshData occlusion_debug_get_current_polys(RID p_scenario) const = 0;
|
virtual Geometry::MeshData occlusion_debug_get_current_polys(RID p_scenario) const = 0;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue