Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion trview.app.tests/Elements/RoomTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <trview.common/Algorithms.h>
#include <trview.common/Mocks/Logs/ILog.h>
#include <trview.graphics/Mocks/ISamplerState.h>
#include <trview.app/Mocks/Elements/IPortal.h>

using namespace trview;
using namespace trview::mocks;
Expand All @@ -40,11 +41,12 @@ namespace
ISector::Source sector_source{ [](auto&&...) { return mock_shared<MockSector>(); } };
std::shared_ptr<ILog> log{ mock_shared<MockLog>() };
graphics::ISamplerState::Source sampler_source{ [](auto&&...) { return mock_shared<MockSamplerState>(); } };
IPortal::Source portal_source{ [](auto&&...) { return mock_shared<MockPortal>(); } };

std::shared_ptr<Room> build()
{
auto new_room = std::make_shared<Room>(room, mesh_source, level_texture_storage, index, level, sampler_source);
new_room->initialise(*tr_level, room, *mesh_storage, static_mesh_source, static_mesh_position_source, sector_source, 0, Activity(log, "Level", "Room 0"));
new_room->initialise(*tr_level, room, *mesh_storage, static_mesh_source, static_mesh_position_source, sector_source, 0, portal_source, Activity(log, "Level", "Room 0"));
return new_room;
}

Expand Down
7 changes: 6 additions & 1 deletion trview.app/ApplicationCreate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,16 @@ namespace trview

auto ngplus = std::make_shared<NgPlusSwitcher>(entity_source);

auto portal_source = [&](auto&&... args)
{
return std::make_shared<Portal>(args...);
};

auto room_source = [=](const trlevel::ILevel& level, const trlevel::tr3_room& room,
const std::shared_ptr<ILevelTextureStorage>& texture_storage, const IMeshStorage& mesh_storage, uint32_t index, const std::weak_ptr<ILevel>& parent_level, uint32_t sector_base_index, const Activity& activity)
{
auto new_room = std::make_shared<Room>(room, mesh_source, texture_storage, index, parent_level, sampler_source);
new_room->initialise(level, room, mesh_storage, static_mesh_source, static_mesh_position_source, sector_source, sector_base_index, activity);
new_room->initialise(level, room, mesh_storage, static_mesh_source, static_mesh_position_source, sector_source, sector_base_index, portal_source, activity);
return new_room;
};
auto trigger_source = [=](auto&&... args) { return std::make_shared<Trigger>(args..., mesh_source); };
Expand Down
3 changes: 3 additions & 0 deletions trview.app/Elements/ILevel.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,16 @@ namespace trview
virtual void set_show_water(bool show) = 0;
virtual void set_show_wireframe(bool show) = 0;
virtual void set_show_bounding_boxes(bool show) = 0;
virtual void set_show_horizontal_portals(bool show) = 0;
virtual void set_show_lighting(bool show) = 0;
virtual void set_show_lights(bool show) = 0;
virtual void set_show_portals(bool show) = 0;
virtual void set_show_items(bool show) = 0;
virtual void set_show_rooms(bool show) = 0;
virtual void set_show_camera_sinks(bool show) = 0;
virtual void set_show_sound_sources(bool show) = 0;
virtual void set_show_animation(bool show) = 0;
virtual void set_show_vertical_portals(bool show) = 0;
virtual void set_neighbour_depth(uint32_t depth) = 0;
virtual void set_selected_room(const std::weak_ptr<IRoom>& room) = 0;
virtual void set_selected_item(const std::weak_ptr<IItem>& item) = 0;
Expand Down
2 changes: 2 additions & 0 deletions trview.app/Elements/IRoom.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "CameraSink/ICameraSink.h"
#include "IStaticMesh.h"
#include "../Filters/IFilterable.h"
#include "Portal/Portal.h"

namespace trview
{
Expand Down Expand Up @@ -330,6 +331,7 @@ namespace trview
virtual std::vector<std::weak_ptr<IStaticMesh>> static_meshes() const = 0;
virtual void update(float delta) = 0;
virtual uint16_t water_scheme() const = 0;
virtual std::vector<std::weak_ptr<IPortal>> portals() const = 0;
};

/// <summary>
Expand Down
18 changes: 18 additions & 0 deletions trview.app/Elements/Level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,24 @@ namespace trview
{
_show_animation = show;
}

void Level::set_show_portals(bool show)
{
_render_filters = set_flag(_render_filters, RenderFilter::Portals, show);
_regenerate_transparency = true;
}

