Skip to content

Commit

Permalink
trail renderer: added continuous fade functionality; added Bin2CPP he…
Browse files Browse the repository at this point in the history
…lper; fixes;
  • Loading branch information
turanszkij committed Feb 20, 2025
1 parent 4f579e9 commit 591f808
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 21 deletions.
1 change: 1 addition & 0 deletions Content/Documentation/ScriptingAPI-Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,7 @@ Path finding operations can be made by using a voxel grid and path queries. The
- [constructor] TrailRenderer()
- AddPoint(Vector pos, opt float width = 1, opt Vector color = Vector(1,1,1,1)) -- adds a new point to the trail
- Cut() -- cuts the trail at last point and starts a new trail
- Fade(float amount) -- Applies fade for the whole trail continuously, and removes segments that can be removed due to faded
- Clear() -- removes all points and cuts from the trail
- GetPointCount() : int -- returns the number of points in the trail
- GetPoint() : Vector pos, float width -- returns the point of the trail on the specified index
Expand Down
28 changes: 22 additions & 6 deletions Editor/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum class FileType
SOUND,
TEXT,
HEADER,
CPP,
};
static wi::unordered_map<std::string, FileType> filetypes = {
{"LUA", FileType::LUA},
Expand All @@ -36,6 +37,7 @@ static wi::unordered_map<std::string, FileType> filetypes = {
{"VRM", FileType::VRM},
{"FBX", FileType::FBX},
{"H", FileType::HEADER},
{"CPP", FileType::CPP},
{"TXT", FileType::TEXT},
};

Expand Down Expand Up @@ -4767,15 +4769,24 @@ void EditorComponent::Save(const std::string& filename)
if (type == FileType::INVALID)
return;

if(type == FileType::WISCENE || type == FileType::HEADER)
if(type == FileType::WISCENE || type == FileType::HEADER || type == FileType::CPP)
{
const bool dump_to_header = type == FileType::HEADER;
const bool dump_to_cpp = type == FileType::CPP;

wi::Archive archive = dump_to_header ? wi::Archive() : wi::Archive(filename, false);
wi::Archive archive = (dump_to_header || dump_to_cpp) ? wi::Archive() : wi::Archive(filename, false);
if (archive.IsOpen())
{
archive.SetCompressionEnabled(generalWnd.saveCompressionCheckBox.GetCheck() || dump_to_header);
archive.SetThumbnailAndResetPos(CreateThumbnailScreenshot());
if (dump_to_header || dump_to_cpp)
{
archive.SetCompressionEnabled(true);
// No thumbnail for header
}
else
{
archive.SetCompressionEnabled(generalWnd.saveCompressionCheckBox.GetCheck());
archive.SetThumbnailAndResetPos(CreateThumbnailScreenshot());
}

Scene& scene = GetCurrentScene();

Expand All @@ -4788,6 +4799,10 @@ void EditorComponent::Save(const std::string& filename)
{
archive.SaveHeaderFile(filename, wi::helper::RemoveExtension(wi::helper::GetFileNameFromPath(filename)));
}
else if (dump_to_cpp)
{
archive.SaveCPPFile(filename, wi::helper::RemoveExtension(wi::helper::GetFileNameFromPath(filename)));
}
}
else
{
Expand All @@ -4811,15 +4826,16 @@ void EditorComponent::SaveAs()
{
wi::helper::FileDialogParams params;
params.type = wi::helper::FileDialogParams::SAVE;
params.description = "Wicked Scene (.wiscene) | GLTF Model (.gltf) | GLTF Binary Model (.glb) | C++ header (.h)";
params.description = "Wicked Scene (.wiscene) | GLTF Model (.gltf) | GLTF Binary Model (.glb) | C++ code (.h,.cpp)";
params.extensions.push_back("wiscene");
params.extensions.push_back("gltf");
params.extensions.push_back("glb");
params.extensions.push_back("h");
params.extensions.push_back("cpp");
wi::helper::FileDialog(params, [=](std::string fileName) {
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
auto extension = wi::helper::toUpper(wi::helper::GetExtensionFromFileName(fileName));
std::string filename = (!extension.compare("GLTF") || !extension.compare("GLB") || !extension.compare("H")) ? fileName : wi::helper::ForceExtension(fileName, params.extensions.front());
std::string filename = (!extension.compare("GLTF") || !extension.compare("GLB") || !extension.compare("H") || !extension.compare("CPP")) ? fileName : wi::helper::ForceExtension(fileName, params.extensions.front());
Save(filename);
});
});
Expand Down
34 changes: 23 additions & 11 deletions Editor/TerrainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,13 @@ void HeightmapModifierWindow::From(wi::terrain::HeightmapModifier* ptr)
scaleSlider.SetValue(ptr->scale);
}

PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)
PropWindow::PropWindow(wi::terrain::Terrain* terrain, wi::terrain::Prop* prop, wi::scene::Scene* scene)
:prop(prop)
,scene(scene)
{
if (terrain == nullptr)
return;

std::string windowName = "Prop: ";
std::string propName = "NONE";
Entity entity = INVALID_ENTITY;
Expand Down Expand Up @@ -332,8 +335,11 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)
for (size_t i = 0; i < scene->objects.GetCount(); ++i)
{
const Entity ent = scene->objects.GetEntity(i);
const auto* name = scene->names.GetComponent(ent);
meshCombo.AddItem(name != nullptr ? name->name : std::to_string(ent), ent);
const NameComponent* name = scene->names.GetComponent(ent);
if (!scene->Entity_IsDescendant(ent, terrain->chunkGroupEntity))
{
meshCombo.AddItem(name != nullptr ? name->name : std::to_string(ent), ent);
}
}
AddWidget(&meshCombo);

