diff --git a/skelatool64/lua/sk_math.lua b/skelatool64/lua/sk_math.lua index b6f4a2f..05ffd58 100644 --- a/skelatool64/lua/sk_math.lua +++ b/skelatool64/lua/sk_math.lua @@ -316,7 +316,7 @@ function Box3.nearest_point_in_box(box, point) return Vector3.min(box.max, point):max(box.min) end ---- Returns the point inside or on the box that is nearest to the given point +--- Returns true of the two bounding boxes have some volume in common --- @function overlaps --- @tparam Vector3|Box3 box_or_point --- @treturn boolean diff --git a/src/savefile/scene_serialize.c b/src/savefile/scene_serialize.c index b3a637f..460fdcc 100644 --- a/src/savefile/scene_serialize.c +++ b/src/savefile/scene_serialize.c @@ -51,6 +51,8 @@ void sceneSerializePortals(struct Serializer* serializer, SerializeAction action } } +#define PORTAL_FLAGS_TO_DESERIALIZE (PortalFlagsPlayerPortal | PortalFlagsZOffset) + void sceneDeserializePortals(struct Serializer* serializer, struct Scene* scene) { for (int portalIndex = 0; portalIndex < 2; ++portalIndex) { char flags; @@ -98,11 +100,8 @@ void sceneDeserializePortals(struct Serializer* serializer, struct Scene* scene) collisionSceneSetPortal(portalIndex, &portal->rigidBody.transform, roomIndex, colliderIndex); collisionObjectUpdateBB(&portal->collisionObject); - if (flags & PortalFlagsPlayerPortal) { - portal->flags |= PortalFlagsPlayerPortal; - } else { - portal->flags &= ~PortalFlagsPlayerPortal; - } + portal->flags &= ~PORTAL_FLAGS_TO_DESERIALIZE; + portal->flags |= PORTAL_FLAGS_TO_DESERIALIZE & flags; portal->opacity = 0.0f; } diff --git a/src/scene/portal.h b/src/scene/portal.h index 8b771c5..f4d7053 100644 --- a/src/scene/portal.h +++ b/src/scene/portal.h @@ -17,6 +17,7 @@ enum PortalFlags { PortalFlagsOddParity = (1 << 0), PortalFlagsPlayerPortal = (1 << 2), + PortalFlagsZOffset = (1 << 3), }; struct Portal { diff --git a/src/scene/portal_surface.h b/src/scene/portal_surface.h index ecee8c3..b2c104e 100644 --- a/src/scene/portal_surface.h +++ b/src/scene/portal_surface.h @@ -27,6 +27,7 @@ struct PortalSurface { u8 edgeCount; u8 vertexCount; u8 shouldCleanup; + u8 hasDecals; struct Vector3 right; struct Vector3 up; diff --git a/src/scene/render_plan.c b/src/scene/render_plan.c index c11929d..5de7cfb 100644 --- a/src/scene/render_plan.c +++ b/src/scene/render_plan.c @@ -563,13 +563,15 @@ void renderPlanExecute(struct RenderPlan* renderPlan, struct Scene* scene, Mtx* faceModel = portal_portal_orange_face_model_gfx; portalModel = portal_portal_orange_model_gfx; } - - // render the portal cover with a slightly offset z - // so it doesn't z fight with the surface it is attached to - Vp* vpWithOffset = renderStateRequestViewport(renderState); - *vpWithOffset = *current->viewport; - vpWithOffset->vp.vtrans[2] -= 1; - gSPViewport(renderState->dl++, vpWithOffset); + + if (portal->flags & PortalFlagsZOffset) { + // render the portal cover with a slightly offset z + // so it doesn't z fight with the surface it is attached to + Vp* vpWithOffset = renderStateRequestViewport(renderState); + *vpWithOffset = *current->viewport; + vpWithOffset->vp.vtrans[2] -= 2; + gSPViewport(renderState->dl++, vpWithOffset); + } gSPDisplayList(renderState->dl++, faceModel); gSPViewport(renderState->dl++, current->viewport); if (current->previousProperties == NULL && portalIndex == renderPlan->clippedPortalIndex && renderPlan->nearPolygonCount) { diff --git a/src/scene/scene.c b/src/scene/scene.c index affd296..fc1b658 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -860,6 +860,12 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int transformInde portal->flags &= ~PortalFlagsPlayerPortal; } + if (existingSurface->hasDecals) { + portal->flags |= PortalFlagsZOffset; + } else { + portal->flags &= ~PortalFlagsZOffset; + } + if (collisionSceneIsPortalOpen()) { // the second portal is fully transparent right away portal->opacity = 0.0f; diff --git a/tools/level_scripts/portal_surfaces.lua b/tools/level_scripts/portal_surfaces.lua index 0c2306b..f332a50 100644 --- a/tools/level_scripts/portal_surfaces.lua +++ b/tools/level_scripts/portal_surfaces.lua @@ -58,7 +58,7 @@ local function get_edge_index(edges, edge_key) return 0xFF end -local function calculate_portal_single_surface(mesh, mesh_display_list) +local function calculate_portal_single_surface(mesh, mesh_display_list, has_decals) local origin = mesh.bb:lerp(0.5) local right, up, normal = calculate_surface_basis(mesh) @@ -129,6 +129,7 @@ local function calculate_portal_single_surface(mesh, mesh_display_list) edgeCount = #edges, vertexCount = #vertices, shouldCleanup = 0, + hasDecals = has_decals, right = right, up = up, @@ -142,7 +143,7 @@ end for _, surface in pairs(static_export.static_nodes) do if surface.accept_portals then table.insert(static_to_portable_surface_mapping, #portal_surfaces) - table.insert(portal_surfaces, calculate_portal_single_surface(surface.mesh, surface.display_list)) + table.insert(portal_surfaces, calculate_portal_single_surface(surface.mesh, surface.display_list, surface.has_decals)) else table.insert(static_to_portable_surface_mapping, -1) end diff --git a/tools/level_scripts/static_export.lua b/tools/level_scripts/static_export.lua index 71d8ecd..960d17d 100644 --- a/tools/level_scripts/static_export.lua +++ b/tools/level_scripts/static_export.lua @@ -33,7 +33,7 @@ local function is_coplanar(mesh, plane) end local function should_join_mesh(entry) - return entry.plane ~= nil + return entry.should_join_mesh end local function bb_union_cost(a, b) @@ -76,6 +76,28 @@ local function bb_list(bb) } end +local function check_for_decals(portal_surface, all_static_ndes) + if not portal_surface.accept_portals then + return false + end + + local box_with_padding = sk_math.box3(portal_surface.original_bb.min - 0.1, portal_surface.original_bb.max + 0.1) + + for _, other in pairs(all_static_ndes) do + local material = other.chunk.mesh.material + + if material.renderMode and + material.renderMode.zMode == "ZMODE_DEC" and + portal_surface.transform_index == other.transform_index and + is_coplanar(other.chunk.mesh, portal_surface.plane) and + box_with_padding:overlaps(other.original_bb) then + return true + end + end + + return false +end + local function list_static_nodes(nodes) local result = {} local bb_scale = sk_input.settings.fixed_point_scale @@ -100,10 +122,11 @@ local function list_static_nodes(nodes) end local plane = sk_math.plane3_with_point(chunkV.mesh.normals[1], chunkV.mesh.vertices[1]) - local accept_portals =chunkV.mesh.material and portalable_surfaces[chunkV.mesh.material.name] and not sk_scene.find_flag_argument(v.arguments, "no_portals") + local should_join_mesh = true + local accept_portals = chunkV.mesh.material and portalable_surfaces[chunkV.mesh.material.name] and not sk_scene.find_flag_argument(v.arguments, "no_portals") if transform_index or signal or accept_portals or not is_coplanar(chunkV.mesh, plane) then - plane = nil + should_join_mesh = false end insert_or_merge(result, { @@ -113,13 +136,19 @@ local function list_static_nodes(nodes) transform_index = transform_index, room_index = room_export.node_nearest_room_index(v.node) or 0, accept_portals = accept_portals, + has_decals = false, signal = signal, original_bb = original_bb, plane = plane, + should_join_mesh = should_join_mesh, }) end end + for _, node in pairs(result) do + node.has_decals = check_for_decals(node, result) + end + return result; end @@ -320,6 +349,7 @@ local function process_static_nodes(nodes) transform_index = source_node.transform_index, room_index = source_node.room_index, accept_portals = source_node.accept_portals, + has_decals = source_node.has_decals, signal = source_node.signal, }) end