diff --git a/Assets/g1/ZROOM.json b/Assets/g1/ZROOM.json index cb20387..faf0ea4 100644 --- a/Assets/g1/ZROOM.json +++ b/Assets/g1/ZROOM.json @@ -8,12 +8,14 @@ "parent": "ZTreeGroup", "properties": [ { - "name": "property_6C", + "name": "iNeighboursCount", + "__comment__": "I'm not sure about that. 6C and 84 sometimes same", "offset": 108, "typename": "PRPOpCode.Int32" }, { - "name": "property_84", + "name": "iExitsCount", + "__comment__": "I'm not sure about that. 6C and 84 sometimes same", "offset": 132, "typename": "PRPOpCode.Int8" }, diff --git a/BMEdit/Editor/Include/Widgets/SceneRenderWidget.h b/BMEdit/Editor/Include/Widgets/SceneRenderWidget.h index 8e4ece5..b5bdac0 100644 --- a/BMEdit/Editor/Include/Widgets/SceneRenderWidget.h +++ b/BMEdit/Editor/Include/Widgets/SceneRenderWidget.h @@ -114,6 +114,8 @@ namespace widgets void invalidateRenderList(); void buildRoomCache(); + void resetLastRoom(); + void updateCameraRoomAttachment(); private: // Data @@ -156,11 +158,31 @@ namespace widgets struct RoomDef { + enum class ELocation : int { + eUNDEFINED = 0, + eOUTSIDE = 1, + eINSIDE = 2, + eBOTH = 3, + }; + + /** + * @brief Weak pointer to entity which represent room + */ gamelib::scene::SceneObject::Ref rRoom {}; + + /** + * @brief World space bounding box which cover whole room. Typically it's been built from collision box, but sometimes it could be a expanded bbox (expanded by children objects) + */ gamelib::BoundingBox vBoundingBox {}; + + /** + * @brief Type of room location. Seee ELocation.json for details + */ + ELocation eLocation { ELocation::eUNDEFINED }; }; std::list m_rooms {}; + const RoomDef* m_pLastRoom { nullptr }; private: void computeRoomBoundingBox(RoomDef& d); diff --git a/BMEdit/Editor/Source/Widgets/SceneRenderWidget.cpp b/BMEdit/Editor/Source/Widgets/SceneRenderWidget.cpp index aa66249..9d22f07 100644 --- a/BMEdit/Editor/Source/Widgets/SceneRenderWidget.cpp +++ b/BMEdit/Editor/Source/Widgets/SceneRenderWidget.cpp @@ -364,6 +364,7 @@ namespace widgets invalidateRenderList(); resetViewMode(); resetRenderMode(); + resetLastRoom(); } } @@ -376,6 +377,7 @@ namespace widgets m_pLevel = nullptr; m_bFirstMouseQuery = true; invalidateRenderList(); + resetLastRoom(); resetViewMode(); resetRenderMode(); repaint(); @@ -1003,28 +1005,60 @@ namespace widgets } else { + // Need to update room before + updateCameraRoomAttachment(); + + if (!m_pLastRoom) + return; // Do nothing + std::list acceptedRooms {}; // Render static + // SEE 0047B190 (ZViewSpace::CheckExitsInRoom) for details. Current solution is piece of crap for (const auto& sRoomDef : m_rooms) { - const bool bCameraInsideRoom = sRoomDef.vBoundingBox.contains(m_camera.getPosition()); + bool bAcceptedAnything = false; - if (bCameraInsideRoom || m_camera.canSeeObject(sRoomDef.vBoundingBox.min, sRoomDef.vBoundingBox.max)) + if (auto eRoomLoc = m_pLastRoom->eLocation; eRoomLoc == RoomDef::ELocation::eBOTH || eRoomLoc == RoomDef::ELocation::eUNDEFINED) { - if (auto pRoom = sRoomDef.rRoom.lock()) + // Render if we've inside or can see + if (sRoomDef.vBoundingBox.contains(m_camera.getPosition()) || m_camera.canSeeObject(sRoomDef.vBoundingBox.min, sRoomDef.vBoundingBox.max)) { - if (bCameraInsideRoom) + // Allowed to render + if (auto pRoom = sRoomDef.rRoom.lock()) { - // Store new room name - stats.currentRoom = QString::fromStdString(pRoom->getName()); + collectRenderEntriesIntoRenderList(pRoom.get(), entries, stats, bIgnoreVisibility); + bAcceptedAnything = true; } - - collectRenderEntriesIntoRenderList(pRoom.get(), entries, stats, bIgnoreVisibility); } + } + else + { + const bool bBothInside = eRoomLoc == RoomDef::ELocation::eINSIDE && sRoomDef.eLocation == RoomDef::ELocation::eINSIDE; + const bool bBothOutside = eRoomLoc == RoomDef::ELocation::eOUTSIDE && sRoomDef.eLocation == RoomDef::ELocation::eOUTSIDE; - acceptedRooms.emplace_back(sRoomDef); + if (bBothInside || bBothOutside) + { + // Allowed to render + if (auto pRoom = sRoomDef.rRoom.lock()) + { + collectRenderEntriesIntoRenderList(pRoom.get(), entries, stats, bIgnoreVisibility); + bAcceptedAnything = true; + } + } } + + // TODO: Here we need to check if we skipped this room we need to check all gates and if we able to see room through gate - include it too + // if (!bAcceptedAnything) + } + + if (auto pRoom = m_pLastRoom->rRoom.lock()) + { + stats.currentRoom = QString::fromStdString(pRoom->getName()); + } + else + { + stats.currentRoom = {}; } // Render dynamic @@ -1075,7 +1109,7 @@ namespace widgets } // Don't draw invisible things - if (bInvisible && !bIgnoreVisibility) + if (bInvisible) return; if (g_bannedObjectIds.contains(std::string_view{geom->getName()})) @@ -1531,6 +1565,8 @@ namespace widgets { auto& room = m_rooms.emplace_back(); room.rRoom = pObject; + room.eLocation = RoomDef::ELocation::eUNDEFINED; + // ZBackdrop always has maximum possible size to see it from any point of the world constexpr float kMinPoint = std::numeric_limits::min(); constexpr float kMaxPoint = std::numeric_limits::max(); @@ -1558,6 +1594,17 @@ namespace widgets auto& room = m_rooms.emplace_back(); room.rRoom = pObject; + //room.eLocation + const auto iLocation = pObject->getProperties().getObject("Location", 0); + if (iLocation >= 0 && iLocation <= 3) + { + room.eLocation = static_cast(iLocation); + } + else + { + assert(false && "Unknown room type, room will be ignored in optimisations loop"); + } + // Compute room dimensions computeRoomBoundingBox(room); @@ -1569,4 +1616,57 @@ namespace widgets }); } } + + void SceneRenderWidget::resetLastRoom() + { + m_pLastRoom = nullptr; + } + + void SceneRenderWidget::updateCameraRoomAttachment() + { + if (!m_pLevel || m_rooms.empty()) + { + m_pLastRoom = nullptr; + return; + } + + // First of all check that we out of our current room + if (m_pLastRoom) + { + if (m_pLastRoom->vBoundingBox.contains(m_camera.getPosition())) + return; // Do nothing + + // Reject current room + m_pLastRoom = nullptr; + } + + std::list foundInRooms {}; + for (const auto& sRoom : m_rooms) + { + if (sRoom.vBoundingBox.contains(m_camera.getPosition())) + { + foundInRooms.emplace_back(&sRoom); + } + } + + if (foundInRooms.empty()) + return; // Out of rooms + + // Then need to sort found rooms list. Firstly we need to have eINSIDE rooms + foundInRooms.sort([this](const RoomDef* a, const RoomDef* b) { + if (a->eLocation == b->eLocation) + { + const float d1 = glm::distance(m_camera.getPosition(), a->vBoundingBox.getCenter()); + const float d2 = glm::distance(m_camera.getPosition(), b->vBoundingBox.getCenter()); + + return d1 < d2; + } + + return static_cast(a->eLocation) > static_cast(b->eLocation); + }); + + // Now, use first found room + // NOTE: Maybe we've better to check that top room is preferable for us? Idk + m_pLastRoom = (*foundInRooms.begin()); + } } \ No newline at end of file diff --git a/BMEdit/Editor/UI/Source/BMEditMainWindow.cpp b/BMEdit/Editor/UI/Source/BMEditMainWindow.cpp index 7478c3c..bfef57d 100644 --- a/BMEdit/Editor/UI/Source/BMEditMainWindow.cpp +++ b/BMEdit/Editor/UI/Source/BMEditMainWindow.cpp @@ -271,6 +271,7 @@ void BMEditMainWindow::onLevelLoadSuccess() // Load controllers index ui->geomControllers->switchToDefaults(); + ui->geomControllers->resetGeom(); // Export action ui->menuExport->setEnabled(true); @@ -289,6 +290,7 @@ void BMEditMainWindow::onLevelLoadFailed(const QString &reason) QMessageBox::warning(this, QString("Failed to load level"), QString("Error occurred during level load process:\n%1").arg(reason)); m_operationCommentLabel->setText(QString("Failed to open level '%1'").arg(reason)); m_operationProgress->setValue(0); + //TODO: Need to reset global state properly! } void BMEditMainWindow::onLevelLoadProgressChanged(int totalPercentsProgress, const QString ¤tOperationTag) @@ -330,6 +332,7 @@ void BMEditMainWindow::onSelectedSceneObject(const gamelib::scene::SceneObject* ui->sceneObjectName->setText(QString::fromStdString(selectedSceneObject->getName())); ui->sceneObjectTypeCombo->setEnabled(true); ui->sceneObjectTypeCombo->setCurrentText(QString::fromStdString(selectedSceneObject->getType()->getName())); + ui->geomInstanceId->setText(QString("%1").arg(selectedSceneObject->getGeomInfo().getInstanceId())); ui->sceneGLView->setSelectedObject(const_cast(selectedSceneObject)); @@ -350,6 +353,7 @@ void BMEditMainWindow::onDeselectedSceneObject() ui->sceneObjectTypeCombo->setEnabled(false); ui->sceneObjectName->clear(); + ui->geomInstanceId->setText("0"); ui->geomControllers->resetGeom(); m_sceneObjectPropertiesModel->resetGeom(); diff --git a/BMEdit/Editor/UI/UI/BMEditMainWindow.ui b/BMEdit/Editor/UI/UI/BMEditMainWindow.ui index 33d798d..a7d0224 100644 --- a/BMEdit/Editor/UI/UI/BMEditMainWindow.ui +++ b/BMEdit/Editor/UI/UI/BMEditMainWindow.ui @@ -229,7 +229,7 @@ Properties - + @@ -269,6 +269,27 @@ + + + + + + Instance ID: + + + + + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + +