Skip to content

Getting Started with Project

This guide demonstrates project creation and configuration management.

Creating a New Project

Create a project programmatically:

cpp
#include <astralix/modules/project/project.hpp>
#include <astralix/modules/project/managers/project-manager.hpp>

using namespace astralix;

ProjectConfig config;
config.name = "MyGame";
config.directory = "MyGame/";
config.manifest = "project.json";

// Window configuration
WindowConfig window;
window.id = 0;  // WindowID
window.title = "My Game";
window.width = 1920;
window.height = 1080;
window.headless = false;
config.windows.push_back(window);

// Renderer system configuration
SystemConfig renderSystem;
renderSystem.name = "RenderSystem";
renderSystem.type = SystemType::Render;

RenderSystemConfig renderConfig;
renderConfig.backend = "opengl";
renderConfig.headless = false;
renderConfig.window_id = "0";
renderConfig.msaa.samples = 4;
renderConfig.msaa.is_enabled = true;
renderSystem.content = renderConfig;
config.systems.push_back(renderSystem);

// Physics system configuration
SystemConfig physicsSystem;
physicsSystem.name = "PhysicsSystem";
physicsSystem.type = SystemType::Physics;

PhysicsSystemConfig physicsConfig;
physicsConfig.backend = "physx";
physicsConfig.gravity = glm::vec3(0, -9.81f, 0);
physicsConfig.pvd_host = "127.0.0.1";
physicsConfig.pvd_port = 5425;
physicsConfig.pvd_timeout = 5;
physicsSystem.content = physicsConfig;
config.systems.push_back(physicsSystem);

// Resource directory configuration
config.resources.directory = "assets/";

// Serialization format
config.serialization.format = SerializationFormat::Json;

// Create project and set as active
Ref<Project> project = Project::create(config);
project_manager()->add_project(project);  // Automatically sets as active

Loading an Existing Project

WARNING

The Project::load() method is currently not implemented (commented out in source). Project loading is done through the serializer directly.

Load a project from file:

cpp
#include <astralix/modules/project/project.hpp>
#include <astralix/modules/project/managers/project-manager.hpp>
#include <astralix/modules/project/serializers/project-serializer.hpp>
#include <astralix/modules/streams/adapters/file/file-stream-reader.hpp>
#include <astralix/modules/streams/adapters/json/json-serialization-context.hpp>

using namespace astralix;

// Create empty project with directory path
ProjectConfig config;
config.directory = "MyGame/";
config.manifest = "project.json";
Ref<Project> project = Project::create(config);

// Deserialize from file
StreamBuffer buffer;
FileStreamReader reader("MyGame/project.json");
reader.read(buffer);

Ref<SerializationContext> ctx = std::make_shared<JsonSerializationContext>(buffer);
ProjectSerializer serializer(project, ctx);
serializer.deserialize();

// Set as active
project_manager()->add_project(project);

// Access project data
std::string name = project->get_config().name;
std::string directory = project->get_config().directory;
std::string resourcesDir = project->get_config().resources.directory;

Resolving Asset Paths

Use the Path class and PathManager to resolve project-relative paths:

cpp
#include <astralix/modules/project/path.hpp>
#include <astralix/modules/project/managers/path-manager.hpp>

using namespace astralix;

// Create a project-relative path
Ref<Path> texturePath = Path::create("textures/wall.png", BaseDirectory::Project);

// Resolve to absolute filesystem path
std::filesystem::path absolutePath = path_manager()->resolve(texturePath);

// Or use user-defined literals for convenience
auto scenePath = "scenes/MainMenu.ascene"_project;
auto shaderPath = "shaders/default.axsl"_engine;

// Resolve paths
std::filesystem::path sceneAbsolute = path_manager()->resolve(scenePath);
std::filesystem::path shaderAbsolute = path_manager()->resolve(shaderPath);

// Project paths resolve relative to: project_directory + resources_directory
// Engine paths resolve relative to: ASTRALIX_ASSETS_DIR (compile-time constant)

Accessing Configuration

Read and modify project configuration:

cpp
#include <astralix/modules/project/managers/project-manager.hpp>

using namespace astralix;

Ref<Project> project = active_project();
ProjectConfig& config = project->get_config();

// Read window settings
if (!config.windows.empty()) {
    int width = config.windows[0].width;
    int height = config.windows[0].height;
    std::string title = config.windows[0].title;
}

