596 lines
24 KiB
C++
596 lines
24 KiB
C++
#include "stdafx.h"
|
|
#include "ProjectCreatorWindow.h"
|
|
|
|
#include "Utility/win32ico.h"
|
|
|
|
using namespace wi::ecs;
|
|
using namespace wi::scene;
|
|
|
|
void ProjectCreatorWindow::Create(EditorComponent* _editor)
|
|
{
|
|
editor = _editor;
|
|
control_size = 30;
|
|
|
|
wi::gui::Window::Create("Project Creator");
|
|
|
|
infoLabel.Create("projectCreatorInfo");
|
|
infoLabel.SetFitTextEnabled(true);
|
|
infoLabel.SetText("Here you can create a new Wicked Engine application project. It will create a new folder with the project name, and set up an executable, lua script startup, custom icon, thumbnail and base colors.");
|
|
AddWidget(&infoLabel);
|
|
|
|
projectNameInput.Create("projectName");
|
|
projectNameInput.SetText("");
|
|
projectNameInput.SetDescription("Name: ");
|
|
projectNameInput.SetCancelInputEnabled(false);
|
|
AddWidget(&projectNameInput);
|
|
|
|
iconButton.Create("projectIcon");
|
|
iconButton.SetText("");
|
|
iconButton.SetDescription("Icon: ");
|
|
iconButton.SetSize(XMFLOAT2(128 * 0.5f, 128 * 0.5f));
|
|
iconButton.font_description.params.v_align = wi::font::WIFALIGN_BOTTOM;
|
|
iconButton.font_description.params.h_align = wi::font::WIFALIGN_CENTER;
|
|
iconButton.SetTooltip("The icon will be used for the executable icon.");
|
|
iconButton.OnClick([this](wi::gui::EventArgs args) {
|
|
if (iconResource.IsValid())
|
|
{
|
|
iconResource = {};
|
|
iconButton.SetImage(iconResource);
|
|
}
|
|
else
|
|
{
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Texture";
|
|
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
|
|
wi::helper::FileDialog(params, [this](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
|
|
wi::Resource res = wi::resourcemanager::Load(fileName);
|
|
if (!res.IsValid())
|
|
return;
|
|
iconResource.SetTexture(editor->CreateThumbnail(res.GetTexture(), 128, 128, true));
|
|
iconButton.SetImage(iconResource);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
AddWidget(&iconButton);
|
|
|
|
thumbnailButton.Create("projectThumbnail");
|
|
thumbnailButton.SetText("");
|
|
thumbnailButton.SetDescription("Thumbnail: ");
|
|
thumbnailButton.font_description.params.v_align = wi::font::WIFALIGN_BOTTOM;
|
|
thumbnailButton.font_description.params.h_align = wi::font::WIFALIGN_CENTER;
|
|
thumbnailButton.SetSize(XMFLOAT2(480 * 0.4f, 270 * 0.4f));
|
|
thumbnailButton.SetTooltip("The thumbnail will be used for displaying the project in the editor.");
|
|
thumbnailButton.OnClick([this](wi::gui::EventArgs args) {
|
|
if (thumbnailResource.IsValid())
|
|
{
|
|
thumbnailResource = {};
|
|
thumbnailButton.SetImage(thumbnailResource);
|
|
}
|
|
else
|
|
{
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Texture";
|
|
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
|
|
wi::helper::FileDialog(params, [this](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
|
|
wi::Resource res = wi::resourcemanager::Load(fileName);
|
|
if (!res.IsValid())
|
|
return;
|
|
thumbnailResource.SetTexture(editor->CreateThumbnail(res.GetTexture(), 480, 270));
|
|
thumbnailButton.SetImage(thumbnailResource);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
AddWidget(&thumbnailButton);
|
|
|
|
splashScreenButton.Create("projectSplashScreen");
|
|
splashScreenButton.SetText("");
|
|
splashScreenButton.SetDescription("Splash screen: ");
|
|
splashScreenButton.font_description.params.v_align = wi::font::WIFALIGN_BOTTOM;
|
|
splashScreenButton.font_description.params.h_align = wi::font::WIFALIGN_CENTER;
|
|
splashScreenButton.SetSize(XMFLOAT2(480 * 0.5f, 270 * 0.5f));
|
|
splashScreenButton.SetTooltip("The splash screen will be shown while the engine is initalizing.\nIf there is a splash screen, then it will replace the intialization log display.");
|
|
splashScreenButton.OnClick([this](wi::gui::EventArgs args) {
|
|
if (splashScreenResource.IsValid())
|
|
{
|
|
splashScreenResource = {};
|
|
splashScreenResourceCroppedPreview = {};
|
|
splashScreenButton.SetImage(splashScreenResourceCroppedPreview);
|
|
}
|
|
else
|
|
{
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Texture";
|
|
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
|
|
wi::helper::FileDialog(params, [this](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
|
|
wi::Resource res = wi::resourcemanager::Load(fileName);
|
|
if (!res.IsValid())
|
|
return;
|
|
splashScreenResource = res;
|
|
splashScreenResourceCroppedPreview.SetTexture(editor->CreateThumbnail(splashScreenResource.GetTexture(), 1280, 720, true));
|
|
splashScreenButton.SetImage(splashScreenResourceCroppedPreview);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
AddWidget(&splashScreenButton);
|
|
|
|
cursorLabel.Create("projectCursorLabel");
|
|
cursorLabel.SetText("You can add a custom cursor for your application here from an image. Specify the cursor click hotspot by clicking the image with the right mouse button and dragging the indicator.");
|
|
AddWidget(&cursorLabel);
|
|
|
|
cursorButton.Create("projectCursorButton");
|
|
cursorButton.SetText("");
|
|
cursorButton.SetDescription("Cursor: ");
|
|
cursorButton.font_description.params.v_align = wi::font::WIFALIGN_BOTTOM;
|
|
cursorButton.font_description.params.h_align = wi::font::WIFALIGN_CENTER;
|
|
cursorButton.SetSize(XMFLOAT2(64, 64));
|
|
cursorButton.SetTooltip("The cursor can be used as a custom cursor for your app. Here you can load an image to create it.");
|
|
cursorButton.OnClick([this](wi::gui::EventArgs args) {
|
|
if (cursorResource.IsValid())
|
|
{
|
|
cursorResource = {};
|
|
cursorButton.SetImage(cursorResource);
|
|
}
|
|
else
|
|
{
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Texture";
|
|
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
|
|
wi::helper::FileDialog(params, [this](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
|
|
wi::Resource res = wi::resourcemanager::Load(fileName);
|
|
if (!res.IsValid())
|
|
return;
|
|
cursorResource.SetTexture(editor->CreateThumbnail(res.GetTexture(), 64, 64, true));
|
|
cursorButton.SetImage(cursorResource);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
cursorButton.OnDrag([this](wi::gui::EventArgs args) {
|
|
if (wi::math::Length(args.deltaPos) > 0.1f)
|
|
{
|
|
hotspotX = saturate(inverse_lerp(cursorButton.GetPos().x, cursorButton.GetPos().x + cursorButton.GetSize().x, args.clickPos.x));
|
|
hotspotY = saturate(inverse_lerp(cursorButton.GetPos().y, cursorButton.GetPos().y + cursorButton.GetSize().y, args.clickPos.y));
|
|
cursorButton.DisableClickForCurrentDragOperation();
|
|
}
|
|
});
|
|
AddWidget(&cursorButton);
|
|
|
|
fontColorPicker.Create("font color", wi::gui::Window::WindowControls::NONE);
|
|
fontColorPicker.SetSize(XMFLOAT2(256, 256));
|
|
fontColorPicker.SetPickColor(exe_customization.font_color);
|
|
AddWidget(&fontColorPicker);
|
|
|
|
backgroundColorPicker.Create("background color", wi::gui::Window::WindowControls::NONE);
|
|
backgroundColorPicker.SetSize(XMFLOAT2(256, 256));
|
|
backgroundColorPicker.SetPickColor(exe_customization.background_color);
|
|
AddWidget(&backgroundColorPicker);
|
|
|
|
colorPreviewButton.Create("colorPreviewButton");
|
|
colorPreviewButton.SetText("Preview: these colors will be used by the application when showing the initialization screen and backlog text. [Click here to reset colors]");
|
|
colorPreviewButton.SetSize(XMFLOAT2(256, 64));
|
|
colorPreviewButton.OnClick([this](wi::gui::EventArgs args) {
|
|
fontColorPicker.SetPickColor(exe_customization.font_color);
|
|
backgroundColorPicker.SetPickColor(exe_customization.background_color);
|
|
});
|
|
AddWidget(&colorPreviewButton);
|
|
|
|
createButton.Create("projectCreate");
|
|
createButton.SetText(ICON_PROJECT_CREATE " Select folder and create project");
|
|
createButton.SetAngularHighlightWidth(6);
|
|
createButton.SetSize(XMFLOAT2(64, 64));
|
|
createButton.font.params.scaling = 1.5f;
|
|
createButton.OnClick([this](wi::gui::EventArgs args) {
|
|
if (projectNameInput.GetText().empty())
|
|
{
|
|
wi::helper::messageBox("Application name must be provided first!");
|
|
return;
|
|
}
|
|
std::string folder = wi::helper::FolderDialog("Select location where project folder will be created.");
|
|
if (folder.empty())
|
|
return;
|
|
std::string name = projectNameInput.GetText();
|
|
while (name.length() > 250)
|
|
{
|
|
// The name cannot be longer than 256 - ".lua", so cut from the end of it
|
|
// It is specifically because I will later overwrite a reserved 256-long string inside the executable
|
|
name.pop_back();
|
|
}
|
|
std::string directory = folder + "/" + name + "/";
|
|
wi::helper::DirectoryCreate(directory);
|
|
wilog("Project creator: created directory %s", directory.c_str());
|
|
|
|
static const std::string script_header = R"(
|
|
-- This script was generated by Wicked Editor Project Creator, you can modify it to your needs.
|
|
-- Read the scripting API documentation here: https://github.com/turanszkij/WickedEngine/blob/master/Content/Documentation/ScriptingAPI-Documentation.md
|
|
)";
|
|
|
|
static const std::string script_cursor = R"(
|
|
input.SetCursorFromFile(CURSOR_DEFAULT, script_dir() .. "cursor.cur")
|
|
)";
|
|
|
|
static const std::string script_process = R"(
|
|
-- by running the script as a process, we can use engine events like update() in it to halt the script while the event doesn't arrive
|
|
runProcess(function()
|
|
|
|
-- retrieve the global scene and camera objects that will be used for 3D rendering
|
|
local scene = GetScene()
|
|
local camera = GetCamera()
|
|
|
|
-- load a sample model simply into the current global scene from an asset file:
|
|
local cube_root_entity = LoadModel(script_dir() .. "/cube.wiscene")
|
|
|
|
-- create a point light to be able to see the cube:
|
|
local light_entity = CreateEntity()
|
|
local light = scene.Component_CreateLight(light_entity)
|
|
light.SetType(POINT)
|
|
light.SetIntensity(10)
|
|
local light_transform = scene.Component_CreateTransform(light_entity)
|
|
light_transform.Translate(Vector(2,2,-2))
|
|
|
|
-- put camera back a bit so we can see the cube in the origin (note that the camera is updated with this transform every frame when TransformCamera() is called):
|
|
local cam_transform = TransformComponent()
|
|
cam_transform.Translate(Vector(0, 2, -8))
|
|
|
|
-- set up a 3D render path, so if you load a model it will be displayed
|
|
local renderpath = RenderPath3D()
|
|
application.SetActivePath(renderpath, 1.0, 0, 0, 0, FadeType.CrossFade) -- 1 sec cross fade
|
|
|
|
-- set up a simple 2D text that will dynamically change every frame
|
|
local counter = 0
|
|
local font = SpriteFont()
|
|
renderpath.AddFont(font)
|
|
|
|
-- run an endless update loop, it will run until killProcesses() is called or the application exits
|
|
while true do
|
|
update() -- blocks this process until next update() is signaled from Wicked Engine
|
|
|
|
local dt = getDeltaTime() -- get delta time (elapsed time since last update())
|
|
|
|
-- every frame the text is positioned to the upper center of the screen and display the value of the frame counter
|
|
font.SetText("Hello World! Current frame counter = " .. counter .. "\nCamera look: right mouse button\nMove camera: WASD\nMove object: arrows\nIf you run this script from Wicked Editor, ESCAPE will return to the editor.")
|
|
font.SetSize(24) -- the true render size of the font (larger can increase memory usage, but improves appearance)
|
|
font.SetScale(2) -- upscaling the font without increasing the true font resolution
|
|
font.SetPos(Vector(GetScreenWidth() * 0.5, GetScreenHeight() * 0.25)) -- put to upper center of the screen
|
|
font.SetAlign(WIFALIGN_CENTER, WIFALIGN_CENTER) -- horizontal and vertical text align
|
|
|
|
-- Mouse look camera:
|
|
if input.Down(MOUSE_BUTTON_RIGHT) then
|
|
local mouse_movement = input.GetPointerDelta()
|
|
mouse_movement = vector.Multiply(mouse_movement, dt * 0.1)
|
|
cam_transform.Rotate(Vector(mouse_movement.GetY(), mouse_movement.GetX())) -- roll-pitch-yaw rotation
|
|
end
|
|
|
|
-- WASD camera movement:
|
|
local camspeed = 10 * dt
|
|
local camera_movement = Vector()
|
|
if input.Down(string.byte('W')) then
|
|
camera_movement = vector.Add(camera_movement, Vector(0,0,camspeed))
|
|
end
|
|
if input.Down(string.byte('S')) then
|
|
camera_movement = vector.Add(camera_movement, Vector(0,0,-camspeed))
|
|
end
|
|
if input.Down(string.byte('A')) then
|
|
camera_movement = vector.Add(camera_movement, Vector(-camspeed,0))
|
|
end
|
|
if input.Down(string.byte('D')) then
|
|
camera_movement = vector.Add(camera_movement, Vector(camspeed,0))
|
|
end
|
|
camera_movement = vector.Rotate(camera_movement, cam_transform.Rotation_local) -- rotate the camera movement with camera orientation, so it's relative
|
|
cam_transform.Translate(camera_movement)
|
|
|
|
cam_transform.UpdateTransform() -- because cam_transform is not part of the scene system, but we created it just in the script, update it manually with UpdateTransform()
|
|
camera.TransformCamera(cam_transform)
|
|
camera.UpdateCamera()
|
|
|
|
-- rotate the cube every frame by a bit with the amount of delta time since last frame:
|
|
local cube_transform = scene.Component_GetTransform(cube_root_entity)
|
|
cube_transform.Rotate(Vector(0, dt * math.pi, 0))
|
|
|
|
-- arrows object movement:
|
|
local movspeed = 10 * dt
|
|
local object_movement = Vector()
|
|
if input.Down(KEYBOARD_BUTTON_UP) then
|
|
object_movement = vector.Add(object_movement, Vector(0,movspeed))
|
|
end
|
|
if input.Down(KEYBOARD_BUTTON_DOWN) then
|
|
object_movement = vector.Add(object_movement, Vector(0,-movspeed))
|
|
end
|
|
if input.Down(KEYBOARD_BUTTON_LEFT) then
|
|
object_movement = vector.Add(object_movement, Vector(-movspeed,0))
|
|
end
|
|
if input.Down(KEYBOARD_BUTTON_RIGHT) then
|
|
object_movement = vector.Add(object_movement, Vector(movspeed,0))
|
|
end
|
|
object_movement = vector.Rotate(object_movement, cam_transform.Rotation_local) -- rotate the object movement with camera orientation, so it's relative
|
|
cube_transform.Translate(object_movement)
|
|
|
|
-- Add some editor testing functionality to return to editor when ESC is pressed. This can help development, and only works if script is running from the Editor:
|
|
if IsThisEditor() and input.Press(KEYBOARD_BUTTON_ESCAPE) then
|
|
ReturnToEditor()
|
|
input.ResetCursor(CURSOR_DEFAULT)
|
|
return
|
|
end
|
|
|
|
counter = counter + 1
|
|
|
|
end
|
|
|
|
end)
|
|
)";
|
|
|
|
std::string script = script_header;
|
|
|
|
if (cursorResource.IsValid())
|
|
{
|
|
script += script_cursor;
|
|
}
|
|
|
|
script += script_process;
|
|
|
|
std::string scriptfilename = name + ".lua";
|
|
std::string scriptfilepath = directory + scriptfilename;
|
|
if (!wi::helper::FileExists(scriptfilepath))
|
|
{
|
|
wi::helper::FileWrite(scriptfilepath, (const uint8_t*)script.data(), script.size());
|
|
}
|
|
else
|
|
{
|
|
wilog("Project creator: %s script file already exists, so it will not be overwritten.", scriptfilepath.c_str());
|
|
}
|
|
if (iconResource.IsValid())
|
|
{
|
|
wi::helper::saveTextureToFile(iconResource.GetTexture(), directory + "icon.png");
|
|
wi::helper::saveTextureToFile(iconResource.GetTexture(), directory + "icon.ico");
|
|
}
|
|
if (thumbnailResource.IsValid())
|
|
{
|
|
wi::helper::saveTextureToFile(thumbnailResource.GetTexture(), directory + "thumbnail.png");
|
|
}
|
|
if (splashScreenResource.IsValid())
|
|
{
|
|
wi::helper::saveTextureToFile(splashScreenResource.GetTexture(), directory + "splash_screen.png");
|
|
}
|
|
if (cursorResource.IsValid())
|
|
{
|
|
wi::graphics::Texture cursorTexture = cursorResource.GetTexture();
|
|
wi::vector<uint8_t> cursordata;
|
|
wi::helper::CreateCursorFromTexture(cursorTexture, int((float)cursorTexture.desc.width * hotspotX), int((float)cursorTexture.desc.height * hotspotY), cursordata);
|
|
wi::helper::FileWrite(directory + "cursor.cur", cursordata.data(), cursordata.size());
|
|
}
|
|
|
|
// Create a sample cube model for the project:
|
|
{
|
|
wi::scene::Scene samplescene;
|
|
samplescene.Entity_CreateCube("cube");
|
|
wi::Archive samplescene_archive;
|
|
samplescene.Serialize(samplescene_archive);
|
|
samplescene_archive.SaveFile(directory + "cube.wiscene");
|
|
}
|
|
|
|
if (wi::renderer::GetShaderDumpCount() == 0)
|
|
{
|
|
// If not using shader dump, try to copy shader compiler dlls into the project:
|
|
std::string dxcompiler_dll_path = wi::helper::GetDirectoryFromPath(wi::helper::GetExecutablePath()) + "dxcompiler.dll";
|
|
std::string dxcompiler_so_path = wi::helper::GetDirectoryFromPath(wi::helper::GetExecutablePath()) + "libdxcompiler.so";
|
|
if (wi::helper::FileExists(dxcompiler_dll_path))
|
|
{
|
|
wi::helper::FileCopy(dxcompiler_dll_path, directory + "dxcompiler.dll");
|
|
}
|
|
if (wi::helper::FileExists(dxcompiler_so_path))
|
|
{
|
|
wi::helper::FileCopy(dxcompiler_so_path, directory + "libdxcompiler.so");
|
|
}
|
|
}
|
|
|
|
wi::unordered_set<std::string> exes;
|
|
exes.insert(wi::helper::BackslashToForwardSlash(wi::helper::GetExecutablePath()));
|
|
exes.insert(wi::helper::BackslashToForwardSlash(wi::helper::GetCurrentPath() + "/Editor_Windows.exe"));
|
|
exes.insert(wi::helper::BackslashToForwardSlash(wi::helper::GetCurrentPath() + "/Editor_Linux"));
|
|
|
|
for (auto& exepath_src : exes)
|
|
{
|
|
if (!wi::helper::FileExists(exepath_src))
|
|
continue;
|
|
std::string exepath_dst = directory + name;
|
|
std::string extension = wi::helper::toUpper(wi::helper::GetExtensionFromFileName(exepath_src));
|
|
if (extension.find("EXE") != std::string::npos)
|
|
{
|
|
exepath_dst += "_Windows.exe";
|
|
}
|
|
else
|
|
{
|
|
exepath_dst += "_Linux";
|
|
}
|
|
if (wi::helper::FileCopy(exepath_src, exepath_dst))
|
|
{
|
|
wilog("Project creator: preparing executable %s -> %s", exepath_src.c_str(), exepath_dst.c_str());
|
|
wi::vector<uint8_t> exedata;
|
|
if (wi::helper::FileRead(exepath_dst, exedata))
|
|
{
|
|
// ApplicationExeCustomization replacement in the executable:
|
|
{
|
|
wi::vector<uint8_t> match_padded(arraysize(exe_customization.name_padded));
|
|
std::memcpy(match_padded.data(), exe_customization.name_padded, sizeof(exe_customization.name_padded));
|
|
|
|
auto it = std::search(exedata.begin(), exedata.end(), match_padded.begin(), match_padded.end());
|
|
if (it != exedata.end())
|
|
{
|
|
wi::vector<uint8_t> replacement(sizeof(ApplicationExeCustomization));
|
|
ApplicationExeCustomization& customization = *(ApplicationExeCustomization*)replacement.data();
|
|
std::memcpy(customization.name_padded, name.c_str(), name.length());
|
|
customization.font_color = fontColorPicker.GetPickColor();
|
|
customization.background_color = backgroundColorPicker.GetPickColor();
|
|
std::copy(replacement.begin(), replacement.end(), it);
|
|
wilog("\tOverwritten ApplicationExeCustomization structure");
|
|
}
|
|
}
|
|
|
|
// startup script string replacement in the executable:
|
|
{
|
|
auto it = std::search(exedata.begin(), exedata.end(), editor->main->rewriteable_startup_script_text.begin(), editor->main->rewriteable_startup_script_text.end());
|
|
if (it != exedata.end())
|
|
{
|
|
wi::vector<uint8_t> replacement(scriptfilename.length() + 1);
|
|
std::copy(scriptfilename.begin(), scriptfilename.end(), replacement.begin());
|
|
std::copy(replacement.begin(), replacement.end(), it);
|
|
wilog("\tOverwritten startup script name: %s", scriptfilename.c_str());
|
|
}
|
|
}
|
|
|
|
// Win32 icon replacement:
|
|
if (iconResource.IsValid())
|
|
{
|
|
wi::graphics::Texture tex = iconResource.GetTexture();
|
|
|
|
const int resolutions[] = {128,64,32};
|
|
|
|
for (int res : resolutions)
|
|
{
|
|
const uint32_t pixelCount = res * res;
|
|
const uint32_t rgbDataSize = pixelCount * 4; // 32-bit RGBA
|
|
const uint32_t maskSize = ((res + 7) / 8) * res; // 1-bit mask, padded to byte
|
|
const uint32_t bmpInfoHeaderSize = sizeof(ico::BITMAPINFOHEADER);
|
|
|
|
ico::BITMAPINFOHEADER bmpHeader = {
|
|
bmpInfoHeaderSize, // Size of header
|
|
int32_t(res), // Width
|
|
int32_t(res * 2), // Height (doubled for XOR + AND mask)
|
|
1, // Planes
|
|
32, // Bits per pixel
|
|
0, // No compression
|
|
rgbDataSize + maskSize, // Image size
|
|
0, // X pixels per meter
|
|
0, // Y pixels per meter
|
|
0, // Colors used
|
|
0 // Important colors
|
|
};
|
|
|
|
wi::vector<uint8_t> bmpvec(sizeof(bmpHeader));
|
|
std::memcpy(bmpvec.data(), &bmpHeader, sizeof(bmpHeader));
|
|
|
|
// searches for exact BMP header match:
|
|
// TODO: add some validation here because this method is quite stupid, just checking header bit pattern is not foolproof
|
|
auto it = std::search(exedata.begin(), exedata.end(), bmpvec.begin(), bmpvec.end());
|
|
if (it != exedata.end())
|
|
{
|
|
wi::vector<uint8_t> iconfiledata;
|
|
if (wi::helper::saveTextureToMemoryFile(editor->CreateThumbnail(tex, res, res, false), "ico", iconfiledata)) // note: individual mip thumbnails at this point!
|
|
{
|
|
// replace the BMP header and data part:
|
|
std::copy(iconfiledata.begin() + sizeof(ico::ICONDIR) + sizeof(ico::ICONDIRENTRY), iconfiledata.end(), it);
|
|
wilog("\tOverwritten Win32 icon at %d * %d resolution", res, res);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// SDL icon replacement:
|
|
if (iconResource.IsValid())
|
|
{
|
|
wi::graphics::Texture tex = iconResource.GetTexture();
|
|
|
|
std::string match = "Wicked Editor Embedded Icon Data SDL";
|
|
wi::vector<uint8_t> match_padded256(256);
|
|
std::memcpy(match_padded256.data(), match.c_str(), match.length());
|
|
|
|
// searches for match string:
|
|
auto it = std::search(exedata.begin(), exedata.end(), match_padded256.begin(), match_padded256.end());
|
|
if (it != exedata.end())
|
|
{
|
|
wi::vector<uint8_t> iconfiledata;
|
|
if (wi::helper::saveTextureToMemoryFile(tex, "raw", iconfiledata))
|
|
{
|
|
// replace the pixel data part:
|
|
std::copy(iconfiledata.begin(), iconfiledata.end(), it + 256);
|
|
wilog("\tOverwritten SDL icon");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wi::helper::FileWrite(exepath_dst, exedata.data(), exedata.size()))
|
|
{
|
|
wilog("\tSuccessfully prepared executable %s", exepath_dst.c_str());
|
|
}
|
|
else
|
|
{
|
|
wilog_error("\nWriting executable %s failed!", exepath_dst.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
editor->RegisterRecentlyUsed(directory + scriptfilename);
|
|
wi::helper::OpenUrl(directory);
|
|
});
|
|
AddWidget(&createButton);
|
|
|
|
SetVisible(false);
|
|
}
|
|
|
|
void ProjectCreatorWindow::Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const
|
|
{
|
|
wi::gui::Window::Render(canvas, cmd);
|
|
|
|
if (!IsVisible())
|
|
return;
|
|
wi::gui::Window::ApplyScissor(canvas, scissorRect, cmd);
|
|
wi::image::Params fx;
|
|
fx.pos.x = cursorButton.GetPos().x + cursorButton.GetSize().x * hotspotX;
|
|
fx.pos.y = cursorButton.GetPos().y + cursorButton.GetSize().y * hotspotY;
|
|
fx.pivot = XMFLOAT2(0.5f, 0.5f);
|
|
fx.color = wi::Color::White();
|
|
fx.siz.x = 2;
|
|
fx.siz.y = 16;
|
|
fx.blendFlag = wi::enums::BLENDMODE_INVERSE;
|
|
wi::image::Draw(nullptr, fx, cmd);
|
|
fx.rotation = XM_PI * 0.5f;
|
|
wi::image::Draw(nullptr, fx, cmd);
|
|
}
|
|
|
|
void ProjectCreatorWindow::ResizeLayout()
|
|
{
|
|
wi::gui::Window::ResizeLayout();
|
|
|
|
layout.margin_left = 60;
|
|
|
|
layout.add_fullwidth(infoLabel);
|
|
layout.add(projectNameInput);
|
|
|
|
layout.jump();
|
|
|
|
layout.add_right(iconButton, thumbnailButton, splashScreenButton);
|
|
|
|
layout.jump();
|
|
|
|
layout.add_right(cursorButton);
|
|
cursorLabel.SetPos(XMFLOAT2(layout.padding, cursorButton.GetPos().y));
|
|
cursorLabel.SetSize(XMFLOAT2(layout.width - cursorButton.GetSize().x - layout.padding * 3, cursorButton.GetSize().y));
|
|
|
|
layout.jump();
|
|
|
|
layout.add_fullwidth(colorPreviewButton);
|
|
layout.add(fontColorPicker, backgroundColorPicker);
|
|
|
|
layout.jump();
|
|
|
|
layout.add_fullwidth(createButton);
|
|
|
|
createButton.SetSize(XMFLOAT2(createButton.GetSize().x, std::max(30.0f, layout.height - createButton.GetPos().y - layout.padding * 2)));
|
|
|
|
colorPreviewButton.SetColor(backgroundColorPicker.GetPickColor());
|
|
colorPreviewButton.font.params.color = fontColorPicker.GetPickColor();
|
|
colorPreviewButton.font.params.v_align = wi::font::WIFALIGN_TOP;
|
|
colorPreviewButton.font.params.h_align = wi::font::WIFALIGN_LEFT;
|
|
colorPreviewButton.font.params.h_wrap = colorPreviewButton.GetSize().x;
|
|
}
|