void Level::set_show_horizontal_portals(bool show)
{
_render_filters = set_flag(_render_filters, RenderFilter::PortalsHorizontal, show);
_regenerate_transparency = true;
}

void Level::set_show_vertical_portals(bool show)
{
_render_filters = set_flag(_render_filters, RenderFilter::PortalsVertical, show);
_regenerate_transparency = true;
}

void Level::receive_message(const Message& message)
{
Expand Down
3 changes: 3 additions & 0 deletions trview.app/Elements/Level.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ namespace trview
void update(float delta) override;
void set_show_animation(bool show) override;
void receive_message(const Message& message) override;
void set_show_horizontal_portals(bool show) override;
void set_show_vertical_portals(bool show) override;
void set_show_portals(bool show) override;
private:
void generate_rooms(const trlevel::ILevel& level, const IRoom::Source& room_source, const IMeshStorage& mesh_storage);
void generate_triggers(const ITrigger::Source& trigger_source);
Expand Down
22 changes: 22 additions & 0 deletions trview.app/Elements/Portal/IPortal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <functional>
#include <memory>

#include <trlevel/trtypes.h>

namespace trview
{
struct ITransparencyBuffer;
struct ICamera;

struct IPortal
{
using Source = std::function<std::shared_ptr<IPortal>(const trlevel::tr_room_portal&, const DirectX::SimpleMath::Vector3&)>;
virtual ~IPortal() = 0;
virtual void get_transparent_triangles(ITransparencyBuffer& transparency, const ICamera& camera) = 0;
virtual DirectX::SimpleMath::Vector3 normal() const = 0;
virtual uint16_t room() const = 0;
virtual std::vector<DirectX::SimpleMath::Vector3> vertices() const = 0;
};
}
51 changes: 51 additions & 0 deletions trview.app/Elements/Portal/Portal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "Portal.h"
#include "../../Geometry/ITransparencyBuffer.h"

namespace trview
{
IPortal::~IPortal()
{
}

Portal::Portal(const trlevel::tr_room_portal& portal, DirectX::SimpleMath::Vector3 room_offset)
: _room(portal.adjoining_room), _normal(portal.normal.x, portal.normal.y, portal.normal.z), _room_offset(room_offset)
{
_vertices =
{
(DirectX::SimpleMath::Vector3(portal.vertices[0].x, portal.vertices[0].y, portal.vertices[0].z) / trlevel::Scale),
(DirectX::SimpleMath::Vector3(portal.vertices[1].x, portal.vertices[1].y, portal.vertices[1].z) / trlevel::Scale),
(DirectX::SimpleMath::Vector3(portal.vertices[2].x, portal.vertices[2].y, portal.vertices[2].z) / trlevel::Scale),
(DirectX::SimpleMath::Vector3(portal.vertices[3].x, portal.vertices[3].y, portal.vertices[3].z) / trlevel::Scale)
};
}

void Portal::get_transparent_triangles(ITransparencyBuffer& transparency, const ICamera&)
{
const DirectX::SimpleMath::Color portal_colour = DirectX::SimpleMath::Color(1.0f, 0.0f, 0.0f, 0.5f);
transparency.add({
.colours = { portal_colour, portal_colour, portal_colour },
.texture_mode = Triangle::TextureMode::Untextured,
.transparency_mode = Triangle::TransparencyMode::Normal,
.vertices = { _vertices[0] + _room_offset, _vertices[1] + _room_offset, _vertices[2] + _room_offset } });
transparency.add({
.colours = { portal_colour, portal_colour, portal_colour },
.texture_mode = Triangle::TextureMode::Untextured,
.transparency_mode = Triangle::TransparencyMode::Normal,
.vertices = { _vertices[2] + _room_offset, _vertices[3] + _room_offset, _vertices[0] + _room_offset } });
}

DirectX::SimpleMath::Vector3 Portal::normal() const
{
return _normal;
}

uint16_t Portal::room() const
{
return _room;
}

std::vector<DirectX::SimpleMath::Vector3> Portal::vertices() const
{
return _vertices;
}
}
23 changes: 23 additions & 0 deletions trview.app/Elements/Portal/Portal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <vector>
#include "IPortal.h"

namespace trview
{
class Portal final : public IPortal
{
public:
virtual ~Portal() = default;
explicit Portal(const trlevel::tr_room_portal& portal, DirectX::SimpleMath::Vector3 room_offset);
void get_transparent_triangles(ITransparencyBuffer& transparency, const ICamera& camera) override;
DirectX::SimpleMath::Vector3 normal() const override;
uint16_t room() const override;
std::vector<DirectX::SimpleMath::Vector3> vertices() const override;
private:
std::vector<DirectX::SimpleMath::Vector3> _vertices;
DirectX::SimpleMath::Vector3 _room_offset;
DirectX::SimpleMath::Vector3 _normal;
uint16_t _room{ 0u };
};
}
3 changes: 3 additions & 0 deletions trview.app/Elements/RenderFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ namespace trview
Lighting = 0x100,
SoundSources = 0x200,
NgPlus = 0x400,
Portals = 0x800,
PortalsHorizontal = 0x1000,
PortalsVertical = 0x2000,
All = 0xffffffff,
Default = Rooms | Entities | Triggers | Water
};
Expand Down
31 changes: 30 additions & 1 deletion trview.app/Elements/Room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,13 @@ namespace trview

