diff --git a/documentation/levels/level_objects/collision.md b/documentation/levels/level_objects/collision.md index 2becfb5..b3a732c 100644 --- a/documentation/levels/level_objects/collision.md +++ b/documentation/levels/level_objects/collision.md @@ -18,8 +18,9 @@ Static level collision geometry. Must be a quad. ## Notes -Game objects in the same [room](./room.md) and on the same collision layer can -collide. Some layers are also used for certain checks by the game. +Game objects can collide if they share a collision layer. Some layers are also +used for certain checks by the game. Static collision is only collidable if it +is in the same [room](./room.md) If no collision layers are specified, the defaults are `STATIC`, `TANGIBLE`, and `BLOCK_BALL`. The possible layers and their uses are as follows. diff --git a/documentation/levels/level_objects/doorway.md b/documentation/levels/level_objects/doorway.md index fd2d4d1..39eefcd 100644 --- a/documentation/levels/level_objects/doorway.md +++ b/documentation/levels/level_objects/doorway.md @@ -17,6 +17,13 @@ associated with a [door](./door.md)). If a doorway is closed, its rooms are not considered connected at that point (other open doorways count). Only the player's current room and visible connected rooms are considered for rendering. +Doorway visibility checks do not consider objects which may be covering a +doorway - just that it is within the bounds of the previous doorway from the +camera's point of view (or within the bounds of the camera itself, if there is +no previous doorway). To block visibility in these cases, either use an +additional room such that looking through all necessary doorways at once is +impossible or set the room's `can_see` argument. + Passing through an open doorway updates an object's room index, allowing it to collide with other objects in the entered room while ignoring those in the exited room. diff --git a/documentation/levels/level_objects/room.md b/documentation/levels/level_objects/room.md index 4a10719..f428fb0 100644 --- a/documentation/levels/level_objects/room.md +++ b/documentation/levels/level_objects/room.md @@ -6,14 +6,15 @@ collision. ## Name structure ``` -@room INDEX +@room INDEX [can_see R1,R2,...,RN] ``` ## Arguments -| Name | Description | -| ------- | -------------------------------------------- | -| `INDEX` | The index number of the room the box defines | +| Name | Description | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `INDEX` | The index number of the room the box defines | +| `can_see R1,R2,...,RN` (optional) | If specified, rooms outside the comma-separated list will not be considered visible from the current room. This is useful for room shapes which cannot be handled by standard visibility checks. | ## Notes @@ -23,7 +24,7 @@ know their room index, which is updated when passing through [doorways](./doorway.md). For performance reasons, only the player's current room and those visible -through open doorways are considered for rendering, and only objects in the same -room can collide with each other. +through open doorways are considered for rendering, and objects can only collide +with static [collision](./collision.md) in their current room. Levels are limited to 64 rooms. diff --git a/src/levels/static_render.c b/src/levels/static_render.c index ea84810..a4e8cd1 100644 --- a/src/levels/static_render.c +++ b/src/levels/static_render.c @@ -117,7 +117,7 @@ void staticRenderPopulateRooms(struct FrustumCullingInformation* cullingInfo, Mt #define FORCE_RENDER_DOORWAY_DISTANCE 0.1f -void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* cullingInfo, u16 currentRoom, u64* visitedRooms) { +void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* cullingInfo, u16 currentRoom, u64* visitedRooms, u64 nonVisibleRooms) { if (currentRoom == RIGID_BODY_NO_ROOM) { return; } @@ -125,6 +125,8 @@ void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* culling u64 roomMask = 1LL << currentRoom; *visitedRooms |= roomMask; + nonVisibleRooms |= gCurrentLevel->world.rooms[currentRoom].nonVisibleRooms; + for (int i = 0; i < gCurrentLevel->world.rooms[currentRoom].doorwayCount; ++i) { struct Doorway* doorway = &gCurrentLevel->world.doorways[gCurrentLevel->world.rooms[currentRoom].doorwayIndices[i]]; @@ -133,7 +135,8 @@ void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* culling } int newRoom = currentRoom == doorway->roomA ? doorway->roomB : doorway->roomA; - if (*visitedRooms & (1LL << newRoom)) { + u64 newRoomMask = 1LL << newRoom; + if ((*visitedRooms & newRoomMask) || (nonVisibleRooms & newRoomMask)) { continue; } @@ -154,7 +157,7 @@ void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* culling struct FrustumCullingInformation doorwayFrustum; frustumFromQuad(&cullingInfo->cameraPos, &doorway->quad, &doorwayFrustum); - staticRenderDetermineVisibleRooms(&doorwayFrustum, newRoom, visitedRooms); + staticRenderDetermineVisibleRooms(&doorwayFrustum, newRoom, visitedRooms, nonVisibleRooms); }; } diff --git a/src/levels/static_render.h b/src/levels/static_render.h index 9bf6c4b..d6afea1 100644 --- a/src/levels/static_render.h +++ b/src/levels/static_render.h @@ -6,7 +6,7 @@ #include "scene/camera.h" #include "../scene/dynamic_render_list.h" -void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* cullingInfo, u16 currentRoom, u64* visitedRooms); +void staticRenderDetermineVisibleRooms(struct FrustumCullingInformation* cullingInfo, u16 currentRoom, u64* visitedRooms, u64 nonVisibleRooms); int staticRenderIsRoomVisible(u64 visibleRooms, u16 roomIndex); void staticRender(struct Transform* cameraTransform, struct FrustumCullingInformation* cullingInfo, u64 visibleRooms, struct DynamicRenderDataList* dynamicList, int stageIndex, Mtx* staticMatrices, struct Transform* staticTransforms, struct RenderState* renderState); diff --git a/src/physics/world.h b/src/physics/world.h index 7355ffd..6c63599 100644 --- a/src/physics/world.h +++ b/src/physics/world.h @@ -29,6 +29,8 @@ struct Room { short* doorwayIndices; short doorwayCount; + + u64 nonVisibleRooms; }; struct World { diff --git a/src/scene/render_plan.c b/src/scene/render_plan.c index 6a5dda4..a6eb4e3 100644 --- a/src/scene/render_plan.c +++ b/src/scene/render_plan.c @@ -370,7 +370,7 @@ int renderShouldRenderOtherPortal(struct Scene* scene, int visiblePortal, struct } void renderPlanFinishView(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderProps* properties, struct RenderState* renderState) { - staticRenderDetermineVisibleRooms(&properties->cameraMatrixInfo.cullingInformation, properties->fromRoom, &properties->visiblerooms); + staticRenderDetermineVisibleRooms(&properties->cameraMatrixInfo.cullingInformation, properties->fromRoom, &properties->visiblerooms, 0); struct Ray cameraRay; quatMultVector(&properties->camera.transform.rotation, &gForward, &cameraRay.dir); diff --git a/tools/level_scripts/room_export.lua b/tools/level_scripts/room_export.lua index b9b5b12..eb02759 100644 --- a/tools/level_scripts/room_export.lua +++ b/tools/level_scripts/room_export.lua @@ -1,14 +1,29 @@ local sk_scene = require('sk_scene') local sk_math = require('sk_math') +local util = require('tools.level_scripts.util') local room_blocks = {} local room_count = 0 local room_bb = {} +local room_non_visibility = {} for _, room in pairs(sk_scene.nodes_for_type("@room")) do local firstMesh = room.node.meshes[1]:transform(room.node.full_transformation) local room_index = tonumber(room.arguments[1]) + local non_visible_rooms = 0 + + local can_see = sk_scene.find_named_argument(room.arguments, "can_see") + if can_see then + local visible_rooms = 1 << room_index + + local can_see_rooms = util.string_split(util.trim(can_see), ',') + for _, can_see_index in pairs(can_see_rooms) do + visible_rooms = visible_rooms | (1 << tonumber(can_see_index)) + end + + non_visible_rooms = ~visible_rooms + end room_count = math.max(room_count, room_index + 1) @@ -18,6 +33,12 @@ for _, room in pairs(sk_scene.nodes_for_type("@room")) do room_bb[room_index + 1] = firstMesh.bb end + if room_non_visibility[room_index + 1] then + room_non_visibility[room_index + 1] = room_non_visibility[room_index + 1] | non_visible_rooms + else + room_non_visibility[room_index + 1] = non_visible_rooms + end + table.insert(room_blocks, { bb = firstMesh.bb, room_index = room_index, @@ -63,4 +84,5 @@ return { node_nearest_room_index = node_nearest_room_index, room_count = room_count, room_bb = room_bb, + room_non_visibility = room_non_visibility, } \ No newline at end of file diff --git a/tools/level_scripts/world.lua b/tools/level_scripts/world.lua index 482242c..496ec45 100644 --- a/tools/level_scripts/world.lua +++ b/tools/level_scripts/world.lua @@ -128,6 +128,7 @@ local function generate_room(room_index) room_export.room_bb[room_index] or sk_math.box3(), sk_definition_writer.reference_to(room_doorways[room_index], 1), #room_doorways[room_index], + room_export.room_non_visibility[room_index] } end