Expand Down Expand Up @@ -366,9 +372,9 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)
minCountPerChunkInput.Create("");
minCountPerChunkInput.SetDescription("Min count per chunk: ");
minCountPerChunkInput.SetSize(elementSize);
minCountPerChunkInput.SetValue(0);
minCountPerChunkInput.SetValue(prop->min_count_per_chunk);
minCountPerChunkInput.SetTooltip("A chunk will try to generate min this many props of this type");
minCountPerChunkInput.OnInputAccepted([&](wi::gui::EventArgs args) {
minCountPerChunkInput.OnInputAccepted([=](wi::gui::EventArgs args) {
prop->min_count_per_chunk = std::min(prop->max_count_per_chunk, args.iValue);
generation_callback();
});
Expand All @@ -377,9 +383,9 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)
maxCountPerChunkInput.Create("");
maxCountPerChunkInput.SetDescription("Max count per chunk: ");
maxCountPerChunkInput.SetSize(elementSize);
maxCountPerChunkInput.SetValue(5);
maxCountPerChunkInput.SetValue(prop->max_count_per_chunk);
maxCountPerChunkInput.SetTooltip("A chunk will try to generate max this many props of this type");
maxCountPerChunkInput.OnInputAccepted([&](wi::gui::EventArgs args) {
maxCountPerChunkInput.OnInputAccepted([=](wi::gui::EventArgs args) {
prop->max_count_per_chunk = std::max(prop->min_count_per_chunk, args.iValue);
generation_callback();
});
Expand All @@ -400,6 +406,7 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)

regionPowerSlider.Create(0.0f, 1.0f, 1.0f, 1000, "Region power: ");
regionPowerSlider.SetSize(elementSize);
regionPowerSlider.SetValue(prop->region_power);
regionPowerSlider.SetTooltip("Region weight affection power factor");
regionPowerSlider.OnSlide([=](wi::gui::EventArgs args) {
prop->region_power = args.fValue;
Expand All @@ -409,6 +416,7 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)

noiseFrequencySlider.Create(0.0f, 1.0f, 1.0f, 1000, "Noise frequency: ");
noiseFrequencySlider.SetSize(elementSize);
noiseFrequencySlider.SetValue(prop->noise_frequency);
noiseFrequencySlider.SetTooltip("Perlin noise's frequency for placement factor");
noiseFrequencySlider.OnSlide([=](wi::gui::EventArgs args) {
prop->noise_frequency = args.fValue;
Expand All @@ -418,6 +426,7 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)

noisePowerSlider.Create(0.0f, 1.0f, 1.0f, 1000, "Noise pwer: ");
noisePowerSlider.SetSize(elementSize);
noisePowerSlider.SetValue(prop->noise_power);
noisePowerSlider.SetTooltip("Perlin noise's power");
noisePowerSlider.OnSlide([=](wi::gui::EventArgs args) {
prop->noise_power = args.fValue;
Expand All @@ -427,6 +436,7 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)

thresholdSlider.Create(0.0f, 1.0f, 0.5f, 1000, "Threshold: ");
thresholdSlider.SetSize(elementSize);
thresholdSlider.SetValue(prop->threshold);
thresholdSlider.SetTooltip("The chance of placement (higher is less chance)");
thresholdSlider.OnSlide([=](wi::gui::EventArgs args) {
prop->threshold = args.fValue;
Expand All @@ -436,15 +446,17 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)

minSizeSlider.Create(0.0f, 1.0f, 1.0f, 1000, "Min size: ");
minSizeSlider.SetSize(elementSize);
minSizeSlider.SetValue(prop->min_size);
minSizeSlider.SetTooltip("Scaling randomization range min");
minSizeSlider.OnSlide([=](wi::gui::EventArgs args) {
prop->min_size = std::min(args.fValue, prop->max_size);
generation_callback();
});
AddWidget(&minSizeSlider);

maxSizeSlider.Create(0.0f, 1.0f, 1.0f, 1000, "Max size: ");
maxSizeSlider.Create(0.0f, 10.0f, 1.0f, 1000, "Max size: ");
maxSizeSlider.SetSize(elementSize);
maxSizeSlider.SetValue(prop->max_size);
maxSizeSlider.SetTooltip("Scaling randomization range max");
maxSizeSlider.OnSlide([=](wi::gui::EventArgs args) {
prop->max_size = std::max(args.fValue, prop->min_size);
Expand All @@ -455,7 +467,7 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)
minYOffsetInput.Create("");
minYOffsetInput.SetDescription("Min vertical offset: ");
minYOffsetInput.SetSize(elementSize);
minYOffsetInput.SetValue(0);
minYOffsetInput.SetValue(prop->min_y_offset);
minYOffsetInput.SetTooltip("Minimal randomized offset on vertical axis");
minYOffsetInput.OnInputAccepted([=](wi::gui::EventArgs args) {
prop->min_y_offset = std::min(args.fValue, prop->max_y_offset);
Expand All @@ -466,7 +478,7 @@ PropWindow::PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene)
maxYOffsetInput.Create("");
maxYOffsetInput.SetDescription("Max vertical offset: ");
maxYOffsetInput.SetSize(elementSize);
maxYOffsetInput.SetValue(0);
maxYOffsetInput.SetValue(prop->max_y_offset);
maxYOffsetInput.SetTooltip("Maximum randomized offset on vertical axis");
maxYOffsetInput.OnInputAccepted([=](wi::gui::EventArgs args) {
prop->max_y_offset = std::max(args.fValue, prop->min_y_offset);
Expand Down Expand Up @@ -554,7 +566,7 @@ void PropsWindow::Rebuild()

void PropsWindow::AddWindow(wi::terrain::Prop& prop)
{
PropWindow* wnd = new PropWindow(&prop, &editor->GetCurrentScene());
PropWindow* wnd = new PropWindow(terrain, &prop, &editor->GetCurrentScene());
wnd->generation_callback = generation_callback;
wnd->OnClose([&, wnd](wi::gui::EventArgs args) {
windows_to_remove.push_back(wnd);
Expand Down
3 changes: 2 additions & 1 deletion Editor/TerrainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ struct PropWindow : public wi::gui::Window
wi::gui::TextInputField minYOffsetInput;
wi::gui::TextInputField maxYOffsetInput;

PropWindow(wi::terrain::Prop* prop, wi::scene::Scene* scene);
PropWindow(wi::terrain::Terrain* terrain, wi::terrain::Prop* prop, wi::scene::Scene* scene);
void ResizeLayout() override;

wi::terrain::Terrain* terrain = nullptr;
wi::terrain::Prop* prop = nullptr;
wi::scene::Scene* scene = nullptr;

Expand Down
11 changes: 11 additions & 0 deletions WickedEngine/wiArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ namespace wi
return wi::helper::Bin2H(data_ptr, pos, fileName, dataName.c_str());
}

bool Archive::SaveCPPFile(const std::string& fileName, const std::string& dataName)
{
if (IsCompressionEnabled())
{
wi::vector<uint8_t> final_data;
WriteCompressedData(final_data);
return wi::helper::Bin2CPP(final_data.data(), final_data.size(), fileName, dataName.c_str());
}
return wi::helper::Bin2CPP(data_ptr, pos, fileName, dataName.c_str());
}

const std::string& Archive::GetSourceDirectory() const
{
return directory;
Expand Down
4 changes: 4 additions & 0 deletions WickedEngine/wiArchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ namespace wi
// Write the archive contents into a C++ header file
// dataName : it will be the name of the byte data array in the header, that can be memory mapped as an Archive
bool SaveHeaderFile(const std::string& fileName, const std::string& dataName);
// Write the archive contents into a C++ source file
// dataName : it will be the name of the byte data array in the header, that can be memory mapped as an Archive
// Note: size is exported as name_size where name is the dataName that you give to it
bool SaveCPPFile(const std::string& fileName, const std::string& dataName);
// If the archive was opened from a file, this will return the file's directory
const std::string& GetSourceDirectory() const;
// If the archive was opened from a file, this will return the file's name
Expand Down
2 changes: 1 addition & 1 deletion WickedEngine/wiEmittedParticle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ namespace wi
EmitLocation& location = emit_locations[i];
XMFLOAT4X4 mat = location.transform.GetMatrix();
XMMATRIX M = XMMatrixTranspose(XMLoadFloat4x4(&mat));
M = M * W;
M = W * M;
XMStoreFloat4x4(&mat, M);
location.transform.Create(mat);
std::memcpy((EmitLocation*)alloc.data + i, &location, sizeof(location));
Expand Down
25 changes: 24 additions & 1 deletion WickedEngine/wiHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ namespace wi::helper
bool Bin2H(const uint8_t* data, size_t size, const std::string& dst_filename, const char* dataName)
{
std::string ss;
ss += "const uint8_t ";
ss += "const unsigned char ";
ss += dataName ;
ss += "[] = {";
for (size_t i = 0; i < size; ++i)
Expand All @@ -1324,6 +1324,29 @@ namespace wi::helper
return FileWrite(dst_filename, (uint8_t*)ss.c_str(), ss.length());
}

bool Bin2CPP(const uint8_t* data, size_t size, const std::string& dst_filename, const char* dataName)
{
std::string ss;
ss += "extern const unsigned char ";
ss += dataName;
ss += "[] = {";
for (size_t i = 0; i < size; ++i)
{
if (i % 32 == 0)
{
ss += "\n";
}
ss += std::to_string((uint32_t)data[i]) + ",";
}
ss += "\n};\n";
ss += "extern const unsigned long long ";
ss += dataName;
ss += "_size = sizeof(";
ss += dataName;
ss += ");";
return FileWrite(dst_filename, (uint8_t*)ss.c_str(), ss.length());
}

void StringConvert(const std::string& from, std::wstring& to)
{
#ifdef _WIN32
Expand Down
5 changes: 5 additions & 0 deletions WickedEngine/wiHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ namespace wi::helper
// dataName : the byte array's name
bool Bin2H(const uint8_t* data, size_t size, const std::string& dst_filename, const char* dataName);

// Converts a file into a C++ source file that contains the file contents as byte array and using extern.
// dataName : the byte array's name
// Note: size is exported as name_size where name is the dataName that you give to it
bool Bin2CPP(const uint8_t* data, size_t size, const std::string& dst_filename, const char* dataName);

void StringConvert(const std::string& from, std::wstring& to);

void StringConvert(const std::wstring& from, std::string& to);
Expand Down
34 changes: 34 additions & 0 deletions WickedEngine/wiTrailRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ namespace wi
static PipelineState PSO[BLENDMODE_COUNT];
static PipelineState PSO_wire;

void TrailRenderer::AddPoint(const XMFLOAT3& position, float width, const XMFLOAT4& color)
{
TrailPoint& point = points.emplace_back();
point.position = position;
point.width = width;
point.color = color;
}

void TrailRenderer::Cut()
{
if (points.empty())
Expand All @@ -32,6 +40,32 @@ namespace wi
}
}

void TrailRenderer::Fade(float amount)
{
if (points.size() > 1)
{
for (auto& point : points)
{
point.color.w = saturate(point.color.w - amount);
}
if (points[0].color.w <= 0 && points[1].color.w <= 0)
{
points.erase(points.begin());
for (auto& cut : cuts)
{
if (cut > 0)
{
cut--;
}
}
if (!cuts.empty() && cuts[0] == 0)
{
cuts.erase(cuts.begin());
}
}
}
}

void TrailRenderer::Draw(const CameraComponent& camera, CommandList cmd) const
{
if (points.size() < 2)
Expand Down
7 changes: 7 additions & 0 deletions WickedEngine/wiTrailRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ namespace wi
XMFLOAT4 texMulAdd = XMFLOAT4(1, 1, 0, 0);
XMFLOAT4 texMulAdd2 = XMFLOAT4(1, 1, 0, 0);

// Adds a new point:
void AddPoint(const XMFLOAT3& position, float width = 1, const XMFLOAT4& color = XMFLOAT4(1, 1, 1, 1));

// Adds a new cut, which will start a new continuous curve from the next AddPoint():
void Cut();

// Fades the curve and remove points that can be removed:
void Fade(float amount);

void Draw(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd) const;

static void Initialize();
Expand Down
Loading

0 comments on commit 591f808

Please sign in to comment.