void Room::initialise(const trlevel::ILevel& level, const trlevel::tr3_room& room, const IMeshStorage& mesh_storage,
const IStaticMesh::MeshSource& static_mesh_mesh_source, const IStaticMesh::PositionSource& static_mesh_position_source,
const ISector::Source& sector_source, uint32_t sector_base_index, const Activity& activity)
const ISector::Source& sector_source, uint32_t sector_base_index, const IPortal::Source& portal_source, const Activity& activity)
{
generate_sectors(level, room, sector_source, sector_base_index);
generate_geometry(_mesh_source, room);
generate_adjacency();
generate_static_meshes(_mesh_source, level, room, mesh_storage, static_mesh_mesh_source, static_mesh_position_source, activity);
generate_portals(portal_source, room);
}

RoomInfo Room::info() const
Expand Down Expand Up @@ -585,6 +586,19 @@ namespace trview
}
}

if (has_flag(render_filter, RenderFilter::Portals) &&
has_any_flag(render_filter, RenderFilter::PortalsHorizontal, RenderFilter::PortalsVertical))
{
for (const auto& portal : _portals)
{
if ((has_flag(render_filter, RenderFilter::PortalsHorizontal) && portal->normal().y == 0) ||
(has_flag(render_filter, RenderFilter::PortalsVertical) && portal->normal().y != 0))
{
portal->get_transparent_triangles(transparency, camera);
}
}
}

get_contained_transparent_triangles(transparency, camera, colour, render_filter);
}

Expand Down Expand Up @@ -1281,6 +1295,21 @@ namespace trview
}
}

std::vector<std::weak_ptr<IPortal>> Room::portals() const
{
return _portals | std::ranges::to<std::vector<std::weak_ptr<IPortal>>>();
}

void Room::generate_portals(const IPortal::Source& portal_source, const trlevel::tr3_room& room)
{
if (auto level = _level.lock())
{
const float offset_y = level->platform_and_version().platform == trlevel::Platform::PSX ? static_cast<float>(room.info.yTop) : 0.0f;
const auto offset = DirectX::SimpleMath::Vector3 { static_cast<float>(room.info.x), offset_y, static_cast<float>(room.info.z) } / trlevel::Scale;
_portals = room.portals | std::views::transform([&](auto&& p) { return portal_source(p, offset); }) | std::ranges::to<std::vector>();
}
}

uint16_t Room::water_scheme() const
{
return _water_scheme;
Expand Down
8 changes: 5 additions & 3 deletions trview.app/Elements/Room.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <trview.app/Geometry/IMesh.h>
#include <trview.app/Elements/ISector.h>
#include <trview.app/Geometry/PickResult.h>
#include "Portal/IPortal.h"
#include <trview.graphics/Texture.h>
#include "IStaticMesh.h"
#include "IRoom.h"
Expand Down Expand Up @@ -101,10 +102,12 @@ namespace trview
const IStaticMesh::PositionSource& static_mesh_position_source,
const ISector::Source& sector_source,
uint32_t sector_base_index,
const IPortal::Source& portal_source,
const Activity& activity);
std::vector<std::weak_ptr<IStaticMesh>> static_meshes() const override;
void update(float delta) override;
uint16_t water_scheme() const override;
std::vector<std::weak_ptr<IPortal>> portals() const override;
int32_t filterable_index() const override;
private:
void generate_geometry(const IMesh::Source& mesh_source, const trlevel::tr3_room& room);
Expand All @@ -116,15 +119,13 @@ namespace trview
void generate_sectors(const trlevel::ILevel& level, const trlevel::tr3_room& room, const ISector::Source& sector_source, uint32_t sector_base_index);
ISector* get_trigger_sector(const ITrigger& trigger, int32_t dx, int32_t dz);
uint32_t get_sector_id(int32_t x, int32_t z) const;

