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