Heightmap editor + saving

This commit is contained in:
2025-12-07 01:31:25 +03:00
parent e0db570581
commit 44896ed0d9
13 changed files with 1901 additions and 172 deletions

View File

@@ -41,6 +41,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
ecs.system<Input, Camera>("HandleInput")
.kind(flecs::OnUpdate)
.each([this](Input &input, Camera &camera) {
if (!ECS::player.is_valid())
return;
/* handle input */
// if (input.control == input.control_prev)
// return;

View File

@@ -8,10 +8,12 @@
#include <OgreApplicationContext.h>
#include <OgreImGuiInputListener.h>
#include <OgreFontManager.h>
#include <OgreTerrainGroup.h>
#include "GameData.h"
#include "Components.h"
#include "LuaData.h"
#include "AppModule.h"
#include "TerrainModule.h"
#include "GUIModule.h"
namespace ECS
{
@@ -472,6 +474,9 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
bool enableMapEditor;
ImFont *smallFont, *midFont, *bigFont;
Ogre::FontPtr _smallFont, _midFont, _bigFont;
Ogre::TexturePtr worldMap;
Ogre::Image worldMapImage;
EditorGUIListener(Ogre::ImGuiOverlay *overlay)
: Ogre::RenderTargetListener()
{
@@ -488,13 +493,47 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
OgreAssert(midFont, "Could not load font");
bigFont = overlay->addFont("bigFont", "General");
OgreAssert(bigFont, "Could not load font");
worldMapImage.load(
"world_map.png",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
#if 0
Ogre::FontPtr _midFont = createFont("midFont", "General",
"Kenney Bold.ttf", 28.0f);
#endif
#if 0
ImGui::GetIO().Fonts->Build();
int x, y, i, j;
for (y = 0; y < worldMapImage.getWidth(); y++)
for (x = 0; x < worldMapImage.getWidth(); x++) {
float r = 0.0f;
for (i = -2; i < 3; i++)
for (j = -2; j < 3; j++) {
int xj = Ogre::Math::Clamp(
x + j, 0,
(int)worldMapImage
.getWidth() -
1);
int yi = Ogre::Math::Clamp(
y + i, 0,
(int)worldMapImage
.getHeight() -
1);
r += worldMapImage
.getColourAt(xj,
yi, 0)
.r;
}
r /= 25.0f;
Ogre::ColourValue cv =
worldMapImage.getColourAt(x, y, 0);
cv.r = r;
worldMapImage.setColourAt(cv, x, y, 0);
}
#endif
worldMap = Ogre::TextureManager::getSingleton().createManual(
"worldMap",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D, worldMapImage.getWidth(),
worldMapImage.getHeight(),
worldMapImage.getNumMipmaps(),
worldMapImage.getFormat(), Ogre::TU_DYNAMIC_WRITE_ONLY);
worldMap->loadImage(worldMapImage);
OgreAssert(worldMap, "could not load world map");
}
Ogre::FontPtr createFont(const Ogre::String &name,
const Ogre::String &group,
@@ -533,6 +572,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
Ogre::Root::getSingleton().queueEndRendering();
if (ImGui::Button("Return"))
ECS::get().get<GUI>().finish();
#if 0
if (ImGui::Button("Enable/Disable item editor")) {
enableEditor ^= true;
if (enableEditor)
@@ -544,6 +584,8 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
enableEditor = false;
}
ImGui::Text("Text message...");
#endif
ImGui::Checkbox("Enable Map", &enableMapEditor);
ImGui::End();
}
void create_entity_node(const Ogre::String &name, int key)
@@ -573,6 +615,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
ECS::get().get<GUI>().finish();
}
#if 0
void buildings_editor()
{
int i;
@@ -602,6 +645,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
}
ImGui::End();
}
#endif
void position_editor(Ogre::SceneNode *node)
{
Ogre::Vector3 position = node->getPosition();
@@ -642,124 +686,561 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
ImGui::Text("Name: %s", pname.c_str());
}
}
#if 0
void map_editor()
{
}
void preview(const Ogre::RenderTargetViewportEvent &evt)
#endif
int pos_x = 0;
int pos_y = 0;
int top_x = 0;
int top_y = 0;
int selected_x = 0;
int selected_y = 0;
bool locationSelected = false;
float strength = 0.0f;
int size = 0;
void updateWorldTexture()
{
int i;
Ogre::ImGuiOverlay::NewFrame();
std::cout << "GUI enabled: " << ECS::get().get<GUI>().enabled
<< std::endl;
if (ECS::get().get<GUI>().enabled) {
buttons_panel();
buildings_editor();
map_editor();
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5f - 20;
ImGui::SetNextWindowPos(ImVec2(size.x - window_width,
size.y * 0.5f + 20),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width,
window_height),
ImGuiCond_Always);
// ImGui::Begin("Dumb and Stupid", &mKbd.gui_active);
ImGui::Begin("Panel...");
std::deque<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(
ECS::get()
.get<EngineData>()
.mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> visited;
while (true) {
int new_nodes_count = 0;
while (!tree_input_queue.empty()) {
int child;
Ogre::SceneNode *item =
tree_input_queue.front();
tree_input_queue.pop_front();
if (item &&
visited.find(item) ==
visited.end()) { // new node
new_nodes_count++;
tree_output_queue.push_back(
item);
visited.insert(item);
const Ogre::Node::ChildNodeMap
&children =
item->getChildren();
for (child = 0;
child < children.size();
child++) {
tree_output_queue.push_back(
static_cast<
Ogre::SceneNode
*>(
children[child]));
tree_output_queue
.push_back(
nullptr);
}
} else
tree_output_queue.push_back(
item);
}
if (new_nodes_count == 0)
break;
tree_input_queue = tree_output_queue;
tree_output_queue.clear();
}
tree_list.insert(tree_list.begin(),
tree_output_queue.begin(),
tree_output_queue.end());
int count = 0;
int depth = 0;
std::vector<int> check_depth;
int max_depth = 0;
check_depth.push_back(0);
for (count = 0; count < tree_list.size(); count++) {
int t;
// Get the hardware pixel buffer
Ogre::HardwarePixelBufferSharedPtr pixelBuffer =
worldMap->getBuffer();
Ogre::SceneNode *node = tree_list[count];
if (node && max_depth >= depth) {
Ogre::String name = node->getName();
if (name.length() == 0) {
name = "Node #" +
Ogre::StringConverter::
toString(count);
}
if (ImGui::TreeNode(name.c_str())) {
check_depth.push_back(
max_depth);
max_depth++;
ImGui::Text("%s",
(name + "##caption")
.c_str());
position_editor(node);
ImGui::Separator();
orientation_editor(node);
ImGui::Separator();
ImGui::Text("Attachments");
attachments_editor(node);
}
} else if (!node && max_depth >= depth) {
max_depth = check_depth.back();
check_depth.pop_back();
ImGui::TreePop();
// Lock the buffer for writing, discarding previous contents for performance
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
// Get information about the locked region (PixelBox)
const Ogre::PixelBox &pixelBox = pixelBuffer->getCurrentLock();
// Ensure the image format matches the texture format
OgreAssert(pixelBox.format == worldMapImage.getFormat(),
"bad format");
// Copy the image data to the pixel box's data pointer
memcpy(pixelBox.data, worldMapImage.getData(),
worldMapImage.getSize());
// Unlock the buffer to apply changes to the GPU
pixelBuffer->unlock();
}
void updateHeightmap()
{
Ogre::Vector3 worldPos =
ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
TerrainModule::update_heightmap(worldMapImage);
long x, y;
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->updateDerivedData(true);
terrain->updateGeometry();
}
if (tree_list[count])
depth++;
else
depth--;
}
ImGui::Spacing();
ImGui::End();
ECS::get<Terrain>().mTerrainGroup->updateDerivedData(true);
ECS::get<Terrain>().mTerrainGroup->updateGeometry();
ECS::get<Terrain>().mTerrainGroup->update(true);
}
void setCameraPos()
{
Ogre::Vector3 worldPos =
ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
worldPos.x = TerrainModule::get_world_x(selected_x);
worldPos.z = TerrainModule::get_world_y(selected_y);
Ogre::Vector3 cameraPos =
ECS::get<Camera>().mCameraPivot->_getDerivedPosition();
cameraPos.x = worldPos.x;
cameraPos.z = worldPos.z;
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);
cameraPos =
ECS::get<Camera>().mCameraGoal->_getDerivedPosition();
ECS::get<Camera>().mCameraNode->_setDerivedPosition(cameraPos);
std::cout << cameraPos << std::endl;
std::cout << worldPos << std::endl;
std::cout << selected_x << " " << selected_y << std::endl;
ECS::get<Terrain>().mTerrainGroup->updateDerivedData(true);
ECS::get<Terrain>().mTerrainGroup->updateGeometry();
ECS::get<Terrain>().mTerrainGroup->update(true);
}
void worldMapView()
{
OgreAssert(TerrainModule::get_img_x(0) ==
worldMap->getWidth() / 2,
"get_img_x");
OgreAssert(TerrainModule::get_img_y(0) ==
worldMap->getHeight() / 2,
"get_img_x");
OgreAssert(TerrainModule::get_world_x(worldMap->getWidth() /
2) == 0.0f,
"get_world_x");
OgreAssert(TerrainModule::get_world_y(worldMap->getHeight() /
2) == 0.0f,
"get_world_y");
if (ECS::get<Camera>().mCameraPivot) {
Ogre::Vector3 worldPos =
ECS::get<Camera>()
.mCameraPivot->_getDerivedPosition();
selected_x = TerrainModule::get_img_x(worldPos.x);
selected_y = TerrainModule::get_img_y(worldPos.z);
locationSelected = true;
std::cout << worldPos << std::endl;
std::cout << selected_x << " " << selected_y
<< std::endl;
OgreAssert(selected_x >= 0 &&
selected_x < worldMap->getWidth(),
"mix width");
OgreAssert(selected_y >= 0 &&
selected_y < worldMap->getHeight(),
"mix height");
}
ImGui::SetNextWindowSizeConstraints(ImVec2(512 + 20, 512 + 20),
ImVec2(768, 768));
// ImGui::SetNextWindowScroll(
// ImVec2(worldMap->getWidth(), worldMap->getHeight()));
ImGui::Begin("WorldMap...");
ImGui::Spacing();
ImGui::BeginChild("WorldMap...", ImVec2(480, 480),
ImGuiChildFlags_None,
ImGuiWindowFlags_HorizontalScrollbar);
ImGui::Spacing();
Ogre::ResourceHandle hdl = worldMap->getHandle();
int w = worldMap->getWidth();
int h = worldMap->getHeight();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
ImVec2((float)5, (float)5));
ImGui::ImageButton("WorldMapPress", (ImTextureID)hdl,
ImVec2(w, h));
ImVec2 mouse_absolute_pos = ImGui::GetMousePos();
ImVec2 item_absolute_pos = ImGui::GetItemRectMin();
top_x = item_absolute_pos.x + 5;
top_y = item_absolute_pos.y + 5;
bool hovered = false;
#if 0
pos_x = mouse_absolute_pos.x - item_absolute_pos.x - 5;
pos_y = mouse_absolute_pos.y - item_absolute_pos.y - 5;
#endif
if (ImGui::IsItemHovered()) {
ImVec2 mouse_absolute_pos = ImGui::GetMousePos();
ImVec2 item_absolute_pos = ImGui::GetItemRectMin();
pos_x = mouse_absolute_pos.x - item_absolute_pos.x - 5;
pos_y = mouse_absolute_pos.y - item_absolute_pos.y - 5;
hovered = true;
}
pos_x = Ogre::Math::Clamp(pos_x, 0,
(int)worldMap->getWidth() - 1);
pos_y = Ogre::Math::Clamp(pos_y, 0,
(int)worldMap->getHeight() - 1);
if (pos_x < 0)
pos_x = 0;
if (pos_x >= worldMap->getWidth())
pos_x = worldMap->getWidth() - 1;
if (pos_y < 0)
pos_y = 0;
if (pos_y >= worldMap->getHeight())
pos_y = worldMap->getHeight() - 1;
if (ImGui::IsItemActivated()) {
locationSelected = true;
selected_x = pos_x;
selected_y = pos_y;
OgreAssert(selected_x >= 0 &&
selected_x < worldMap->getWidth(),
"mix width");
OgreAssert(selected_y >= 0 &&
selected_y < worldMap->getHeight(),
"mix height");
setCameraPos();
std::cout << "worldClickPos: " << pos_x << " " << pos_y
<< std::endl;
}
ImDrawList *draw_list = ImGui::GetWindowDrawList();
draw_list->AddCircleFilled(ImVec2(top_x + pos_x, top_y + pos_y),
1.0f, IM_COL32(0, 255, 0, 255));
if (locationSelected)
draw_list->AddCircleFilled(
ImVec2(top_x + selected_x, top_y + selected_y),
4.0f, IM_COL32(64, 255, 64, 255));
ImGui::PopStyleVar();
ImGui::Spacing();
ImGui::EndChild();
ImGui::SameLine();
ImGui::BeginChild("WorldMap...", ImVec2(64, 480),
ImGuiChildFlags_None,
ImGuiWindowFlags_HorizontalScrollbar);
ImGui::EndChild();
ImGui::Spacing();
ImGui::BeginChild("WorldMap Bottom...", ImVec2(0, 0));
ImGui::Text("Position: %d %d", pos_x, pos_y);
ImGui::Text("Selected Position: %d %d", selected_x, selected_y);
ImGui::Text("Height: %f",
worldMapImage.getColourAt(pos_x, pos_y, 0).r);
ImGui::Text(
"Selected height: %f",
worldMapImage.getColourAt(selected_x, selected_y, 0).r);
if (ImGui::Button("Update terrain")) {
ECS::get<Terrain>().mTerrainGroup->update(true);
ECS::get<Terrain>().mTerrainGroup->updateDerivedData(
true);
ECS::get<Terrain>().mTerrainGroup->updateGeometry();
}
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 (riseLower) {
int actualSize = 1 + size * 2;
int i, j;
for (i = -actualSize; i < actualSize + 1; i++)
for (j = -actualSize; j < actualSize + 1; j++) {
if (i * i + j * j >
actualSize * actualSize)
continue;
if (selected_x + j < 0 ||
selected_x + j >=
worldMap->getWidth())
continue;
if (selected_y + i < 0 ||
selected_y + i >=
worldMap->getHeight())
continue;
Ogre::ColourValue cv =
worldMapImage.getColourAt(
selected_x + j,
selected_y + i, 0);
float original = cv.r;
original += riseLowerChange;
original = Ogre::Math::Clamp(
original, 0.0f, 1.0f);
cv.r = original;
worldMapImage.setColourAt(
cv, selected_x + j,
selected_y + i, 0);
}
updateWorldTexture();
updateHeightmap();
}
if (riseLower2) {
int actualSize = 1 + size * 2;
int i, j;
Ogre::ColourValue maxcv = worldMapImage.getColourAt(
selected_x, selected_y, 0);
for (i = -actualSize; i < actualSize + 1; i++)
for (j = -actualSize; j < actualSize + 1; j++) {
if (i * i + j * j >
actualSize * actualSize)
continue;
if (selected_x + j < 0 ||
selected_x + j >=
worldMap->getWidth())
continue;
if (selected_y + i < 0 ||
selected_y + i >=
worldMap->getHeight())
continue;
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,
selected_y + i, 0);
float original =
maxcv.r + actualStrength;
original = Ogre::Math::Clamp(
original, 0.0f, 1.0f);
if (cv.r >= original)
continue;
cv.r = original;
worldMapImage.setColourAt(
cv, selected_x + j,
selected_y + i, 0);
}
updateWorldTexture();
updateHeightmap();
}
if (smooth) {
int actualSize = 1 + size * 2;
int i, j, k, l;
for (i = -actualSize; i < actualSize + 1; i++)
for (j = -actualSize; j < actualSize + 1; j++) {
if (i * i + j * j >
actualSize * actualSize)
continue;
if (selected_x + j < 0 ||
selected_x + j >=
worldMap->getWidth())
continue;
if (selected_y + i < 0 ||
selected_y + i >=
worldMap->getHeight())
continue;
int kernel = 3;
float original = 0.0f;
Ogre::ColourValue cv;
float count = 0.0f;
for (k = -kernel; k < kernel + 1; k++) {
if (selected_y + i + k < 0 ||
selected_y + i + k >=
worldMap->getHeight())
continue;
for (l = -kernel;
l < kernel + 1; l++) {
if (selected_x + j + l <
0 ||
selected_x + j +
l >=
worldMap->getWidth())
continue;
cv = worldMapImage.getColourAt(
selected_x + j,
selected_y + i,
0);
original += cv.r;
count += 1.0f;
}
}
original /= count;
cv = worldMapImage.getColourAt(
selected_x + j, selected_y + i,
0);
original = Ogre::Math::Clamp(
original, 0.0f, 1.0f);
cv.r = original;
worldMapImage.setColourAt(
cv, selected_x + j,
selected_y + i, 0);
}
updateWorldTexture();
updateHeightmap();
}
if (setLevel) {
int actualSize = 1 + size * 2;
int i, j;
float original = setLevelValue;
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 (selected_x + j < 0 ||
selected_x + j >=
worldMap->getWidth())
continue;
if (selected_y + i < 0 ||
selected_y + i >=
worldMap->getHeight())
continue;
Ogre::ColourValue cv =
worldMapImage.getColourAt(
selected_x + j,
selected_y + i, 0);
cv.r = original;
worldMapImage.setColourAt(
cv, selected_x + j,
selected_y + i, 0);
}
updateWorldTexture();
updateHeightmap();
}
if (ImGui::Button("Save heightmap")) {
updateWorldTexture();
updateHeightmap();
TerrainModule::save_heightmap();
}
ImGui::EndChild();
ImGui::Spacing();
ImGui::End();
}
void panel()
{
ImVec2 size = ImGui::GetMainViewport()->Size;
float window_width = size.x * 0.2f;
if (window_width > panel_width)
window_width = panel_width;
float window_height = size.y * 0.5f - 20;
ImGui::SetNextWindowPos(ImVec2(size.x - window_width, 20),
ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_Always);
// ImGui::Begin("Dumb and Stupid", &mKbd.gui_active);
ImGui::Begin("Panel...");
std::deque<Ogre::SceneNode *> tree_input_queue,
tree_output_queue;
std::vector<Ogre::SceneNode *> tree_list;
tree_input_queue.push_back(
ECS::get()
.get<EngineData>()
.mScnMgr->getRootSceneNode());
tree_input_queue.push_back(nullptr);
std::set<Ogre::SceneNode *> visited;
while (true) {
int new_nodes_count = 0;
while (!tree_input_queue.empty()) {
int child;
Ogre::SceneNode *item =
tree_input_queue.front();
tree_input_queue.pop_front();
if (item && visited.find(item) ==
visited.end()) { // new node
new_nodes_count++;
tree_output_queue.push_back(item);
visited.insert(item);
const Ogre::Node::ChildNodeMap
&children = item->getChildren();
for (child = 0; child < children.size();
child++) {
tree_output_queue.push_back(
static_cast<Ogre::SceneNode
*>(
children[child]));
tree_output_queue.push_back(
nullptr);
}
} else
tree_output_queue.push_back(item);
}
if (new_nodes_count == 0)
break;
tree_input_queue = tree_output_queue;
tree_output_queue.clear();
}
tree_list.insert(tree_list.begin(), tree_output_queue.begin(),
tree_output_queue.end());
int count = 0;
int depth = 0;
std::vector<int> check_depth;
int max_depth = 0;
check_depth.push_back(0);
for (count = 0; count < tree_list.size(); count++) {
int t;
Ogre::SceneNode *node = tree_list[count];
if (node && max_depth >= depth) {
Ogre::String name = node->getName();
if (name.length() == 0) {
name = "Node #" +
Ogre::StringConverter::toString(
count);
}
if (ImGui::TreeNode(name.c_str())) {
check_depth.push_back(max_depth);
max_depth++;
ImGui::Text(
"%s",
(name + "##caption").c_str());
position_editor(node);
ImGui::Separator();
orientation_editor(node);
ImGui::Separator();
if (ImGui::Button("From Cursor"))
std::cout << name
<< " From Cursor"
<< std::endl;
if (ImGui::Button("To Cursor"))
std::cout << name
<< " To Cursor"
<< std::endl;
ImGui::Separator();
ImGui::Text("Attachments");
attachments_editor(node);
}
} else if (!node && max_depth >= depth) {
max_depth = check_depth.back();
check_depth.pop_back();
ImGui::TreePop();
}
if (tree_list[count])
depth++;
else
depth--;
}
ImGui::Spacing();
ImGui::End();
#if 0
if (ECS::get().get<GUI>().narrationBox) {
ImVec2 size = ImGui::GetMainViewport()->Size;
@@ -990,6 +1471,20 @@ struct EditorGUIListener : public Ogre::RenderTargetListener {
ImGui::End();
}
#endif
}
void preview(const Ogre::RenderTargetViewportEvent &evt)
{
int i;
Ogre::ImGuiOverlay::NewFrame();
if (ECS::get().get<GUI>().enabled) {
buttons_panel();
#if 0
buildings_editor();
map_editor();
#endif
panel();
if (enableMapEditor)
worldMapView();
}
}
};

