Compare commits

...

2 Commits

Author SHA1 Message Date
9bb9e2c09b Generating path from shore to pier 2025-12-15 01:41:44 +03:00
3f99099919 Creating pier 2025-12-14 06:59:12 +03:00
13 changed files with 1720 additions and 329 deletions

View File

@@ -76,6 +76,7 @@ add_subdirectory(src/world)
add_subdirectory(src/tests)
add_subdirectory(src/physics)
add_subdirectory(src/editor)
add_subdirectory(assets/blender/buildings/parts)
add_executable(Game Game.cpp ${WATER_SRC})
target_include_directories(Game PRIVATE src/gamedata)

View File

@@ -0,0 +1,17 @@
project(building-parts)
set(PARTS_FILES pier.blend)
set(PARTS_OUTPUT_DIRS)
foreach(PARTS_FILE ${PARTS_FILES})
get_filename_component(FILE_NAME ${PARTS_FILE} NAME_WE)
set(PARTS_OUTPUT_DIR ${CMAKE_BINARY_DIR}/resources/buildings/parts/${FILE_NAME})
add_custom_command(
OUTPUT ${PARTS_OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${PARTS_OUTPUT_DIR}
COMMAND ${BLENDER} ${CMAKE_CURRENT_SOURCE_DIR}/${PARTS_FILE}
-b -Y -P
${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_building_parts.py
-- ${PARTS_OUTPUT_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${PARTS_FILE} ${CMAKE_SOURCE_DIR}/assets/blender/scripts/export_building_parts.py)
list(APPEND PARTS_OUTPUT_DIRS ${PARTS_OUTPUT_DIR})
endforeach()
add_custom_target(import_building_parts ALL DEPENDS ${PARTS_OUTPUT_DIRS})

Binary file not shown.

View File

@@ -20,6 +20,7 @@ FileSystem=resources/terrain
[General]
FileSystem=skybox
FileSystem=resources/buildings
FileSystem=resources/buildings/parts/pier
FileSystem=resources/vehicles
FileSystem=resources/debug
FileSystem=resources/fonts

View File

@@ -9,7 +9,7 @@ find_package(OgreProcedural REQUIRED CONFIG)
find_package(pugixml REQUIRED CONFIG)
find_package(flecs REQUIRED CONFIG)
set(COPY_DIRECTORIES resources skybox water)
set(COPY_DIRECTORIES resources skybox water resources/buildings/parts)
set(INSTALL_DEPS ${CMAKE_CURRENT_BINARY_DIR}/resources.cfg)
foreach(DIR_NAME ${COPY_DIRECTORIES})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME}
@@ -19,7 +19,7 @@ foreach(DIR_NAME ${COPY_DIRECTORIES})
list(APPEND INSTALL_DEPS ${CMAKE_CURRENT_BINARY_DIR}/${DIR_NAME})
endforeach()
add_custom_target(install_resources DEPENDS ${INSTALL_DEPS})
add_custom_target(install_resources DEPENDS import_buildings import_building_parts ${INSTALL_DEPS})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/resources.cfg
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../../resources.cfg ${CMAKE_CURRENT_BINARY_DIR}/resources.cfg
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../../resources.cfg

View File

@@ -3,17 +3,18 @@ set(CMAKE_CXX_STANDARD 17)
find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG)
find_package(Bullet REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(OgreProcedural REQUIRED CONFIG)
add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp
GUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp
CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp
VehicleManagerModule.cpp AppModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp)
VehicleManagerModule.cpp AppModule.cpp StaticGeometryModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp)
target_link_libraries(GameData PUBLIC
lua
flecs::flecs_static
nlohmann_json::nlohmann_json
OgreMain
OgreBites
OgrePaging OgreTerrain OgreOverlay
OgrePaging OgreTerrain OgreOverlay OgreProcedural::OgreProcedural
PRIVATE sceneloader world-build physics editor)
target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${BULLET_INCLUDE_DIR} ../luaaa)
target_compile_definitions(GameData PRIVATE FLECS_CPP_NO_AUTO_REGISTRATION)

View File

