Wicked Engine Documentation

repository·master·Indexed 27 days ago

https://github.com/turanszkij/wickedengine

A high-performance, real-time graphics engine for high-fidelity rendering. Features include C++ and Lua scripting support, a dedicated Editor, and cross-platform builds for Windows, Linux, macOS, and iOS. Documentation covers engine initialization, scene and audio management, WISCENE model import/export, and detailed integration with metal-cpp for Apple platforms.

Tokens
48.7K
Snippets
78
Records
258
Agent score
93%

What's inside Wicked Engine

  1. Introduction to Wicked Engine Scripting

    master

    Wicked Engine uses Lua for scripting. You can execute Lua scripts by loading files or by using the engine's scripting console, known as the BackLog.

    • Startup Script: The engine automatically attempts to load a file named startup.lua from the application's root directory upon startup. You can use this file for initial logic like loading content.
    • BackLog (Scripting Console): Press the HOME key to open the BackLog interface. Enter Lua commands and press ENTER to execute them. Press HOME again to exit. You can also use the dofile command within the BackLog to execute script files.
    • Object Inspection: You can inspect the properties and functionality of any object by calling getprops(YourObject) in the BackLog.
  2. Use Automatic Instancing for Performance

    master

    Wicked Engine automatically uses instanced rendering for ObjectComponents that share the same mesh. This batches objects into a single draw call even if they have different transformations, colors, or dithering parameters, significantly reducing CPU overhead for duplicated objects like trees or rocks.

    Note on Stencil Overrides: If multiple ObjectComponents share a mesh but use different stencil overrides, they may be removed from the instanced batch, incurring overhead.

  3. Build and link Wicked Engine as a static library

    master

    Wicked Engine is a static library that you include and link into your C++ application.

    Windows Setup

    1. Open WickedEngine.sln in Visual Studio.
    2. Build the WickedEngine_Windows project.
    3. In your application's build system:
      • Add $(SolutionDir)WickedEngine to your "additional include directories".
      • Add $(SolutionDir)BUILD/$(Platform)/$(Configuration) to your "additional library directories".
      • Include #include "WickedEngine.h" in your code.

    Linux Setup

    1. Install dependencies:
    sudo apt update
    sudo apt install libsdl2-dev build-essential
    1. Build using cmake and make:
    mkdir build
    cd build
    cmake ..
    make
    1. Configure your application's build system to point to the resulting include and library directories as described in the Windows setup.

    If you encounter issues, refer to the Samples/Template projects for correct configuration examples.

    # Linux build commands
    mkdir build
    cd build
    cmake ..
    make
  4. Enable Autocomplete and Type Checking for Lua Scripts

    master

    You can get IntelliSense (autocomplete, signatures, and type checking) in editors like VS Code (using the sumneko.lua extension) by generating Lua Language Server (LuaLS) definitions from the Wicked Engine documentation.

    1. Generate the definitions

    Requires Python 3. Run the following command from the documentation directory:

    cd Content/Documentation/scripting_api
    python3 generate_stubs.py

    This creates wicked_engine_bindings.lua. To generate separate files per topic instead, use:

    python3 generate_stubs.py --split

    2. Install into your project

    Copy the generated wicked_engine_bindings.lua into your project directory (e.g., into a library/ folder).

    3. Configure .luarc.json

    Create a .luarc.json file at your project root to point the language server to the definitions:

    {
      "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
      "workspace": {
        "library": ["library/wicked_engine_bindings.lua"],
        "checkThirdParty": false
      },
      "runtime": {
        "version": "Lua 5.4"
      }
    }

    If your project uses custom globals that aren't defined in your scripts, add them to diagnostics.globals to prevent error reporting:

    "diagnostics": {
      "globals": [ "my_custom_global", "MY_CONSTANT" ]
    }
    cd Content/Documentation/scripting_api
    python3 generate_stubs.py
  5. Build Wicked Engine for Windows

    master

    To build the engine on Windows, use Visual Studio with the WickedEngine.sln solution file. Pressing F5 will build and start both the Wicked Engine and the Editor.

    To develop a custom C++ application using the engine:

    1. Build the WickedEngine_Windows static library project.
    2. Link against it in your project.
    3. Include the "WickedEngine.h" header.
    4. Set up additional library directories, for example: $(SolutionDir)BUILD\$(Platform)\$(Configuration).

    Alternatively, you can use CMake:

    cmake -B build
    cmake --build build --config Release
    cmake -B build
    cmake --build build --config Release
  6. Perform Async Compute with QUEUE_COMPUTE

    master

    You can perform asynchronous workloads on the compute queue using CommandList granularity.

    Usage

    Pass the QUEUE_TYPE parameter to BeginCommandList(). By default, work is executed on QUEUE_GRAPHICS.

    • QUEUE_GRAPHICS: The main queue; can execute both graphics and compute work.
    • QUEUE_COMPUTE: Can only execute compute work.
    • Fallback: If the API/device does not support async compute (e.g., DX11), QUEUE_GRAPHICS is used.

    Synchronization

    Use WaitCommandList(CommandList first, CommandList second) to insert a GPU dependency barrier. This makes first wait for second to finish. This is a GPU-side operation and does not block the CPU.

    Note on Resource States: The SHADER_RESOURCE state cannot be used on the compute queue. You must use SHADER_RESOURCE_COMPUTE as the starting state for resources used in a compute queue, and transition them back to SHADER_RESOURCE before use in a pixel shader.

    CommandList cmd0 = device->BeginCommandList(QUEUE_GRAPHICS);
    CommandList cmd1 = device->BeginCommandList(QUEUE_COMPUTE);
    device->WaitCommandList(cmd1, cmd0); // cmd1 waits for cmd0 to finish
    CommandList cmd2 = device->BeginCommandList(QUEUE_GRAPHICS);
    CommandList cmd3 = device->BeginCommandList(QUEUE_GRAPHICS);
    device->WaitCommandList(cmd3, cmd1); // cmd3 waits for cmd1 to finish
    
    device->SubmitCommandLists();
  7. Decode H264 Video on the GPU

    master

    To decode H264 video in real time, follow these steps:

    1. Prepare Bitstream: Provide H264 slice data in an UPLOAD GPUBuffer. Ensure the offset is aligned using GraphicsDevice::GetVideoDecodeBitstreamAlignment().
    2. Create Decoder: Initialize a VideoDecoder object with parsed H264 parameters (resolution, picture parameters, sequence parameters). The decode format must be Format::NV12.
    3. Setup DPB: Create a Decode Picture Buffer (DPB) as a texture array using Format::NV12. Set the misc_flags to ResourceMiscFlags::VIDEO_DECODE.
    4. Execute Decode: Call GraphicsDevice::VideoDecode() with the correct H264 arguments and DPB picture indices.
    5. Access Data: Manually read from the DPB texture (e.g., in a shader) and resolve the YUV format to RGB if necessary.
  8. Use the Entity-Component System (ECS)

    master

    Wicked Engine uses an Entity-Component System where an Entity is a unique identifier (number) and data is stored in ComponentManager<T> containers. To bind data to an entity, you create a component within a manager associated with that entity ID.

    Key Concepts:

    • Entity: A unique ID. It does not require components to be valid.
    • ComponentManager<T>: Manages contiguous memory for components of type T.
    • Memory Safety:
      • Pointer/Index Invalidation: Adding or removing components can reallocate memory or change the order of elements (the manager is kept dense). Never store long-lived pointers or indices to components; always re-query using GetComponent(entity) or GetIndex(entity) after structural changes.
      • Array Operator: Do NOT use components[entity]. This is invalid and will cause undefined behavior or crashes. Use GetComponent(entity) instead.

    Iteration Patterns:

    • Linear Iteration: Use GetCount(), components[i], and components.GetEntity(i) to iterate through all components and their associated entities in order.
    • Random Access: Use GetComponent(entity) to find a component for a specific entity, or GetIndex(entity) to find its current position in the contiguous array.
    struct MyComponent
    {
    	float3 position;
    	float speed;
    };
    ComponentManager<MyComponent> components; // create a component manager
    Entity entity = CreateEntity(); // create a new entity ID
    MyComponent& component = components.Create(entity); // create a component and bind it to the entity
    
    // To query a component for a given entity:
    MyComponent* component = components.GetComponent(entity);
    if(component != nullptr) 
    {
    	// use component
    }
    
    // To get the index of an entity:
    size_t index = components.GetIndex(entity);
    if(index != INVALID_INDEX) 
    {
    	MyComponent& component = components[index];
    }
  9. Initialize and run the Application class

    master

    The Application class is the main runtime component. It manages the engine lifecycle, including initialization, the main loop, and RenderPath management.

    To use it, you must provide an operating system window handle via SetWindow(). It is highly recommended to call Initialize() explicitly if you intend to use engine features (like LoadModel) before the first call to Run(), as calling them before initialization can lead to undefined behavior.

    To ensure all engine sub-systems are fully ready before proceeding, you can use wi::initializer::WaitForInitializationsToFinish() after calling Initialize().

    Application app;
    app.SetWindow(hWnd); // operating-system dependent window handle
    app.Initialize(); 
    // Block until all engine sub-systems are ready
    wi::initializer::WaitForInitializationsToFinish(); 
    
    LoadModel("something.wiscene");
    
    while(true)
    {
    	app.Run();
    }
  10. Import and Export Models

    master

    The native format for Wicked Engine is WISCENE. The Editor supports importing the following formats:

    • OBJ
    • FBX
    • GLTF, GLB
    • VRM, VRMA
    • PLY

    Workflow: Import models into the Editor, save them as .wiscene, and they can be used in any Wicked Engine application.