// Read system configurations
for (const auto& system : config.systems) {
    if (system.type == SystemType::Physics) {
        if (std::holds_alternative<PhysicsSystemConfig>(system.content)) {
            const auto& physicsConfig = std::get<PhysicsSystemConfig>(system.content);
            glm::vec3 gravity = physicsConfig.gravity;
        }
    } else if (system.type == SystemType::Render) {
        if (std::holds_alternative<RenderSystemConfig>(system.content)) {
            const auto& renderConfig = std::get<RenderSystemConfig>(system.content);
            int msaaSamples = renderConfig.msaa.samples;
            bool msaaEnabled = renderConfig.msaa.is_enabled;
        }
    }
}

// Modify settings
for (auto& system : config.systems) {
    if (system.type == SystemType::Render) {
        if (std::holds_alternative<RenderSystemConfig>(system.content)) {
            auto& renderConfig = std::get<RenderSystemConfig>(system.content);
            renderConfig.msaa.samples = 8;
            renderConfig.msaa.is_enabled = true;
        }
    }
}

// Save changes
ElasticArena arena;
project->save(arena);

Application Integration

Initialize application with project:

cpp
#include <astralix/modules/project/project.hpp>
#include <astralix/modules/project/managers/project-manager.hpp>
#include <astralix/modules/project/serializers/project-serializer.hpp>
#include <astralix/modules/streams/adapters/file/file-stream-reader.hpp>
#include <astralix/modules/streams/adapters/json/json-serialization-context.hpp>

using namespace astralix;

int main(int argc, char** argv) {
    // Parse project path from command line
    std::string projectPath = "MyGame/project.json";
    if (argc > 1) {
        projectPath = argv[1];
    }

    // Create and load project
    ProjectConfig config;
    config.directory = std::filesystem::path(projectPath).parent_path().string() + "/";
    config.manifest = std::filesystem::path(projectPath).filename().string();

    Ref<Project> project = Project::create(config);

    // Deserialize project manifest
    StreamBuffer buffer;
    FileStreamReader reader(projectPath);
    reader.read(buffer);

    Ref<SerializationContext> ctx = std::make_shared<JsonSerializationContext>(buffer);
    ProjectSerializer serializer(project, ctx);
    serializer.deserialize();

    // Set as active project
    project_manager()->add_project(project);

    // Systems can now access project configuration via active_project()
    // Engine modules use path_manager() to resolve project-relative paths

    return 0;
}

Asset Management Helpers

Create helper functions for common operations:

cpp
#include <astralix/modules/project/path.hpp>
#include <astralix/modules/project/managers/path-manager.hpp>

using namespace astralix;

class AssetManager {
public:
    static std::filesystem::path GetTexturePath(const std::string& name) {
        auto path = Path::create("textures/" + name, BaseDirectory::Project);
        return path_manager()->resolve(path);
    }

    static std::filesystem::path GetModelPath(const std::string& name) {
        auto path = Path::create("models/" + name, BaseDirectory::Project);
        return path_manager()->resolve(path);
    }

    static std::filesystem::path GetScenePath(const std::string& name) {
        auto path = Path::create("scenes/" + name, BaseDirectory::Project);
        return path_manager()->resolve(path);
    }

    // Example with user-defined literals
    static std::filesystem::path GetShaderPath(const std::string& name) {
        auto path = ("shaders/" + name)._engine;  // Engine-relative shader
        return path_manager()->resolve(path);
    }
};

// Usage
auto texturePath = AssetManager::GetTexturePath("wall.png");
auto modelPath = AssetManager::GetModelPath("character.gltf");
auto scenePath = AssetManager::GetScenePath("MainMenu.ascene");

Project Templates

Create project templates for different game types:

cpp
#include <astralix/modules/project/project.hpp>
#include <astralix/modules/project/managers/project-manager.hpp>

using namespace astralix;

class ProjectTemplate {
public:
    static Ref<Project> Create2DProject(const std::string& name, const std::string& directory) {
        ProjectConfig config;
        config.name = name;
        config.directory = directory;
        config.manifest = "project.json";

        // Window configuration
        WindowConfig window;
        window.id = 0;
        window.title = name;
        window.width = 1280;
        window.height = 720;
        window.headless = false;
        config.windows.push_back(window);

        // 2D Renderer (no MSAA, simpler config)
        SystemConfig renderSystem;
        renderSystem.name = "RenderSystem";
        renderSystem.type = SystemType::Render;
        RenderSystemConfig renderConfig;
        renderConfig.backend = "opengl";
        renderConfig.msaa.samples = 1;
        renderConfig.msaa.is_enabled = false;
        renderConfig.window_id = "0";
        renderSystem.content = renderConfig;
        config.systems.push_back(renderSystem);

        // Physics with no gravity for 2D
        SystemConfig physicsSystem;
        physicsSystem.name = "PhysicsSystem";
        physicsSystem.type = SystemType::Physics;
        PhysicsSystemConfig physicsConfig;
        physicsConfig.backend = "physx";
        physicsConfig.gravity = glm::vec3(0);
        physicsSystem.content = physicsConfig;
        config.systems.push_back(physicsSystem);

        config.resources.directory = "assets/";
        config.serialization.format = SerializationFormat::Json;

        return Project::create(config);
    }