View File

@@ -145,7 +145,6 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
PhysicsShape &s = e.ensure<PhysicsShape>();
s.shape = shape;
e.modified<PhysicsShape>();
delete hfd.samples;
e.remove<PhysicsHeightfieldData>();
});
#if 1
@@ -341,6 +340,16 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
.each([this](const EngineData &eng) {
ECS::get().set<WaterBody>({});
});
#if 0
ecs.system<const EngineData>("DebugData")
.kind(PhysicsPostUpdate)
.each([this](const EngineData &eng) {
std::cout << "TerrainReady: "
<< ECS::get().has<TerrainReady>();
std::cout << " WaterReady: "
<< ECS::get().has<WaterReady>() << std::endl;
});
#endif
ecs.system<const EngineData, WaterBody>("update_water")
.kind(PhysicsPostUpdate)
.with<TerrainReady>()

View File

@@ -1,3 +1,4 @@
#include <iostream>
#include <Ogre.h>
#include "Components.h"
#include "SunModule.h"

View File

@@ -8,6 +8,7 @@
#include <OgreTerrainPagedWorldSection.h>
#include <OgrePage.h>
#include <OgreTerrainPaging.h>
#include <OgreFileSystemLayer.h>
#include "GameData.h"
#include "Components.h"
@@ -71,11 +72,50 @@ struct HeightData {
}
return img_brushes.getColourAt(x, y + m, 0).r;
}
float get_base_height(const Ogre::Vector2 &worldOffset, int x, int y)
float get_world_x(int x)
{
return (float)(x - (int)img.getWidth() / 2) * BRUSH_SIZE;
}
float get_world_y(int y)
{
return (float)(y - (int)img.getHeight() / 2) * BRUSH_SIZE;
}
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;
// 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;
// ret = Ogre::Math::Clamp(ret, 0, (int)img.getHeight() - 1);
return ret;
}
void update_heightmap(const Ogre::Image &heightmap)
{
img = heightmap;
}
void save_heightmap()
{
Ogre::String group =
Ogre::ResourceGroupManager::getSingleton()
.findGroupContainingResource("world_map.png");
Ogre::FileInfoListPtr fileInfoList(
Ogre::ResourceGroupManager::getSingleton()
.findResourceFileInfo(group, "world_map.png"));
OgreAssert(fileInfoList->size() == 1,
"worpd_map.png should be there and only once");
Ogre::String path = fileInfoList->at(0).archive->getName() +
"/" + "world_map.png";
Ogre::FileSystemLayer::removeFile(path);
img.save(path);
}
float get_base_height(long world_x, long world_y)
{
float height = 0.0f;
int world_x = worldOffset.x + x;
int world_y = worldOffset.y + y;
int world_img_x =
world_x + (int)img.getWidth() * BRUSH_SIZE / 2;
int world_img_y =
@@ -91,7 +131,7 @@ struct HeightData {
world_img_x >= img.getWidth() * BRUSH_SIZE ||
world_img_y < 0 ||
world_img_y >= img.getWidth() * BRUSH_SIZE) {
height = -1.0f;
height = 0.0f;
goto out;
}
color = img.getColourAt(map_img_x, map_img_y, 0);
@@ -103,7 +143,7 @@ struct HeightData {
out:
return height;
}
float get_noise_height(const Ogre::Vector2 &worldOffset, int x, int y)
float get_noise_height(long world_x, long world_y)
{
int h;
Ogre::Vector2 noisePoint;
@@ -122,7 +162,7 @@ out:
for (h = 0; h < (int)sizeof(noise_values) /
(int)sizeof(noise_values[0]);
h++) {
noisePoint = (worldOffset + Ogre::Vector2(x, y) +
noisePoint = (Ogre::Vector2(world_x, world_y) +
noise_pass[h].noiseOfft) *
noise_pass[h].noiseMul;
int noise_x =
@@ -139,31 +179,44 @@ out:
}
return noise_values[0] + noise_values[1];
}
float get_height(Ogre::TerrainGroup *terrainGroup, long x, long y,
int j, int i)
float get_height(Ogre::TerrainGroup *terrainGroup, long world_x,
long world_y)
{
uint16_t terrainSize = terrainGroup->getTerrainSize();
Ogre::Vector2 worldOffset(Ogre::Real(x * (terrainSize - 1)),
Ogre::Real(y * (terrainSize - 1)));
float brush_height0 =
HeightData::get_singleton()->get_brush_height(
0, j % BRUSH_SIZE, i % BRUSH_SIZE) -
0.55f;
float brush_height1 =
HeightData::get_singleton()->get_brush_height(
1, j % BRUSH_SIZE, i % BRUSH_SIZE) -
0.55f;
long grid_center_x = img.getWidth() * BRUSH_SIZE / 2;
long grid_center_y = img.getHeight() * BRUSH_SIZE / 2;
long world_grid_x = world_x + grid_center_x;
long world_grid_y = world_y + grid_center_y;
float amplitude = 150.0f;
if (world_grid_x < 0 || world_grid_y < 0) {
std::cout << "world: " << world_x << " " << world_y
<< " ";
std::cout << "grid: " << world_grid_x << " ";
std::cout << world_grid_y << std::endl;
return -amplitude;
}
OgreAssert(world_grid_x >= 0, "bad world x");
OgreAssert(world_grid_y >= 0, "bad world y");
long cell = 8;
long b1 = (world_grid_x / cell) * cell + cell / 2;
long b2 = (world_grid_y / cell) * cell + cell / 2;
long o1 = Ogre::Math::Abs(world_grid_x - b1);
long o2 = Ogre::Math::Abs(world_grid_y - b2);
// std::cout << "h: " << o1 << " " << o2 << std::endl;
// std::cout << "h: " << (o1 * o1 + o2 * o2) << std::endl;
float hbase = 1.0 / (1.0f + 0.02f * (o1 * o1 + o2 * o2));
float h1 = hbase * 0.5f + 0.5f;
float h2 = (1.0f - hbase) * 0.5f;
float mheight =
Ogre::Math::lerp(
brush_height1, brush_height0,
HeightData::get_singleton()->get_base_height(
worldOffset, j, i)) *
120.0f;
(Ogre::Math::lerp(h2, h1,
get_base_height(world_x, world_y)) -
0.51f) *
amplitude;
float height = mheight;
if (mheight > 0.5f)
height += 2.0f + get_noise_height(worldOffset, j, i);
height += 2.0f + get_noise_height(world_x, world_y);
else if (mheight < -0.5f)
height -= 2.0f + get_noise_height(worldOffset, j, i);
height -= 2.0f + get_noise_height(world_x, world_y);
// OgreAssert(false, "height");
return height;
}
};
@@ -231,11 +284,29 @@ public:
// Ogre::Vector2(img.getWidth(), img.getHeight()) * 0.5f;
float chunk = 128.0f;
Ogre::Vector2 revisedValuePoint;
Ogre::Vector3 worldPos;
terrainGroup->convertTerrainSlotToWorldPosition(x, y,
&worldPos);
for (int i = 0; i < terrainSize; i++)
for (int j = 0; j < terrainSize; j++) {
float height =
HeightData::get_singleton()->get_height(
terrainGroup, x, y, j, i);
long world_x = (long)(worldPos.x + j -
(terrainSize - 1) / 2);
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 = -2.0f;
heightMap[i * terrainSize + j] = height;
@@ -526,16 +597,16 @@ TerrainModule::TerrainModule(flecs::world &ecs)
priv.mSunUpdate.reset();
}
});
ecs.system<const CharacterBase, const Terrain>("UpdateTerrainStatus")
ecs.system<const ECS::Camera, const Terrain>("UpdateTerrainStatus")
.kind(flecs::OnUpdate)
.without<TerrainReady>()
.each([](const CharacterBase &ch, const Terrain &terrain) {
.each([](const ECS::Camera &cam, const Terrain &terrain) {
std::cout << "mTerrainReady: " << terrain.mTerrainReady
<< "\n";
std::cout << "mBodyNode: " << ch.mBodyNode << "\n";
if (ch.mBodyNode && terrain.mTerrainReady) {
if (cam.mCameraNode && terrain.mTerrainReady) {
long x, y;
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
Ogre::Vector3 pos =
cam.mCameraNode->getPosition();
terrain.mTerrainGroup
->convertWorldPositionToTerrainSlot(
pos, &x, &y);
@@ -560,8 +631,7 @@ TerrainModule::TerrainModule(flecs::world &ecs)
item.position = Ogre::Vector3(0, 0, 0);
float height =
HeightData::get_singleton()->get_height(
terrain.mTerrainGroup, 0, 0, 0,
0);
terrain.mTerrainGroup, 0, 0);
item.position.y = height;
placement.altar_items.push_back(item);
for (i = -64000; i < 64000; i += 2000)
@@ -586,14 +656,10 @@ TerrainModule::TerrainModule(flecs::world &ecs)
HeightData::get_singleton()
->get_height(
terrain.mTerrainGroup,
xslot,
yslot,
(int)offset.x +
(terrainSize -
1) / 2,
(int)offset.z +
(terrainSize -
1) / 2);
(long)position
.x,
(long)position
.z);
#if 0
height =
terrain.mTerrainGroup
@@ -672,8 +738,31 @@ float TerrainModule::get_height(Ogre::TerrainGroup *group,
group->convertTerrainSlotToWorldPosition(xslot, yslot, &slotpos);
Ogre::Vector3 offset = (position - slotpos) * terrainSize / worldSize;
float height = HeightData::get_singleton()->get_height(
group, xslot, yslot, (int)offset.x + (terrainSize - 1) / 2,
(int)offset.z + (terrainSize - 1) / 2);
group, (long)position.x, (long)position.z);
return height;
}
float TerrainModule::get_world_x(int x)
{
return HeightData::get_singleton()->get_world_x(x);
}
float TerrainModule::get_world_y(int y)
{
return HeightData::get_singleton()->get_world_y(y);
}
int TerrainModule::get_img_x(float world_x)
{
return HeightData::get_singleton()->get_img_x(world_x);
}
int TerrainModule::get_img_y(float world_z)
{
return HeightData::get_singleton()->get_img_y(world_z);
}
void TerrainModule::update_heightmap(const Ogre::Image &heightmap)
{
return HeightData::get_singleton()->update_heightmap(heightmap);
}
void TerrainModule::save_heightmap()
{
HeightData::get_singleton()->save_heightmap();
}
}

View File

@@ -35,6 +35,12 @@ struct TerrainModule {
TerrainModule(flecs::world &ecs);
static float get_height(Ogre::TerrainGroup *group,
const Ogre::Vector3 &position);
static float get_world_x(int x);
static float get_world_y(int y);
static int get_img_x(float world_x);
static int get_img_y(float world_z);
static void update_heightmap(const Ogre::Image &heightmap);
static void save_heightmap();
};
struct TerrainReady {};
}

View File

@@ -56,6 +56,7 @@ public:
};
#endif
static const uint32_t WATER_MASK = 0xF00;
static bool debugEnabled = false;
WaterModule::WaterModule(flecs::world &ecs)
{
ecs.module<WaterModule>();
@@ -163,15 +164,18 @@ WaterModule::WaterModule(flecs::world &ecs)
Ogre::FT_MIP, Ogre::FO_LINEAR);
}
// create a frosted screen in front of the camera, using our dynamic texture to "thaw" certain areas
Ogre::Entity *ent = eng.mScnMgr->createEntity(
"WaterDebugPlane",
Ogre::SceneManager::PT_PLANE);
ent->setMaterialName("Water/Debug", "Water");
ent->setVisibilityFlags(WATER_MASK);
Ogre::SceneNode *node =
camera.mCameraNode->createChildSceneNode();
node->setPosition(-150, 60, -400);
node->attachObject(ent);
if (debugEnabled) {
Ogre::Entity *ent = eng.mScnMgr->createEntity(
"WaterDebugPlane",
Ogre::SceneManager::PT_PLANE);
ent->setMaterialName("Water/Debug", "Water");
ent->setVisibilityFlags(WATER_MASK);
Ogre::SceneNode *node =
camera.mCameraNode
->createChildSceneNode();
node->setPosition(-150, 60, -400);
node->attachObject(ent);
}
water.mReflectionTexture =
reflectionTexture->getBuffer()