Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@
[submodule "external/implot"]
path = external/implot
url = https://github.com/epezent/implot.git
[submodule "external/imnodes"]
path = external/imnodes
url = https://github.com/Nelarius/imnodes
37 changes: 22 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.15)
include(FetchContent)

if (WIN32)
if(WIN32)
set(VCPKG_TARGET_TRIPLET x64-windows-static-md)
endif()

Expand All @@ -27,7 +27,7 @@ add_subdirectory(external/embed)

file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")

set(EXTERNAL_SOURCES
set(EXTERNAL_SOURCES
external/tinyfiledialogs/tinyfiledialogs.c
external/microtar/src/microtar.c
external/nitroarc/nitroarc.c
Expand All @@ -50,6 +50,9 @@ set(EXTERNAL_SOURCES
# ImPlot
external/implot/implot.cpp
external/implot/implot_items.cpp

# ImNodes
external/imnodes/imnodes.cpp
)

add_executable(nitroefx ${SOURCES} ${EXTERNAL_SOURCES})
Expand All @@ -66,7 +69,7 @@ execute_process(
ERROR_QUIET
)

if (NOT NITROEFX_VERSION)
if(NOT NITROEFX_VERSION)
set(NITROEFX_VERSION "v0.0.0")
endif()

Expand All @@ -78,9 +81,11 @@ configure_file(

# Read versions for packages whose CMake configs don't set <pkg>_VERSION
set(VCPKG_STATUS_FILE "${CMAKE_BINARY_DIR}/vcpkg_installed/vcpkg/status")
if (EXISTS ${VCPKG_STATUS_FILE})

if(EXISTS ${VCPKG_STATUS_FILE})
file(READ ${VCPKG_STATUS_FILE} _vcpkg_status)
if (_vcpkg_status MATCHES "Package: efsw\nVersion: ([^\n]+)")

if(_vcpkg_status MATCHES "Package: efsw\nVersion: ([^\n]+)")
set(efsw_VERSION "${CMAKE_MATCH_1}")
endif()
endif()
Expand All @@ -91,11 +96,11 @@ configure_file(
@ONLY
)

if (WIN32 AND NOT CMAKE_BUILD_TYPE MATCHES Debug)
if(WIN32 AND NOT CMAKE_BUILD_TYPE MATCHES Debug)
set_target_properties(nitroefx PROPERTIES WIN32_EXECUTABLE true)
endif()

if (WIN32)
if(WIN32)
set(IMAGEQUANT_LIB "${LIBIMAGEQUANT_DIR}/target/release/imagequant_sys.lib")
else()
set(IMAGEQUANT_LIB "${LIBIMAGEQUANT_DIR}/target/release/libimagequant_sys.a")
Expand All @@ -115,8 +120,8 @@ add_custom_target(libimagequant_sys_build ALL

add_dependencies(nitroefx libimagequant_sys_build)

target_include_directories(nitroefx PRIVATE
src
target_include_directories(nitroefx PRIVATE
src
external/tinyfiledialogs
external/microtar/src
external/stb
Expand All @@ -127,13 +132,14 @@ target_include_directories(nitroefx PRIVATE
external/imgui/backends
external/imgui/misc/freetype
external/imgui/misc/cpp
external/implot)
target_compile_definitions(nitroefx PRIVATE
external/implot
external/imnodes)
target_compile_definitions(nitroefx PRIVATE
GLM_ENABLE_EXPERIMENTAL
IMGUI_DEFINE_MATH_OPERATORS
IMGUI_USER_CONFIG=<imgui/config.h>)
target_link_libraries(nitroefx PRIVATE
SDL3::SDL3
target_link_libraries(nitroefx PRIVATE
SDL3::SDL3
spdlog::spdlog
fmt::fmt
glm::glm
Expand All @@ -147,14 +153,15 @@ target_link_libraries(nitroefx PRIVATE
Freetype::Freetype
${IMAGEQUANT_LIB})

if (WIN32)
if(WIN32)
target_link_libraries(nitroefx PRIVATE Ws2_32.lib ntdll.lib userenv.lib Mpr.lib)
target_compile_options(nitroefx PRIVATE /wd4312)
target_sources(nitroefx PRIVATE data/icon.rc)
target_compile_definitions(nitroefx PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN)
else()
target_compile_options(nitroefx PRIVATE -Wno-int-to-pointer-cast -Wno-deprecated-enum-enum-conversion)
if (CMAKE_BUILD_TYPE MATCHES Debug)

if(CMAKE_BUILD_TYPE MATCHES Debug)
target_compile_definitions(nitroefx PRIVATE _DEBUG) # Match MSVC debug define
endif()
endif()
1 change: 1 addition & 0 deletions external/imnodes
Submodule imnodes added at eb3690
119 changes: 28 additions & 91 deletions src/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ Application::Application() {
};
}

int Application::run(int argc, char** argv) {
int Application::run(std::optional<std::filesystem::path> openPath) {
m_startupPath = std::move(openPath);

initLogging();

if (!SDL_Init(SDL_INIT_VIDEO)) {
Expand Down Expand Up @@ -235,13 +237,15 @@ int Application::run(int argc, char** argv) {

m_editor->update(delta);

if (!idle || activeEmitters) {
m_editor->updateParticles(delta);
} else if (idle && !activeEmitters) {
m_idleAccumulator += delta;
if (m_idleAccumulator > 0.5f) {
m_editor->updateParticles(m_idleAccumulator);
m_idleAccumulator = 0.0f;
if (const auto& active = g_projectManager->getActiveEditor()) {
if (!idle || activeEmitters) {
active->update(delta);
} else if (idle && !activeEmitters) {
m_idleAccumulator += delta;
if (m_idleAccumulator > 0.5f) {
active->update(m_idleAccumulator);
m_idleAccumulator = 0.0f;
}
}
}

Expand All @@ -258,7 +262,9 @@ int Application::run(int argc, char** argv) {
// Build default docking layout once if no ini file exists
if (!m_layoutInitialized) {
initDefaultDockingLayout();
checkArgs(argc, argv);
if (m_startupPath) {
openStartupTarget(*m_startupPath);
}
}

ImGui::DockSpaceOverViewport(ImGui::GetID("DockSpace"));
Expand Down Expand Up @@ -347,71 +353,6 @@ int Application::run(int argc, char** argv) {
return 0;
}

int Application::runCli(argparse::ArgumentParser& parser) {
if (parser.is_subcommand_used("export")) {
const auto& cmd = parser.at<argparse::ArgumentParser>("export");
const auto output = cmd.get<std::string>("--output");
const auto indices = cmd.get<std::vector<int>>("--index");

std::filesystem::path filePath(cmd.get<std::string>("path"));
if (!SPLArchive::isValid(filePath)) {
spdlog::error("Invalid SPL file: {}", filePath.string());
return 1;
}

SPLArchive archive(filePath, /* createGpuTextures */ false);

std::filesystem::path outputPath = output.empty() ? std::filesystem::current_path() : std::filesystem::path(output);

if (indices.empty()) {
std::filesystem::create_directories(outputPath);
archive.exportTextures(outputPath);
spdlog::info("Exported {} textures to {}", archive.getTextureCount(), outputPath.string());
return 0;
}

if (indices.size() == 1) {
const int index = indices[0];
if (index < 0 || static_cast<size_t>(index) >= archive.getTextureCount()) {
spdlog::error("Invalid texture index: {}", index);
return 1;
}

if (std::filesystem::is_directory(outputPath)) {
std::string filename = fmt::format("texture_{}.png", index);
outputPath /= filename;
}

archive.exportTexture(index, outputPath);
spdlog::info("Exported texture {} to {}", index, outputPath.string());
return 0;
}

if (std::filesystem::is_regular_file(outputPath)) {
spdlog::error("Output path must be a directory when exporting multiple textures");
return 1;
}

std::filesystem::create_directories(outputPath);
archive.exportTextures(outputPath);
} else if (parser.is_subcommand_used("info")) {
const auto& cmd = parser.at<argparse::ArgumentParser>("info");
std::filesystem::path filePath(cmd.get<std::string>("path"));
if (!SPLArchive::isValid(filePath)) {
spdlog::error("Invalid SPL file: {}", filePath.string());
return 1;
}

SPLArchive archive(filePath, /* createGpuTextures */ false);
archive.printInfo(filePath.filename().string());
} else {
spdlog::error("No subcommand specified");
return 1;
}

return 0;
}

void Application::showPopup(const std::string& title, const std::string& message, PopupType type, std::optional<PopupCallback> callback) {
const auto id = ImGui::GetID(title.c_str());

Expand Down Expand Up @@ -1161,7 +1102,9 @@ void Application::renderPerformanceWindow() {
}

ImGui::SeparatorText("Current Editor");
m_editor->renderStats();
if (const auto& editor = g_projectManager->getActiveEditor()) {
editor->renderStats();
}
}

ImGui::End();
Expand Down Expand Up @@ -1835,12 +1778,12 @@ void Application::executeAction(u32 action) {
break;
case ApplicationAction::Undo:
if (g_projectManager->hasActiveEditor()) {
g_projectManager->getActiveEditor()->undo();
m_editor->undo();
}
break;
case ApplicationAction::Redo:
if (g_projectManager->hasActiveEditor()) {
g_projectManager->getActiveEditor()->redo();
m_editor->redo();
}
break;
case ApplicationAction::Exit:
Expand Down Expand Up @@ -1870,18 +1813,13 @@ void Application::executeAction(u32 action) {
}
}

void Application::checkArgs(int argc, char** argv) {
if (argc > 1) {
const std::filesystem::path arg = argv[1];
if (std::filesystem::is_directory(arg)) {
g_projectManager->openProject(arg);
}
else if (arg.extension() == ".spa") {
g_projectManager->openEditor(arg);
}
else {
spdlog::warn("Invalid argument: {}", arg.string());
}
void Application::openStartupTarget(const std::filesystem::path& path) {
if (std::filesystem::is_directory(path)) {
addRecentProject(path.string());
g_projectManager->openProject(path);
} else {
// Routes by file type (.spa -> editor, .narc/.arc -> narc project) and updates recents.
tryOpenEditor(path);
}
}

Expand Down Expand Up @@ -2967,8 +2905,7 @@ bool Application::gunzipFile(const std::filesystem::path& srcPath, std::vector<u

bool Application::hasActiveEmitters() const {
if (!g_projectManager) return false;
if (!g_projectManager->hasActiveEditor()) return false;
const auto editor = g_projectManager->getActiveEditor();
const auto editor = g_projectManager->getActiveEditorAs<EditorInstance>();
if (!editor) return false;
// If any emitters exist we treat as active animation
return !editor->getParticleSystem().getEmitters().empty();
Expand Down
9 changes: 5 additions & 4 deletions src/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "version.h"
#include "util/circular_buffer.h"

#include <argparse/argparse.hpp>
#include <SDL3/SDL_events.h>
#include <string_view>

Expand Down Expand Up @@ -78,8 +77,7 @@ class Application {
public:
Application();

int run(int argc, char** argv);
int runCli(argparse::ArgumentParser& parser);
int run(std::optional<std::filesystem::path> openPath = std::nullopt);

void showPopup(const std::string& title, const std::string& message, PopupType type, std::optional<PopupCallback> callback);

Expand Down Expand Up @@ -142,7 +140,7 @@ class Application {
void loadIcon();
void clearTempDir();
void executeAction(u32 action);
void checkArgs(int argc, char** argv);
void openStartupTarget(const std::filesystem::path& path);
void clearCache();
void checkForBackups();

Expand Down Expand Up @@ -250,6 +248,9 @@ class Application {
// Tracks whether we've already attempted to initialize the layout
bool m_layoutInitialized = false;

// Optional file/folder to open once the GUI has initialized (from the command line)
std::optional<std::filesystem::path> m_startupPath;

std::string m_downloadedArchivePath;
std::string m_extractedBinaryPath;

Expand Down
Loading
Loading