    static Ref<Project> Create3DProject(const std::string& name, const std::string& directory) {
        ProjectConfig config;
        config.name = name;
        config.directory = directory;
        config.manifest = "project.json";

        WindowConfig window;
        window.id = 0;
        window.title = name;
        window.width = 1920;
        window.height = 1080;
        window.headless = false;
        config.windows.push_back(window);

        // 3D Renderer with MSAA
        SystemConfig renderSystem;
        renderSystem.name = "RenderSystem";
        renderSystem.type = SystemType::Render;
        RenderSystemConfig renderConfig;
        renderConfig.backend = "opengl";
        renderConfig.msaa.samples = 4;
        renderConfig.msaa.is_enabled = true;
        renderConfig.window_id = "0";
        renderSystem.content = renderConfig;
        config.systems.push_back(renderSystem);

        // Physics with standard gravity
        SystemConfig physicsSystem;
        physicsSystem.name = "PhysicsSystem";
        physicsSystem.type = SystemType::Physics;
        PhysicsSystemConfig physicsConfig;
        physicsConfig.backend = "physx";
        physicsConfig.gravity = glm::vec3(0, -9.81f, 0);
        physicsSystem.content = physicsConfig;
        config.systems.push_back(physicsSystem);

        config.resources.directory = "assets/";
        config.serialization.format = SerializationFormat::Json;

        return Project::create(config);
    }

    static Ref<Project> CreateVRProject(const std::string& name, const std::string& directory) {
        ProjectConfig config;
        config.name = name;
        config.directory = directory;
        config.manifest = "project.json";

        WindowConfig window;
        window.id = 0;
        window.title = name;
        window.width = 1920;
        window.height = 1080;
        window.headless = false;
        config.windows.push_back(window);

        // VR Renderer with high MSAA
        SystemConfig renderSystem;
        renderSystem.name = "RenderSystem";
        renderSystem.type = SystemType::Render;
        RenderSystemConfig renderConfig;
        renderConfig.backend = "opengl";
        renderConfig.msaa.samples = 8;
        renderConfig.msaa.is_enabled = true;
        renderConfig.window_id = "0";
        renderSystem.content = renderConfig;
        config.systems.push_back(renderSystem);

        SystemConfig physicsSystem;
        physicsSystem.name = "PhysicsSystem";
        physicsSystem.type = SystemType::Physics;
        PhysicsSystemConfig physicsConfig;
        physicsConfig.backend = "physx";
        physicsConfig.gravity = glm::vec3(0, -9.81f, 0);
        physicsSystem.content = physicsConfig;
        config.systems.push_back(physicsSystem);

        config.resources.directory = "assets/";
        config.serialization.format = SerializationFormat::Json;

        return Project::create(config);
    }
};

Saving Configuration Changes

Update and persist configuration:

cpp
#include <astralix/modules/project/managers/project-manager.hpp>

using namespace astralix;

struct GraphicsSettings {
    int msaaSamples;
    bool msaaEnabled;
    std::string backend;
};

void UpdateGraphicsSettings(const GraphicsSettings& settings) {
    Ref<Project> project = active_project();
    ProjectConfig& config = project->get_config();

    // Find and update render system config
    for (auto& system : config.systems) {
        if (system.type == SystemType::Render) {
            if (std::holds_alternative<RenderSystemConfig>(system.content)) {
                auto& renderConfig = std::get<RenderSystemConfig>(system.content);
                renderConfig.msaa.samples = settings.msaaSamples;
                renderConfig.msaa.is_enabled = settings.msaaEnabled;
                renderConfig.backend = settings.backend;
            }
        }
    }

    // Save to file (note: save() requires ElasticArena)
    ElasticArena arena;
    project->save(arena);
}

Next Steps

  • Learn about Streams for serialization
  • Explore Application for initialization
  • Review project file format in the documentation