TerraForge3D  2.3.1
3D Terrain And Landscape Generator
HeightmapNode.cpp
1#include "Generators/CPUNodeEditor/Nodes/HeightmapNode.h"
2#include "Utils/Utils.h"
3#include "Data/ProjectData.h"
4#include "Base/Heightmap.h"
5#include "Base/ImGuiShapes.h"
6#include "Generators/CPUNodeEditor/CPUNodeEditor.h"
7#include <iostream>
8#include <implot.h>
9#include <mutex>
10#include <cmath>
11#include "Base/ImGuiCurveEditor.h"
12#include "Platform.h"
13
14static float fract(float v)
15{
16 return v - floorf(v);
17}
18
19NodeOutput HeightmapNode::Evaluate(NodeInputParam input, NodeEditorPin *pin)
20{
21 if (isDefault)
22 return NodeOutput({0.0f});
23 float res, sc, x, y;
24 res = sc = x = y = 0.0f;
25 int channel = 0;
26
27 if (inputPins[0]->IsLinked())
28 {
29 x = inputPins[0]->other->Evaluate(input).value;
30 }
31
32 else
33 {
34 x = input.texX;
35 }
36
37 if (inputPins[1]->IsLinked())
38 {
39 y = inputPins[1]->other->Evaluate(input).value;
40 }
41
42 else
43 {
44 y = input.texY;
45 }
46
47 if (inputPins[2]->IsLinked())
48 {
49 sc = inputPins[2]->other->Evaluate(input).value;
50 }
51
52 else
53 {
54 sc = scale;
55 }
56
57 x = (x * 2.0f - 1.0f) * sc - posi[0];
58 y = (y * 2.0f - 1.0f) * sc - posi[1];
59 float cr = cos(rota * 3.1415926535f / 180.0f);
60 float sr = sin(rota * 3.1415926535f / 180.0f);
61 float tx = x;
62 float ty = y;
63 x = tx * cr - ty * sr;
64 y = tx * sr + ty * cr;
65 x = x * 0.5f + 0.5f;
66 y = y * 0.5f + 0.5f;
67 x = fract(x);
68 y = fract(y);
69 int xC = (int)(x * (heightmap->GetWidth()-1));
70 int yC = (int)(y * (heightmap->GetHeight()-1));
71
72
73 mutex.lock();
74
75 res = heightmap->Sample(x, y, interpolated) / 65536.0;
76 if (!autoTiled)
77 {
78 if(x > numTiles || y > numTiles || x < 0 || y < 0)
79 return NodeOutput({ 0.0f });
80 }
81
82 if(npScale)
83 {
84 res = res * 2.0f - 1.0f;
85 }
86
87 if(inv)
88 {
89 res = 1.0f - res;
90 }
91
92 mutex.unlock();
93 return NodeOutput({ res });
94}
95
96void HeightmapNode::Load(nlohmann::json data)
97{
98 scale = data["scale"];
99
100 if (isDefault && data["isDefault"])
101 {
102 return;
103 }
104
105 isDefault = data["isDefault"];
106 interpolated = data["interpolated"];
107 npScale = data["npsc"];
108 inv = data["inv"];
109 autoTiled = data["autoTiled"];
110 numTiles = data["numTiles"];
111 posi[0] = data["posiX"];
112 posi[1] = data["posiY"];
113 rota = data["rota"];
114
115 if (isDefault)
116 {
117 delete heightmap;
118 heightmap = new Heightmap(GetExecutableDir() + PATH_SEPARATOR "Data" PATH_SEPARATOR "heightmaps" PATH_SEPARATOR "flat.png");
119 }
120
121 else
122 {
123 std::string hash = data["heightmap"];
124
125 if (!ProjectManager::Get()->AssetExists(hash))
126 {
127 ShowMessageBox("Failed to Load Heightmap : " + hash, "Error");
128 isDefault = true;
129 }
130
131 else
132 {
133 delete heightmap;
134 heightmap = new Heightmap(ProjectManager::Get()->GetResourcePath() + PATH_SEPARATOR + ProjectManager::Get()->GetAsset(hash));
135 Log("Loaded Cached Heightmap : " + hash);
136 }
137 }
138}
139
140nlohmann::json HeightmapNode::Save()
141{
142 nlohmann::json data;
143 data["type"] = MeshNodeEditor::MeshNodeType::Heightmap;
144 data["scale"] = scale;
145 data["isDefault"] = isDefault;
146 data["interpolated"] = interpolated;
147 data["inv"] = inv;
148 data["npsc"] = npScale;
149 data["autoTiled"] = autoTiled;
150 data["numTiles"] = numTiles;
151 data["posiX"] = posi[0];
152 data["posiY"] = posi[1];
153 data["rota"] = rota;
154
155 if (!isDefault)
156 {
157 std::string hash = MD5File(heightmap->GetPath()).ToString();
158 data["heightmap"] = hash;
159
160 if (!ProjectManager::Get()->AssetExists(hash))
161 {
162 ProjectManager::Get()->SaveResource("heightmaps", heightmap->GetPath());
163 Log("Cached " + heightmap->GetPath());
164 }
165
166 else
167 {
168 Log("Heightmap already cached : " + hash);
169 }
170 }
171
172 return data;
173}
174
175void HeightmapNode::OnRender()
176{
177 DrawHeader("Heightmap");
178 inputPins[0]->Render();
179 ImGui::Text("X");
180 ImGui::SameLine();
181 ImGui::Dummy(ImVec2(150, 10));
182 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
183 ImGui::Text("Height");
184 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
185 outputPins[0]->Render();
186 inputPins[1]->Render();
187 ImGui::Text("Y");
188 inputPins[2]->Render();
189
190 if (inputPins[2]->IsLinked())
191 {
192 ImGui::Text("Scale");
193 }
194
195 else
196 {
197 ImGui::PushItemWidth(100);
198 ImGui::DragFloat(("Scale##" + std::to_string(inputPins[1]->id)).c_str(), &scale, 0.01f);
199 ImGui::PopItemWidth();
200 }
201
202 ImGui::Checkbox(("Auto Tiled##tild" + std::to_string(id)).c_str(), &autoTiled);
203 ImGui::Checkbox(("Interpolated##intrp" + std::to_string(id)).c_str(), &interpolated);
204 ImGui::Checkbox(("Inverted##tinv" + std::to_string(id)).c_str(), &inv);
205 ImGui::Checkbox(("Scale -1 To 1##tnpsc" + std::to_string(id)).c_str(), &npScale);
206
207 if(!autoTiled)
208 {
209 ImGui::PushItemWidth(100);
210 ImGui::DragFloat(("Num Tiles##nmtl" + std::to_string(id)).c_str(), &numTiles, 0.01f);
211 ImGui::PopItemWidth();
212 }
213 ImGui::DragFloat2(("Position##posi" + std::to_string(id)).c_str(), posi, 0.01f);
214 ImGui::PushItemWidth(100);
215 ImGui::DragFloat(("Rotation##rota" + std::to_string(id)).c_str(), &rota, 0.1f);
216 ImGui::PopItemWidth();
217 ImGui::NewLine();
218
219 if (ImGui::ImageButton((void*) heightmap->GetRendererID(), ImVec2(200, 200)))
220 {
221 ChangeHeightmap();
222 }
223
224 if (ImGui::Button(MAKE_IMGUI_LABEL(id, "Change Heightmap")))
225 {
226 ChangeHeightmap();
227 }
228}
229
230void HeightmapNode::ChangeHeightmap()
231{
232 std::string path = ShowOpenFileDialog(".png");
233
234 if (path.size() < 3)
235 {
236 return;
237 }
238
239 isDefault = false;
240 delete heightmap;
241 heightmap = new Heightmap(path);
242 if (heightmap->GetData())
243 {
244 Log("Changed Heightmap : " + heightmap->GetPath());
245 }
246 else {
247 Log("Failed To Change Heightmap : " + heightmap->GetPath());
248 }
249}
250
251
252HeightmapNode::~HeightmapNode()
253{
254 if(heightmap)
255 {
256 delete heightmap;
257 }
258}
259
260HeightmapNode::HeightmapNode()
261{
262 inputPins.push_back(new NodeEditorPin());
263 inputPins.push_back(new NodeEditorPin());
264 inputPins.push_back(new NodeEditorPin());
265 outputPins.push_back(new NodeEditorPin(NodeEditorPinType::Output));
266 headerColor = ImColor(IMAGE_NODE_COLOR);
267 heightmap = new Heightmap(GetExecutableDir() + PATH_SEPARATOR "Data" PATH_SEPARATOR "heightmaps" PATH_SEPARATOR "flat.png");
268 isDefault = true;
269 scale = 1.0f;
270 inv = false;
271 npScale = true;
272 autoTiled = true;
273 interpolated = true;
274 numTiles = 1;
275 rota = 0.0f;
276 posi[0] = posi[1] = 0.0f;
277}
a class to store JSON values
Definition: json.hpp:17860
std::size_t hash(const BasicJsonType &j)
hash a JSON value
Definition: json.hpp:5240