@@ -9,11 +9,16 @@
#include <OgreImGuiInputListener.h>
#include <OgreFontManager.h>
#include <OgreTerrainGroup.h>
#include <OgrePagedWorld.h>
#include <OgreTerrainPaging.h>
#include <OgreTerrainPagedWorldSection.h>
#include <nlohmann/json.hpp>
#include "GameData.h"
#include "Components.h"
#include "LuaData.h"
#include "AppModule.h"
#include "TerrainModule.h"
#include "StaticGeometryModule.h"
#include "EditorGizmoModule.h"
#include "GUIModule.h"
namespace ECS
@@ -701,6 +706,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
float strength = 0.0f;
int size = 0;
long slot_x, slot_y;
float cursorAngle = 0;
void updateWorldTexture()
{
// Get the hardware pixel buffer
@@ -733,21 +739,16 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
ECS::get<Terrain>()
.mTerrainGroup->convertWorldPositionToTerrainSlot(
worldPos, &x, &y);
int i, j;
for (j = -1; j < 2; j++)
for (i = -1; i < 2; i++) {
Ogre::Terrain *terrain =
ECS::get<Terrain>()
.mTerrainGroup->getTerrain(
x + j, y + i);
if (terrain && terrain->isLoaded()) {
terrain->dirty();
terrain->update(true);
terrain->waitForDerivedProcesses();
}
}
ECS::get<Terrain>().mTerrainGroup->update(true);
for (auto &slot :
ECS::get<Terrain>().mTerrainGroup->getTerrainSlots()) {
Ogre::uint32 page =
ECS::get<Terrain>().mTerrainGroup->packIndex(
slot.second->x, slot.second->y);
ECS::get<Terrain>()
.mTerrainPagedWorldSection->unloadPage(page,
false);
}
ECS::get<Terrain>().mTerrainGroup->update(false);
}
void setCursorPos(Ogre::Vector3 &cursorPosition,
Ogre::Quaternion &orientation)
@@ -793,8 +794,327 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
.mCameraGoal->_getDerivedOrientation());
updateHeightmap();
}
void setCursorSelectedPos(flecs::entity e, Ogre::Vector3 &position,
Ogre::Quaternion &orientation)
{
StaticGeometryModule::getItemPositionAndRotation(e, position,
orientation);
selected_x = TerrainModule::get_img_x(position.x);
selected_y = TerrainModule::get_img_y(position.z);
ECS::get<EditorGizmo>().sceneNode->_setDerivedPosition(
position);
ECS::get<EditorGizmo>().sceneNode->_setDerivedOrientation(
orientation);
}
void setCameraSelectedPos(flecs::entity e)
{
Ogre::Vector3 cursorPos;
Ogre::Quaternion cursorOrientation;
setCursorSelectedPos(e, cursorPos, cursorOrientation);
Ogre::Vector3 cameraPos =
ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
Ogre::Vector3 cameraOffset =
cursorOrientation * Ogre::Vector3::UNIT_Z * 30.0f;
cameraPos.x = cursorPos.x;
cameraPos.z = cursorPos.z;
cameraPos += cameraOffset;
cameraPos.y =
TerrainModule::get_height(
ECS::get<Terrain>().mTerrainGroup, cameraPos) +
10.0f;
if (cameraPos.y < 0.0f)
cameraPos.y = 10.0f;
ECS::get<Camera>().mCameraPivot->_setDerivedPosition(cameraPos);
ECS::get<Camera>().mCameraPivot->_setDerivedOrientation(
cursorOrientation);
cameraPos =
ECS::get<Camera>().mCameraGoal->_getDerivedPosition();
ECS::get<Camera>().mCameraNode->_setDerivedPosition(cameraPos);
ECS::get<Camera>().mCameraNode->_setDerivedOrientation(
ECS::get<Camera>()
.mCameraGoal->_getDerivedOrientation());
updateHeightmap();
}
void setSurfaceLevel(int actualSize, int center_x, int center_y,
float level)
{
int i, j;
float original = level;
if (actualSize == 1)
level += 0.4f;
else if (actualSize == 2)
level += 0.35f;
original = Ogre::Math::Clamp(original, 0.0f, 1.0f);
for (i = -actualSize; i < actualSize + 1; i++)
for (j = -actualSize; j < actualSize + 1; j++) {
if (i * i + j * j > actualSize * actualSize)
continue;
if (center_x + j < 0 ||
center_x + j >= worldMap->getWidth())
continue;
if (center_y + i < 0 ||
center_y + i >= worldMap->getHeight())
continue;
Ogre::ColourValue cv =
worldMapImage.getColourAt(
center_x + j, center_y + i, 0);
cv.r = original;
worldMapImage.setColourAt(cv, center_x + j,
center_y + i, 0);
}
updateWorldTexture();
updateHeightmap();
}
void setHarbourSurface()
{
int base_size = 3;
float base_height = 0.517f;
float base_step = 0.1f;
float deep = 0.25f;
float shallow = 0.35f;
float maxStep = 600.0f;
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
float baseOffset = 200.0f;
Ogre::Vector3 stepOffset =
baseRot * Ogre::Vector3::NEGATIVE_UNIT_Z * baseOffset;
std::vector<float> heights = { deep, shallow, base_height,
base_height + base_step,
base_height + base_step * 2.0f };
int step_count = 0;
for (float height : heights) {
float localStep = 0.0f;
Ogre::Vector3 currentPosition =
basePos + stepOffset * (float)step_count -
stepOffset * 0.5f;
float goTill = maxStep;
if (step_count < 2)
goTill += 420.0f;
while (localStep <
goTill - 150.0f * (float)step_count) {
localStep += baseOffset;
currentPosition += stepOffset;
int center_x = TerrainModule::get_img_x(
currentPosition.x);
int center_y = TerrainModule::get_img_y(
currentPosition.z);
int size = base_size + 10 - step_count * 2;
if (step_count < 2)
size = base_size + 14 - step_count * 2;
if (step_count == 0)
size += 1;
setSurfaceLevel(size, center_x, center_y,
height);
}
step_count++;
}
}
/* This is editor function */
static bool findPierOffset(float &offset)
{
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
float length = 0.0f;
while (length < 250.0f) {
Ogre::Vector3 currentPosition =
basePos + direction * length;
float height =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (height < -4.0f) {
offset = length;
break;
}
length += 2.0f;
}
return length < 250.0f;
}
static bool findPierOffsetAndLengthAndDepth(float &offset,
float &length, float &depth)
{
if (!findPierOffset(offset))
return false;
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
length = 0.0f;
depth = 4.0f;
while (length < 60.0f) {
Ogre::Vector3 currentPosition =
basePos + direction * (offset + length);
float height =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (depth < -height)
depth = -height;
if (height > -4.0f)
break;
length += 6.0f;
}
return true;
}
static void findPierHeight(float maxLength, float &height)
{
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
float length = 0.0f;
height = 0.0f;
while (length < 60.0f) {
Ogre::Vector3 currentPosition =
basePos + direction * (length);
float dheight =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
if (height < dheight)
height = dheight;
length += 1.0f;
}
}
static void findPierPath(std::vector<Ogre::Vector3> &path)
{
Ogre::Vector3 basePos =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion baseRot =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
Ogre::Vector3 direction = baseRot * Ogre::Vector3(0, 0, 1);
float length = 0.0f;
while (length < 260.0f) {
Ogre::Vector3 currentPosition =
basePos + direction * (length);
float dheight =
ECS::get<Terrain>()
.mTerrainGroup->getHeightAtWorldPosition(
currentPosition);
Ogre::Vector3 localOffset =
Ogre::Vector3(0, 0, 1) * length;
if (dheight < 0 && path.size() == 0)
return;
if (path.size() == 0) {
Ogre::Vector3 localFromWorld =
ECS::get<EditorGizmo>()
.sceneNode
->convertWorldToLocalPosition(
{ currentPosition.x,
dheight,
currentPosition.z });
path.push_back({ localOffset.x,
localFromWorld.y,
localOffset.z });
} else {
float height = path.back().y;
if (height - dheight > 0.2f)
dheight = height - 0.2f;
height = dheight;
if (height < 0) {
height = 0;
Ogre::Vector3 localFromWorld =
ECS::get<EditorGizmo>()
.sceneNode
->convertWorldToLocalPosition(
{ currentPosition
.x,
height,
currentPosition
.z });
path.push_back({ localOffset.x,
localFromWorld.y,
localOffset.z });
break;
} else {
Ogre::Vector3 localFromWorld =
ECS::get<EditorGizmo>()
.sceneNode
->convertWorldToLocalPosition(
{ currentPosition
.x,
height,
currentPosition
.z });
path.push_back({ localOffset.x,
localFromWorld.y,
localOffset.z });
}
}
length += 0.5f;
}
}
static void to_json(nlohmann::json &j, const Ogre::Vector3 &position)
{
j["x"] = position.x;
j["y"] = position.y;
j["z"] = position.z;
}
void createHarbourItem()
{
Ogre::Vector3 itemPosition =
ECS::get<EditorGizmo>().sceneNode->_getDerivedPosition();
Ogre::Quaternion itemOrientation =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
float pierLength, pierDepth;
float pierOffset;
float pierHeight;
if (!findPierOffsetAndLengthAndDepth(pierOffset, pierLength,
pierDepth))
return;
findPierHeight(pierOffset + pierLength, pierHeight);
std::vector<Ogre::Vector3> pierPath;
findPierPath(pierPath);
flecs::entity e = StaticGeometryModule::createItem(
itemPosition, itemOrientation, "harbour");
Ogre::String prop = StaticGeometryModule::getItemProperties(e);
nlohmann::json j = nlohmann::json::parse(prop);
j["pierOffset"] = pierOffset;
j["pierLength"] = pierLength;
j["pierDepth"] = pierDepth;
j["pierHeight"] = pierHeight;
nlohmann::json p = nlohmann::json::array();
for (const auto &pt : pierPath) {
nlohmann::json pj;
to_json(pj, pt);
p.push_back(pj);
}
j["pierPath"] = p;
StaticGeometryModule::setItemProperties(e, j.dump());
// setHarbourSurface();
StaticGeometryModule::saveItems();
// updateWorldTexture();
// updateHeightmap();
// TerrainModule::save_heightmap();
}
void createHarbourMenu()
{
if (ImGui::MenuItem("Create"))
createHarbourItem();
}
void worldMapView()
{
bool riseLower = false;
bool riseLower2 = false;
bool smooth = false;
bool setLevel = false;
float setLevelValue = 0.0f;
float riseLowerChange = 0.0f;
OgreAssert(TerrainModule::get_img_x(0) ==
worldMap->getWidth() / 2,
"get_img_x");
@@ -829,7 +1149,108 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
ImVec2(768, 768));
// ImGui::SetNextWindowScroll(
// ImVec2(worldMap->getWidth(), worldMap->getHeight()));
ImGui::Begin("WorldMap...");
ImGui::Begin("WorldMap...", nullptr, ImGuiWindowFlags_MenuBar);
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Create")) {
if (ImGui::BeginMenu("Harbour")) {
createHarbourMenu();
ImGui::EndMenu();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Heightmap")) {
if (ImGui::MenuItem("Update terrain"))
ECS::get<Terrain>()
.mTerrainGroup->update(false);
ImGui::Separator();
ImGui::SliderFloat("Strength...", &strength,
0.0f, 1.0f);
ImGui::SliderInt("Size", &size, 0, 32);
ImGui::Separator();
if (ImGui::Button("Elevate")) {
riseLower = true;
riseLowerChange = strength;
}
ImGui::SameLine();
if (ImGui::Button("Elevate2")) {
riseLower2 = true;
riseLowerChange = strength;
}
ImGui::SameLine();
if (ImGui::Button("Lower")) {
riseLower = true;
riseLowerChange = -strength;
}
if (ImGui::Button("Deepest")) {
setLevel = true;
setLevelValue = 0.0f;
}
ImGui::SameLine();
if (ImGui::Button("Deep")) {
setLevel = true;
setLevelValue = 0.25f;
}
ImGui::SameLine();
if (ImGui::Button("Shallow1")) {
setLevel = true;
setLevelValue = 0.35f;
}
ImGui::SameLine();
if (ImGui::Button("Shallow2")) {
setLevel = true;
setLevelValue = 0.47f;
}
if (ImGui::Button("Beach")) {
setLevel = true;
setLevelValue = 0.516f;
}
ImGui::SameLine();
if (ImGui::Button("Shore1")) {
setLevel = true;
setLevelValue = 0.536f;
}
ImGui::SameLine();
if (ImGui::Button("Shore2")) {
setLevel = true;
setLevelValue = 0.556f;
}
if (ImGui::Button("Shore3")) {
setLevel = true;
setLevelValue = 0.586f;
}
ImGui::SameLine();
if (ImGui::Button("Shore4")) {
setLevel = true;
setLevelValue = 0.606f;
}
ImGui::SameLine();
if (ImGui::Button("Shore5")) {
setLevel = true;
setLevelValue = 0.626f;
}
if (ImGui::Button("Shore6")) {
setLevel = true;
setLevelValue = 0.646f;
}
ImGui::SameLine();
if (ImGui::Button("Highest")) {
setLevel = true;
setLevelValue = 1.0f;
}
ImGui::SameLine();
if (ImGui::Button("Smooth")) {
smooth = true;
}
ImGui::Separator();
if (ImGui::MenuItem("Save heightmap")) {
updateWorldTexture();
updateHeightmap();
TerrainModule::save_heightmap();
}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
ImGui::Spacing();
ImGui::BeginChild("WorldMap...", ImVec2(480, 480),
ImGuiChildFlags_None,
@@ -885,20 +1306,29 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
1.0f, IM_COL32(0, 255, 0, 255));
{
std::list<Ogre::Vector3> positions;
TerrainModule::getItemPositions(&positions);
StaticGeometryModule::getItemPositions(&positions);
for (auto pos : positions) {
int item_x = TerrainModule::get_img_x(pos.x);
int item_y = TerrainModule::get_img_y(pos.z);
draw_list->AddCircleFilled(
ImVec2(top_x + item_x, top_y + item_y),
3.0f, IM_COL32(255, 255, 0, 255));
std::cout << pos << std::endl;
}
}
if (locationSelected)
draw_list->AddCircleFilled(
ImVec2(top_x + selected_x, top_y + selected_y),
4.0f, IM_COL32(64, 255, 64, 255));
{
Ogre::Vector3 cursorPos =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedPosition();
int cursor_x = TerrainModule::get_img_x(cursorPos.x);
int cursor_y = TerrainModule::get_img_y(cursorPos.z);
draw_list->AddCircleFilled(
ImVec2(top_x + cursor_x, top_y + cursor_y),
4.0f, IM_COL32(255, 64, 64, 128));
}
ImGui::PopStyleVar();
ImGui::Spacing();
ImGui::EndChild();
@@ -923,87 +1353,65 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
ImGui::Text("Cursor position %f %f %f", position.x,
position.y, position.z);
}
if (ImGui::Button("Update terrain")) {
ECS::get<Terrain>().mTerrainGroup->update(true);
}
ImGui::SliderFloat("Strength...", &strength, 0.0f, 0.2f);
ImGui::SliderInt("Size", &size, 0, 8);
bool riseLower = false;
bool riseLower2 = false;
bool smooth = false;
bool setLevel = false;
float setLevelValue = 0.0f;
float riseLowerChange = 0.0f;
if (ImGui::Button("Elevate")) {
riseLower = true;
riseLowerChange = strength;
}
ImGui::SameLine();
if (ImGui::Button("Lower")) {
riseLower = true;
riseLowerChange = -strength;
}
ImGui::SameLine();
if (ImGui::Button("Smooth")) {
smooth = true;
}
ImGui::SameLine();
if (ImGui::Button("Elevate2")) {
riseLower2 = true;
riseLowerChange = strength;
}
if (ImGui::Button("Deepest")) {
setLevel = true;
setLevelValue = 0.0f;
}
ImGui::SameLine();
if (ImGui::Button("Highest")) {
setLevel = true;
setLevelValue = 1.0f;
}
ImGui::SameLine();
if (ImGui::Button("Beach")) {
setLevel = true;
setLevelValue = 0.516f;
}
if (ImGui::Button("Shore1")) {
setLevel = true;
setLevelValue = 0.536f;
}
ImGui::SameLine();
if (ImGui::Button("Shore2")) {
setLevel = true;
setLevelValue = 0.556f;
}
ImGui::SameLine();
if (ImGui::Button("Shore3")) {
setLevel = true;
setLevelValue = 0.586f;
}
ImGui::SameLine();
if (ImGui::Button("Shore4")) {
setLevel = true;
setLevelValue = 0.606f;
}
if (ImGui::Button("Shore5")) {
setLevel = true;
setLevelValue = 0.626f;
}
ImGui::SameLine();
if (ImGui::Button("Shore6")) {
setLevel = true;
setLevelValue = 0.646f;
}
if (ImGui::Button("Harbour")) {
Ogre::Vector3 itemPosition =
if (ImGui::Button("Update cursor position")) {
Ogre::Vector3 position =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedPosition();
Ogre::Quaternion itemOrientation =
ECS::get<EditorGizmo>()
.sceneNode->_getDerivedOrientation();
TerrainModule::createItem(itemPosition, itemOrientation,
"harbour");
TerrainModule::saveItems();
position.y =
ECS::get<Terrain>()
.mTerrainGroup
->getHeightAtWorldPosition(position);
ECS::get<EditorGizmo>().sceneNode->_setDerivedPosition(
position);
}
ImGui::SliderFloat("Cursor Angle...", &cursorAngle, -180.0f,
180.0f);
ECS::get<EditorGizmo>().sceneNode->_setDerivedOrientation(
Ogre::Quaternion(Ogre::Degree(cursorAngle),
Ogre::Vector3::UNIT_Y));
flecs::entity selected_item;
bool item_is_selected = false;
{
std::list<std::pair<flecs::entity, Ogre::String> > items;
StaticGeometryModule::getItemsProperties(&items);
for (const auto &item : items) {
Ogre::String label =
Ogre::StringConverter::toString(
item.first.id());
label += item.second.substr(0, 32);
if (ImGui::SmallButton(
label.c_str())) { /* select */
selected_item = item.first;
item_is_selected = true;
setCameraSelectedPos(selected_item);
}
ImGui::SameLine();
Ogre::String upd_label =
"Update Height##" +
Ogre::StringConverter::toString(
item.first.id());
if (ImGui::SmallButton(upd_label.c_str())) {
TerrainItem &uitem =
item.first
.get_mut<TerrainItem>();
uitem.position.y =
ECS::get<Terrain>()
.mTerrainGroup
->getHeightAtWorldPosition(
uitem.position);
StaticGeometryModule::saveItems();
}
ImGui::SameLine();
Ogre::String del_label =
"delete##" +
Ogre::StringConverter::toString(
item.first.id());
if (ImGui::SmallButton(del_label.c_str())) {
item.first.destruct();
StaticGeometryModule::saveItems();
}
ImGui::Spacing();
}
}
if (riseLower) {
int actualSize = 1 + size * 2;
@@ -1058,12 +1466,6 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
float actualStrength =
riseLowerChange /
(1.0f + (float)(i * i + j * j));
if (i * i + j * j ==
actualSize * actualSize) {
std::cout << actualStrength
<< std::endl;
// OgreAssert(false, "strength");
}
Ogre::ColourValue cv =
worldMapImage.getColourAt(
selected_x + j,
@@ -1167,11 +1569,6 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
updateWorldTexture();
updateHeightmap();
}
if (ImGui::Button("Save heightmap")) {
updateWorldTexture();
updateHeightmap();
TerrainModule::save_heightmap();
}
ImGui::EndChild();
ImGui::Spacing();
ImGui::End();
@@ -1597,6 +1994,7 @@ EditorGUIModule::EditorGUIModule(flecs::world &ecs)
{
ecs.module<EditorGUIModule>();
ecs.import <AppModule>();
ecs.import <StaticGeometryModule>();
ecs.component<GUI>()
.on_add([](GUI &gui) {
gui.enabled = true;

View File

@@ -99,6 +99,7 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
nullptr,
nullptr,
nullptr,
nullptr,
false,
{ 0, 0, 0 } });
if (!ecs.has<LuaBase>())
@@ -175,6 +176,7 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
nullptr,
nullptr,
nullptr,
nullptr,
false,
{ 0, 0, 0 } });
ecs.set<GUI>({ true, true, true, false, false, "", {}, -1 });

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
#ifndef _STATIC_GEOMETRY_MODULE_H_
#define _STATIC_GEOMETRY_MODULE_H_
#include <flecs.h>
#include <Ogre.h>
namespace ECS
{
struct TerrainSlotParent {
std::pair<long, long> slot;
};
struct TerrainItem {
Ogre::Vector3 position;
Ogre::Quaternion orientation;
Ogre::String properties;
};
struct TerrainItemNode {
Ogre::SceneNode *itemNode;
};
struct StaticGeometryModule {
StaticGeometryModule(flecs::world &ecs);
static void addGeometryForSlot(long x, long y);
static void removeGeometryForSlot(long x, long y);
static flecs::entity createItem(const Ogre::Vector3 &position,
const Ogre::Quaternion &orientation,
const Ogre::String &type);
static void setItemProperties(flecs::entity id,
Ogre::String properties);
static const Ogre::String &getItemProperties(flecs::entity id);
static void saveItems();
static void loadItems();
static void getItemPositionPerSlot(long x, long y,
std::list<Ogre::Vector3> *positions);
static void getItemPositions(std::list<Ogre::Vector3> *positions);
static void getItemPositionAndRotation(flecs::entity e,
Ogre::Vector3 &position,
Ogre::Quaternion &orientation);
static void getItemsProperties(
std::list<std::pair<flecs::entity, Ogre::String> > *items);
static void createItemGeometry(flecs::entity e);
static void createBridge(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
static void createPier(flecs::entity e, Ogre::SceneNode *sceneNode,
Ogre::StaticGeometry *geo);
static void createHarbour(flecs::entity e, Ogre::SceneNode *sceneNode);
};
}
#endif

View File

@@ -16,10 +16,11 @@
#include "CharacterModule.h"
#include "SunModule.h"
#include "PhysicsModule.h"
#include "StaticGeometryModule.h"
#include "TerrainModule.h"
#define TERRAIN_SIZE 129
#define TERRAIN_WORLD_SIZE 1000.0f
#define TERRAIN_SIZE 65
#define TERRAIN_WORLD_SIZE 500.0f
#define ENDLESS_TERRAIN_FILE_PREFIX Ogre::String("EndlessWorldTerrain")
#define ENDLESS_TERRAIN_FILE_SUFFIX Ogre::String("dat")
@@ -32,6 +33,12 @@
#define ENDLESS_PAGE_MAX_Y 0x7FFF
namespace ECS
{
class DummyPageProvider;
/* Components */
struct TerrainPrivate {
DummyPageProvider *mDummyPageProvider;
Ogre::Timer mSunUpdate;
};
#define BRUSH_SIZE 64
struct HeightData {
@@ -83,15 +90,17 @@ struct HeightData {
}
int get_img_x(float world_x)
{
float world_img_x = world_x + img.getWidth() * BRUSH_SIZE / 2;
int ret = world_img_x / BRUSH_SIZE;
float world_img_x = world_x + (float)img.getWidth() *
(float)BRUSH_SIZE / 2.0f;
int ret = (world_img_x + BRUSH_SIZE - 1) / BRUSH_SIZE;
// ret = Ogre::Math::Clamp(ret, 0, (int)img.getWidth() - 1);
return ret;
}
int get_img_y(float world_z)
{
float world_img_y = world_z + img.getHeight() * BRUSH_SIZE / 2;
int ret = world_img_y / BRUSH_SIZE;
float world_img_y = world_z + (float)img.getHeight() *
(float)BRUSH_SIZE / 2.0f;
int ret = (world_img_y + BRUSH_SIZE - 1) / BRUSH_SIZE;
// ret = Ogre::Math::Clamp(ret, 0, (int)img.getHeight() - 1);
return ret;
}
@@ -234,6 +243,7 @@ class FlatTerrainDefiner
long y;
};
std::deque<struct gen_collider> collider_queue;
std::deque<struct gen_collider> colliderRemove_queue;
public:
FlatTerrainDefiner(Ogre::SceneManager *
@@ -247,10 +257,13 @@ public:
}
private:
std::mutex mtx;
public:
void createTerrainChunk(Ogre::TerrainGroup *terrainGroup, long x,
long y)
{
std::lock_guard<std::mutex> guard(mtx);
Ogre::Terrain *terrain = terrainGroup->getTerrain(x, y);
float minH = terrain->getMinHeight();
float maxH = terrain->getMaxHeight();
@@ -276,6 +289,7 @@ public:
}
void define(Ogre::TerrainGroup *terrainGroup, long x, long y) override
{
std::lock_guard<std::mutex> guard(mtx);
uint16_t terrainSize = terrainGroup->getTerrainSize();
float *heightMap = OGRE_ALLOC_T(float, terrainSize *terrainSize,
MEMCATEGORY_GEOMETRY);
@@ -295,19 +309,9 @@ public:
long world_y = (long)(worldPos.z + i -
(terrainSize - 1) / 2);
float height = 0.0f;
int k, l;
for (l = -1; l < 2; l++)
for (k = -1; k < 2; k++) {
height +=
HeightData::get_singleton()
->get_height(
terrainGroup,
world_x +
4 * k,
world_y +
4 * l);
}
height /= 9.0f;
height +=
HeightData::get_singleton()->get_height(
terrainGroup, world_x, world_y);
// height = -2.0f;
heightMap[i * terrainSize + j] = height;
@@ -421,6 +425,9 @@ public:
what->setOrientation(item.rotation);
what->setPosition(item.position);
}
/* Spawn items */
StaticGeometryModule::addGeometryForSlot(x, y);
} else {
output.push_back(collider_queue.front());
collider_queue.pop_front();
@@ -453,6 +460,10 @@ public:
bool unloadProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section)
{
long x, y;
ECS::get<Terrain>().mTerrainGroup->unpackIndex(page->CHUNK_ID,
&x, &y);
StaticGeometryModule::removeGeometryForSlot(x, y);
return true;
}
bool unprepareProceduralPage(Ogre::Page *page,
@@ -461,20 +472,6 @@ public:
return true;
}
};
struct TerrainPrivate {
DummyPageProvider *mDummyPageProvider;
Ogre::Timer mSunUpdate;
};
struct TerrainSlotParent {
std::pair<long, long> slot;
};
struct TerrainItem {
Ogre::Vector3 position;
Ogre::Quaternion orientation;
Ogre::String properties;
};
TerrainModule::TerrainModule(flecs::world &ecs)
{
struct CanSetPlayerPosition {};
@@ -482,12 +479,11 @@ TerrainModule::TerrainModule(flecs::world &ecs)
ecs.component<CanSetPlayerPosition>().add(flecs::Singleton);
ecs.component<Terrain>().add(flecs::Singleton);
ecs.component<TerrainPrivate>().add(flecs::Singleton);
ecs.component<TerrainSlotParent>();
ecs.component<TerrainItem>();
ecs.component<PlacementObjects>();
ecs.component<TerrainReady>().add(flecs::Singleton);
ecs.import <CharacterModule>();
ecs.import <SunModule>();
ecs.import <StaticGeometryModule>();
ecs.set<TerrainPrivate>({ nullptr, {} });
ecs.system<const EngineData, const Camera, const Sun, Terrain,
TerrainPrivate>("SetupUpdateTerrain")
@@ -523,11 +519,11 @@ TerrainModule::TerrainModule(flecs::world &ecs)
terrain.mTerrainGroup->setOrigin(
terrain.mTerrainPos);
// Configure global
terrain.mTerrainGlobals->setMaxPixelError(0);
terrain.mTerrainGlobals->setMaxPixelError(1);
// testing composite map
// mTerrainGlobals->setCompositeMapDistance(30);
terrain.mTerrainGlobals->setCompositeMapDistance(
500);
300);
//mTerrainGlobals->setUseRayBoxDistanceCalculation(true);
terrain.mTerrainGlobals
->getDefaultMaterialGenerator()
@@ -547,7 +543,8 @@ TerrainModule::TerrainModule(flecs::world &ecs)
defaultimp.terrainSize = TERRAIN_SIZE;
defaultimp.worldSize = TERRAIN_WORLD_SIZE;
defaultimp.inputScale = 1.0f;
defaultimp.minBatchSize = 33;
// defaultimp.minBatchSize = 33;
defaultimp.minBatchSize = 5;
defaultimp.maxBatchSize = 65;
Ogre::Image combined;
combined.loadTwoImagesAsRGBA(
@@ -575,24 +572,33 @@ TerrainModule::TerrainModule(flecs::world &ecs)
terrain.mPageManager);
terrain.mPagedWorld =
terrain.mPageManager->createWorld();
#if 0
terrain.mTerrainGroup->setAutoUpdateLod(
Ogre::TerrainAutoUpdateLodFactory::
getAutoUpdateLod(
Ogre::BY_DISTANCE));
#endif
terrain.mTerrainPagedWorldSection =
terrain.mTerrainPaging
->createWorldSection(
terrain.mPagedWorld,
terrain.mTerrainGroup,
300, 800,
300, 500,
ENDLESS_PAGE_MIN_X,
ENDLESS_PAGE_MIN_Y,
ENDLESS_PAGE_MAX_X,
ENDLESS_PAGE_MAX_Y);
terrain.definer = OGRE_NEW FlatTerrainDefiner(
eng.mScnMgr /*, eng.mWorld */);
terrain.mTerrainPagedWorldSection->setDefiner(
OGRE_NEW FlatTerrainDefiner(
eng.mScnMgr /*, eng.mWorld */));
terrain.definer);
terrain.mTerrainGroup->freeTemporaryResources();
std::cout << "Terrain setup done\n";
ECS::get().set<PlacementObjects>({});
terrain.mTerrainGroup->loadAllTerrains(true);
}
if (sun.mSun &&
priv.mSunUpdate.getMilliseconds() > 1000) {
@@ -607,6 +613,7 @@ TerrainModule::TerrainModule(flecs::world &ecs)
.getPitch()
<< "\n";
priv.mSunUpdate.reset();
//terrain.mTerrainGroup->autoUpdateLodAll()
}
});
ecs.system<const ECS::Camera, const Terrain>("UpdateTerrainStatus")
@@ -738,11 +745,13 @@ TerrainModule::TerrainModule(flecs::world &ecs)
player.modified<CharacterLocation>();
ECS::get().remove<CanSetPlayerPosition>();
});
ecs.observer<const Terrain>("LoadTerrainItems")
.event(flecs::OnSet)
ecs.system<const Terrain>("UpdateTerrainGroup")
.kind(flecs::OnUpdate)
.interval(2.0f)
.each([](const Terrain &terrain) {
if (terrain.mTerrainGroup)
loadItems();
if (!terrain.mTerrainGroup
->isDerivedDataUpdateInProgress())
terrain.mTerrainGroup->update(false);
});
}
float TerrainModule::get_height(Ogre::TerrainGroup *group,
@@ -783,167 +792,9 @@ void TerrainModule::save_heightmap()
{
HeightData::get_singleton()->save_heightmap();
}
flecs::entity TerrainModule::createItem(const Ogre::Vector3 &position,
const Ogre::Quaternion &orientation,
const Ogre::String &type)
void TerrainModule::defineTerrain(long x, long y)
{
long x, y;
ECS::get<Terrain>().mTerrainGroup->convertWorldPositionToTerrainSlot(
position, &x, &y);
std::pair<long, long> pos{ x, y };
flecs::entity slot =
ECS::get().query_builder<const TerrainSlotParent>().build().find(
[&](const TerrainSlotParent &slot) -> bool {
return slot.slot == pos;
});
if (!slot.is_valid())
slot = ECS::get().entity().add<TerrainSlotParent>();
flecs::entity item = ECS::get().entity().child_of(slot);
nlohmann::json jproperties;
jproperties["type"] = type;
item.set<TerrainItem>({ position, orientation, jproperties.dump() });
return item;
}
void TerrainModule::setItemProperties(flecs::entity id, Ogre::String properties)
{
OgreAssert(id.is_valid(), "bad id");
id.get_mut<TerrainItem>().properties = properties;
id.modified<TerrainItem>();
}
const Ogre::String &TerrainModule::getItemProperties(flecs::entity id)
{
OgreAssert(id.is_valid(), "bad id");
return id.get<TerrainItem>().properties;
}
static void to_json(nlohmann::json &j, const Ogre::Vector3 &position)
{
j["x"] = position.x;
j["y"] = position.y;
j["z"] = position.z;
}
static void to_json(nlohmann::json &j, const Ogre::Quaternion &orientation)
{
j["w"] = orientation.w;
j["x"] = orientation.x;
j["y"] = orientation.y;
j["z"] = orientation.z;
}
static void from_json(const nlohmann::json &j, Ogre::Vector3 &position)
{
position.x = j["x"].get<float>();
position.y = j["y"].get<float>();
position.z = j["z"].get<float>();
}
static void from_json(const nlohmann::json &j, Ogre::Quaternion &orientation)
{
orientation.w = j["w"].get<float>();
orientation.x = j["x"].get<float>();
orientation.y = j["y"].get<float>();
orientation.z = j["z"].get<float>();
}
void TerrainModule::saveItems()
{
Ogre::String path = "resources/buildings/items.list";
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
"items.list")) {
Ogre::String group =
Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("items.list");
Ogre::FileInfoListPtr fileInfoList(
Ogre::ResourceGroupManager::getSingleton()
.findResourceFileInfo(group, "items.list"));
OgreAssert(fileInfoList->size() == 1,
"worpd_map.png should be there and only once");
path = fileInfoList->at(0).archive->getName() + "/" +
"items.list";
Ogre::FileSystemLayer::removeFile(path);
}
std::fstream fout(path.c_str(), std::ios::out);
nlohmann::json jitemlist;
ECS::get().query_builder<const TerrainItem>().build().each(
[&](flecs::entity e, const TerrainItem &item) {
nlohmann::json jitem;
to_json(jitem["position"], item.position);
to_json(jitem["orientation"], item.orientation);
to_json(jitem["properties"], item.properties);
jitemlist.push_back(jitem);
});
fout << jitemlist.dump();
fout.close();
}
void TerrainModule::loadItems()
{
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(
"items.list"))
return;
Ogre::String group = Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("items.list");
Ogre::DataStreamPtr stream =
Ogre::ResourceGroupManager::getSingleton().openResource(
"items.list", group);
Ogre::String json = stream->getAsString();
nlohmann::json jlist = nlohmann::json::parse(json);
ECS::get().delete_with<TerrainItem>();
ECS::get().delete_with<TerrainSlotParent>();
for (const auto &v : jlist) {
Ogre::Vector3 position;
Ogre::Quaternion orientation;
Ogre::String properties;
from_json(v["position"], position);
from_json(v["orientation"], orientation);
properties = v["properties"].get<Ogre::String>();
long x, y;
ECS::get<Terrain>()
.mTerrainGroup->convertWorldPositionToTerrainSlot(
position, &x, &y);
std::pair<long, long> pos{ x, y };
flecs::entity slot =
ECS::get()
.query_builder<const TerrainSlotParent>()
.build()
.find([&](const TerrainSlotParent &slot)
-> bool {
return slot.slot == pos;
});
if (!slot.is_valid())
slot = ECS::get().entity().add<TerrainSlotParent>();
flecs::entity item = ECS::get().entity().child_of(slot);
item.set<TerrainItem>({ position, orientation, properties });
std::cout << "position: " << item.id() << " " << position
<< std::endl;
}
}
void TerrainModule::getItemPositionPerSlot(long x, long y,
std::list<Ogre::Vector3> *positions)
{
std::pair<long, long> pos{ x, y };
if (!positions)
return;
flecs::entity slot =
ECS::get().query_builder<const TerrainSlotParent>().build().find(
[&](const TerrainSlotParent &slot) -> bool {
return slot.slot == pos;
});
if (!slot.is_valid())
return;
ECS::get()
.query_builder<const TerrainItem>()
.with(flecs::ChildOf, slot)
.build()
.each([&](flecs::entity e, const TerrainItem &item) {
positions->push_back(item.position);
std::cout << e.id() << " " << item.position
<< std::endl;
});
}
void TerrainModule::getItemPositions(std::list<Ogre::Vector3> *positions)
{
ECS::get().query_builder<const TerrainItem>().build().each(
[&](flecs::entity e, const TerrainItem &item) {
positions->push_back(item.position);
std::cout << e.id() << " " << item.position
<< std::endl;
});
ECS::get<Terrain>().definer->define(ECS::get<Terrain>().mTerrainGroup,
x, y);
}
}