/// Find any transparent triangles that match floor data geometry.
/// @param transparent_triangles The transparent triangles in the sector.
/// @param collision_triangles The collision output vector.
void process_collision_transparency(std::vector<Triangle>& triangles);

void generate_all_geometry_mesh(const IMesh::Source& mesh_source);

void add_centroid_to_pick(const IMesh& mesh, PickResult& geometry_result) const;
void generate_portals(const IPortal::Source& portal_source, const trlevel::tr3_room& room);

RoomInfo _info;
std::set<uint16_t> _neighbours;
Expand Down Expand Up @@ -171,6 +172,7 @@ namespace trview
std::shared_ptr<graphics::ISamplerState> _geometry_sampler_state;
std::shared_ptr<graphics::ISamplerState> _sampler_state;

std::vector<std::shared_ptr<IPortal>> _portals;
uint16_t _water_scheme{ 0u };
};
}
10 changes: 10 additions & 0 deletions trview.app/Messages/Messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ namespace trview
send_message(messaging, light, "select_light");
}

std::optional<std::weak_ptr<IPortal>> read_select_portal(const Message& message)
{
return read_message<std::weak_ptr<IPortal>>(message, "select_portal");
}

void send_select_portal(const std::weak_ptr<IMessageSystem>& messaging, const std::weak_ptr<IPortal>& portal)
{
send_message(messaging, portal, "select_portal");
}

void get_selected_room(const std::weak_ptr<IMessageSystem>& messaging, const std::weak_ptr<IRecipient>& reply_to)
{
get_message(messaging, reply_to, "get_selected_room");
Expand Down
4 changes: 4 additions & 0 deletions trview.app/Messages/Messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace trview
struct ILevel;
struct ILight;
struct IMessageSystem;
struct IPortal;
struct IRecipient;
struct IRoom;
struct IRoute;
Expand Down Expand Up @@ -105,6 +106,9 @@ namespace trview
std::optional<std::weak_ptr<ILight>> read_select_light(const Message& message);
void send_select_light(const std::weak_ptr<IMessageSystem>& messaging, const std::weak_ptr<ILight>& light);

std::optional<std::weak_ptr<IPortal>> read_select_portal(const Message& message);
void send_select_portal(const std::weak_ptr<IMessageSystem>& messaging, const std::weak_ptr<IPortal>& portal);

void get_selected_room(const std::weak_ptr<IMessageSystem>& messaging, const std::weak_ptr<IRecipient>& reply_to);
std::optional<std::weak_ptr<IRoom>> read_select_room(const Message& message);
void send_select_room(const std::weak_ptr<IMessageSystem>& messaging, const std::weak_ptr<IRoom>& room);
Expand Down
3 changes: 3 additions & 0 deletions trview.app/Mocks/Elements/ILevel.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ namespace trview
MOCK_METHOD(void, update, (float), (override));
MOCK_METHOD(void, set_show_animation, (bool), (override));
MOCK_METHOD(void, receive_message, (const Message&), (override));
MOCK_METHOD(void, set_show_horizontal_portals, (bool), (override));
MOCK_METHOD(void, set_show_vertical_portals, (bool), (override));
MOCK_METHOD(void, set_show_portals, (bool), (override));

std::shared_ptr<MockLevel> with_version(trlevel::LevelVersion version)
{
Expand Down
19 changes: 19 additions & 0 deletions trview.app/Mocks/Elements/IPortal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "../../Elements/Portal/IPortal.h"

namespace trview
{
namespace mocks
{
struct MockPortal : public IPortal
{
explicit MockPortal();
virtual ~MockPortal();
MOCK_METHOD(void, get_transparent_triangles, (ITransparencyBuffer&, const ICamera&), (override));
MOCK_METHOD(DirectX::SimpleMath::Vector3, normal, (), (const, override));
MOCK_METHOD(uint16_t, room, (), (const, override));
MOCK_METHOD(std::vector<DirectX::SimpleMath::Vector3>, vertices, (), (const, override));
};
}
}
1 change: 1 addition & 0 deletions trview.app/Mocks/Elements/IRoom.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ namespace trview
MOCK_METHOD(std::vector<std::weak_ptr<IStaticMesh>>, static_meshes, (), (const));
MOCK_METHOD(void, update, (float), (override));
MOCK_METHOD(uint16_t, water_scheme, (), (const, override));
MOCK_METHOD(std::vector<std::weak_ptr<IPortal>>, portals, (), (const, override));
MOCK_METHOD(int32_t, filterable_index, (), (const, override));

bool _visible_state{ false };
Expand Down
Loading
Loading