View File

@@ -12,12 +12,14 @@ class TerrainPagedWorldSection;
}
namespace ECS
{
class FlatTerrainDefiner;
struct Terrain {
Ogre::TerrainGlobalOptions *mTerrainGlobals;
Ogre::TerrainGroup *mTerrainGroup;
Ogre::TerrainPaging *mTerrainPaging;
Ogre::PageManager *mPageManager;
Ogre::PagedWorld *mPagedWorld;
FlatTerrainDefiner *definer;
Ogre::TerrainPagedWorldSection *mTerrainPagedWorldSection;
bool mTerrainReady;
@@ -41,17 +43,7 @@ struct TerrainModule {
static int get_img_y(float world_z);
static void update_heightmap(const Ogre::Image &heightmap);
static void save_heightmap();
static flecs::entity createItem(const Ogre::Vector3 &position,
const Ogre::Quaternion &orientation,
const Ogre::String &type);
static void setItemProperties(flecs::entity id,
Ogre::String properties);
static const Ogre::String &getItemProperties(flecs::entity id);
static void saveItems();
static void loadItems();
static void getItemPositionPerSlot(long x, long y,
std::list<Ogre::Vector3> *positions);
static void getItemPositions(std::list<Ogre::Vector3> *positions);
static void defineTerrain(long x, long y);
};
struct TerrainReady {};
}

View File

@@ -852,6 +852,8 @@ public:
JPH::BodyInterface &body_interface =
physics_system.GetBodyInterface();
JPH::Body *body = body_interface.CreateBody(settings);
if (!body)
return JPH::BodyID();
return body->GetID();
}
void removeBody(const JPH::BodyID &id)