### Install Arch Linux/Manjaro Dependencies for Laigter Source: https://github.com/azagaya/laigter/blob/master/README.md Installs the Qt5 base package needed for compiling Laigter on Arch Linux and its derivatives like Manjaro. ```bash sudo pacman -Sy qt5-base ``` -------------------------------- ### Build Laigter from Terminal Source: https://github.com/azagaya/laigter/blob/master/README.md Compiles the Laigter project using qmake and make after dependencies are installed. Utilizes parallel processing for faster build times. ```bash mkdir build cd build qmake ../ make -j$(nproc) ``` -------------------------------- ### Install Fedora Dependencies for Laigter Source: https://github.com/azagaya/laigter/blob/master/README.md Installs required development libraries for compiling Laigter on Fedora systems. Uses dnf package manager. ```bash sudo dnf install qt5-devel mesa-libGL-devel ``` -------------------------------- ### Install Debian/Ubuntu Dependencies for Laigter Source: https://github.com/azagaya/laigter/blob/master/README.md Installs necessary packages for compiling Laigter on Debian-based systems like Ubuntu. Requires root privileges. ```bash sudo apt install qt5-default qt5-qmake libgl1-mesa-dev ``` -------------------------------- ### Headless Image Processing with ImageProcessor Source: https://context7.com/azagaya/laigter/llms.txt Minimal C++ example demonstrating headless usage of `ImageProcessor`. Loads a diffuse texture, configures map generation parameters, and saves the resulting maps. Ensure all necessary Qt modules and Laigter headers are included. ```cpp #include "src/image_processor.h" #include "src/image_loader.h" #include int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); ImageLoader il; bool ok = false; QImage diffuse = il.loadImage("sprite.png", &ok); if (!ok) return 1; diffuse = diffuse.convertToFormat(QImage::Format_RGBA8888_Premultiplied); ImageProcessor p; // Enable only the maps you need (saves time in headless mode) p.has_normal = true; p.has_parallax = true; p.has_specular = true; p.has_occlusion = true; // Tune normal-map parameters before loading p.set_normal_depth(250); // surface "height" strength (1–500) p.set_normal_blur_radius(6); // pre-blur radius for smooth gradients p.set_normal_bisel_depth(100); // edge bevel depth p.set_normal_bisel_distance(60); // edge bevel reach in pixels p.set_normal_bisel_soft(true); // soft (curved) bevel falloff // Tune parallax parameters p.set_parallax_type(ParallaxType::Binary); p.set_parallax_thresh(140); // luminance threshold p.set_parallax_focus(2); // pre-blur before thresholding p.set_parallax_soft(3); // post-blur after thresholding p.set_parallax_invert(false); // Tune specular parameters p.set_specular_thresh(127); p.set_specular_blur(3); p.set_specular_bright(0); p.set_specular_contrast(1000); // value / 1000.0 internally // Tune occlusion parameters p.set_occlusion_distance_mode(true); p.set_occlusion_distance(10); p.set_occlusion_blur(3); p.set_occlusion_thresh(1); // loadImage triggers calculate() synchronously when timer is stopped p.recalculate_timer.stop(); p.loadImage("sprite.png", diffuse); p.calculate(); // blocks until all maps are ready p.get_normal() ->save("sprite_n.png"); p.get_parallax() ->save("sprite_p.png"); p.get_specular() ->save("sprite_s.png"); p.get_occlusion()->save("sprite_o.png"); return 0; } // Output files: sprite_n.png, sprite_p.png, sprite_s.png, sprite_o.png ``` -------------------------------- ### Run Laigter from Command Line (macOS) Source: https://github.com/azagaya/laigter/blob/master/README.md Executes Laigter with specified options after it has been symlinked to a PATH directory. This example exports multiple textures using a custom preset. ```bash laigter --no-gui -d ".png" --r "" -n -c -o -p ``` -------------------------------- ### Example: Export Multiple Textures (Custom Preset) Source: https://github.com/azagaya/laigter/blob/master/README.md Exports normals, specular, occlusion, and parallax textures from the specified diffuse texture using a custom preset profile. Assumes Laigter is in the system PATH or the full path is provided. ```bash /laigter.exe --no-gui -d ".png" --r "" -n -c -o -p ``` -------------------------------- ### Example: Export Multiple Textures (Default Profile) Source: https://github.com/azagaya/laigter/blob/master/README.md Exports normals, specular, occlusion, and parallax textures from the specified diffuse texture using the default profile. Assumes Laigter is in the system PATH or the full path is provided. ```bash /laigter.exe --no-gui -d ".png" -n -c -o -p ``` -------------------------------- ### Example: Export Normals Texture (Default Profile) Source: https://github.com/azagaya/laigter/blob/master/README.md Exports a normals texture from the specified diffuse texture using the default profile. Assumes Laigter is in the system PATH or the full path is provided. ```bash /laigter.exe --no-gui -d ".png" -n ``` -------------------------------- ### Loading Diffuse Texture with ImageProcessor Source: https://context7.com/azagaya/laigter/llms.txt Example of loading a diffuse texture using `ImageProcessor::loadImage`. This initializes the sprite and starts the asynchronous recalculation timer. Connect to the `processed()` signal to handle updated maps. ```cpp ImageProcessor p; bool ok = false; QImage img = ImageLoader::loadImage("/assets/wall.png", &ok); if (ok) { img = img.convertToFormat(QImage::Format_RGBA8888_Premultiplied); int result = p.loadImage("/assets/wall.png", img); // result == 0 on success // Recalculation timer is now running; maps computed asynchronously. // Connect p.processed() signal to consume updated maps: QObject::connect(&p, &ImageProcessor::processed, [&]() { QImage *nm = p.get_normal(); nm->save("/out/wall_n.png"); }); } ``` -------------------------------- ### Symlink Laigter Binary on macOS Source: https://github.com/azagaya/laigter/blob/master/README.md Creates a symbolic link for the Laigter binary to a location in the system's PATH, allowing it to be run from anywhere. Replace `/Applications` with the actual path if Laigter is installed elsewhere. ```bash sudo ln -s /Applications/laigter.app/Contents/MacOS/laigter /usr/local/bin ``` -------------------------------- ### Configure LightSource for OpenGL Preview Source: https://context7.com/azagaya/laigter/llms.txt Set up a LightSource with position, color, intensity, and animation for the real-time OpenGL preview. Attach the configured light source to an ImageProcessor or the OpenGL widget. ```cpp LightSource light; // Position: x, y in normalized device coordinates; z = height above surface [0,1] light.set_light_position(QVector3D(0.5f, 0.5f, 0.3f)); // Diffuse (main) light light.set_diffuse_color(QColor(255, 230, 180)); // warm white light.set_diffuse_intensity(1.2f); // Specular highlight light.set_specular_color(QColor(255, 255, 255)); light.set_specular_intensity(0.8f); light.set_specular_scatter(0.4f); // higher = wider highlight // Animated orbit light.set_animate(true); light.set_speed(0.5f); // orbit speed multiplier // Attach to an ImageProcessor for the preview renderer QList lightList; lightList.append(&light); processor.set_light_list(lightList); // Or attach to the OpenGL widget directly // oglWidget->set_current_light_list(&lightList); ``` -------------------------------- ### Laigter Command Line Options Source: https://github.com/azagaya/laigter/blob/master/README.md Displays help on command line options for Laigter. Use --help-all for Qt specific options. ```bash ``` -?, -h, --help ``` Displays help on commandline options. ``` --help-all ``` Displays help including Qt specific options. ``` -v, --version ``` Displays version information. ``` -s, --software-opengl ``` Use software opengl renderer. ``` -g, --no-gui ``` Do not start graphical interface. ``` -d, --diffuse ``` Diffuse texture to load. ``` -n, --normal ``` Generate normals texture. ``` -c, --specular ``` Generate specular texture. ``` -o, --occlusion ``` Generate occlusion teture. ``` -p, --parallax ``` Generate parallax textures. ``` -r, --preset ``` Preset file to use for texture generation. ``` -------------------------------- ### Deploy Laigter Application on Windows Source: https://github.com/azagaya/laigter/blob/master/README.md This batch script deploys the Laigter application on Windows using windeployqt. Ensure the paths to the build directory and executable are correct. ```batch mkdir .\deploy windeployqt --dir .\deploy ..\build-laigter-Desktop_Qt_5_14_0_MinGW_32_bit-Release\release\laigter.exe copy /Y ..\build-laigter-Desktop_Qt_5_14_0_MinGW_32_bit-Release\release\laigter.exe .\deploy\laigter.exe ``` -------------------------------- ### Data Type Formatting Source: https://github.com/azagaya/laigter/blob/master/CONTRIBUTING.md Demonstrates the correct way to format floating-point literals. ```cpp float a_float = 0.1f; //always put number(s) before the decimal point ``` -------------------------------- ### Implement Custom Brushes with BrushInterface Plugin API Source: https://context7.com/azagaya/laigter/llms.txt Create custom brush tools for Laigter by implementing the BrushInterface in a Qt plugin. This allows plugins to receive mouse events and paint directly onto image processor overlays in real time. ```cpp // MyBrushPlugin.h — minimal BrushInterface implementation #include "src/brush_interface.h" #include "src/image_processor.h" #include class MyBrushPlugin : public QObject, public BrushInterface { Q_OBJECT Q_INTERFACES(BrushInterface) Q_PLUGIN_METADATA(IID BrushInterface_iid) ImageProcessor **m_processor = nullptr; bool m_selected = false; float m_pressure = 1.0f; public: void mousePress(const QPoint &pos) override { // Paint a white dot on the normal overlay at pos if (!m_processor || !*m_processor) return; QImage ov = (*m_processor)->get_normal_overlay(); QPainter p(&ov); p.setBrush(QColor(255, 128, 128, 200 * m_pressure)); p.drawEllipse(pos, 8, 8); p.end(); (*m_processor)->set_normal_overlay(ov); } void mouseMove(const QPoint &, const QPoint &newPos) override { mousePress(newPos); } void mouseRelease(const QPoint &) override {} void setPressure(float p) override { m_pressure = p; } bool get_selected() override { return m_selected; } void set_selected(bool s) override { m_selected = s; emit selected_changed(this); } QWidget *loadGUI(QWidget *parent) override { return new QWidget(parent); } void setProcessor(ImageProcessor **p) override { m_processor = p; } QString getIcon() override { return ":/icons/my_brush.png"; } QString getName() override { return "My Brush"; } QImage getBrushSprite() override { return QImage(); } QObject *getObject() override { return this; } signals: void selected_changed(BrushInterface *brush); }; // Compile as a Qt plugin shared library (.so/.dll/.dylib) and install via // Laigter → Plugins → Install Plugin ``` -------------------------------- ### Load Various Image Formats with ImageLoader Source: https://context7.com/azagaya/laigter/llms.txt Demonstrates loading single images, including TGA files, and handling potential loading failures. Supports all Qt-supported formats. ```cpp bool ok; // Load a single image (supports PNG, JPG, BMP, TGA, and all Qt-supported formats) QImage img = ImageLoader::loadImage("/sprites/tile.tga", &ok); if (!ok) qWarning() << "Failed to load image"; // Load a TGA file directly QImage tga = ImageLoader::loadTga("/sprites/character.tga", &ok); ``` -------------------------------- ### Clone Laigter Source Code Source: https://github.com/azagaya/laigter/blob/master/README.md Retrieves the Laigter source code from its GitHub repository using Git. This is the first step before compilation. ```bash git clone https://github.com/azagaya/laigter ``` -------------------------------- ### Save and Load Laigter Project Files Source: https://context7.com/azagaya/laigter/llms.txt Manage Laigter project files (.laigter), which are ZIP archives containing project settings and sprite images. This includes saving the current state and loading it back, automatically recalculating maps. ```cpp Project project; QList processorList; // --- Build processorList as usual, then save --- ImageProcessor *p1 = new ImageProcessor; bool ok; p1->loadImage("hero.png", ImageLoader::loadImage("hero.png", &ok)); p1->set_name("hero"); processorList.append(p1); QJsonObject generalSettings; generalSettings.insert("ambientLight", 0.3); generalSettings.insert("bgColor", "#222222"); bool saved = project.save("scene.laigter", processorList, generalSettings); qDebug() << "Saved:" << saved; // → true // --- Load back --- QList loadedProcessors; QJsonObject loadedGeneral; bool loaded = project.load("scene.laigter", &loadedProcessors, &loadedGeneral); qDebug() << "Loaded processors:" << loadedProcessors.count(); // → 1 qDebug() << "Ambient:" << loadedGeneral.value("general").toObject().value("ambientLight"); // All maps are recalculated from the restored diffuse + presets automatically loadedProcessors[0]->get_normal()->save("hero_n_restored.png"); ``` -------------------------------- ### Switch Statement Formatting Source: https://github.com/azagaya/laigter/blob/master/CONTRIBUTING.md Provides the required formatting for switch statements, including case blocks. ```cpp switch (var) { case 1: { //do stuff here break; } case 2: { //do stuff here break; } } ``` -------------------------------- ### CLI Batch Processing with Laigter Source: https://context7.com/azagaya/laigter/llms.txt Execute Laigter in batch mode using the --no-gui flag for automated processing of image files or directories. Options allow specifying map types, custom suffixes, recursive processing, and change detection. ```bash # Generate a normal map for a single file (default suffix _n) ./laigter --no-gui -d sprite.png -n # → sprite_n.png ``` ```bash # Generate all four maps with custom suffixes ./laigter --no-gui \ -d character.png \ -n --normal-suffix _normal \ -c --specular-suffix _spec \ -o --occlusion-suffix _occ \ -p --paralax-suffix _parallax # → character_normal.png character_spec.png # character_occ.png character_parallax.png ``` ```bash # Batch process a whole directory recursively with a preset ./laigter --no-gui \ -d ./assets/textures/ \ -n -c -o -p \ -r ./presets/stone.presets \ -l ./output/maps/ # → output/maps//_n.png etc. ``` ```bash # Batch process but skip files whose output maps are already up to date ./laigter --no-gui \ -d ./assets/ \ -n -p \ --check-changes \ --flatten \ -l ./out/ # --flatten: all outputs go directly into ./out/ (no subdirectory structure) # --not-recursive: process only the top-level directory ``` ```bash # macOS: symlink binary to PATH first sudo ln -s /Applications/laigter.app/Contents/MacOS/laigter /usr/local/bin laigter --no-gui -d texture.png -n -c -o -p ``` -------------------------------- ### CLI Batch Processing Source: https://context7.com/azagaya/laigter/llms.txt Command-line interface for batch processing images. ```APIDOC ## CLI Batch Processing — Command-Line Interface Laigter can run without a GUI using the `--no-gui` (`-g`) flag. This mode allows processing single files, lists of files, or entire directory trees, with options for applying presets and specifying output map types and suffixes. ### Basic Usage Generate a normal map for a single file with the default suffix `_n`. ```bash ./laigter --no-gui -d sprite.png -n # → sprite_n.png ``` ### Generating Multiple Map Types Generate all four map types (normal, specular, occlusion, parallax) with custom suffixes. ```bash ./laigter --no-gui \ -d character.png \ -n --normal-suffix _normal \ -c --specular-suffix _spec \ -o --occlusion-suffix _occ \ -p --paralax-suffix _parallax # → character_normal.png character_spec.png # character_occ.png character_parallax.png ``` ### Batch Processing a Directory with a Preset Recursively process all textures in a directory, apply a preset, and save the output maps to a specified location. ```bash ./laigter --no-gui \ -d ./assets/textures/ \ -n -c -o -p \ -r ./presets/stone.presets \ -l ./output/maps/ # → output/maps//_n.png etc. ``` ### Conditional Batch Processing Batch process a directory, skipping files if their output maps are already up-to-date. Includes options for flattening the output directory structure and controlling recursion. ```bash ./laigter --no-gui \ -d ./assets/ \ -n -p \ --check-changes \ --flatten \ -l ./out/ # --flatten: all outputs go directly into ./out/ (no subdirectory structure) # --not-recursive: process only the top-level directory ``` ### macOS Symlink Example On macOS, you can symlink the Laigter binary to your PATH for easier command-line access. ```bash # Symlink binary to PATH first sudo ln -s /Applications/laigter.app/Contents/MacOS/laigter /usr/local/bin laigter --no-gui -d texture.png -n -c -o -p ``` ``` -------------------------------- ### BrushInterface Source: https://context7.com/azagaya/laigter/llms.txt Plugin API for creating custom overlay brushes. ```APIDOC ## `BrushInterface` — Plugin API for Custom Overlay Brushes Third-party Qt plugins can implement `BrushInterface` to add custom brush tools to Laigter's overlay-painting system. These plugins receive mouse/tablet events and paint directly onto an `ImageProcessor`'s overlay images, which are then composited into the generated maps in real time. ### `MyBrushPlugin` Example A minimal implementation of `BrushInterface` demonstrating how to create a custom brush plugin. ```cpp // MyBrushPlugin.h — minimal BrushInterface implementation #include "src/brush_interface.h" #include "src/image_processor.h" #include class MyBrushPlugin : public QObject, public BrushInterface { Q_OBJECT Q_INTERFACES(BrushInterface) Q_PLUGIN_METADATA(IID BrushInterface_iid) ImageProcessor **m_processor = nullptr; bool m_selected = false; float m_pressure = 1.0f; public: // Called when the mouse button is pressed. void mousePress(const QPoint &pos) override { // Paint a white dot on the normal overlay at pos if (!m_processor || !*m_processor) return; QImage ov = (*m_processor)->get_normal_overlay(); QPainter p(&ov); p.setBrush(QColor(255, 128, 128, 200 * m_pressure)); p.drawEllipse(pos, 8, 8); p.end(); (*m_processor)->set_normal_overlay(ov); } // Called when the mouse is moved. void mouseMove(const QPoint &, const QPoint &newPos) override { mousePress(newPos); } // Called when the mouse button is released. void mouseRelease(const QPoint &) override {} // Sets the pressure value, typically from a tablet. void setPressure(float p) override { m_pressure = p; } // Returns whether the brush is currently selected. bool get_selected() override { return m_selected; } // Sets the selected state of the brush. void set_selected(bool s) override { m_selected = s; emit selected_changed(this); } // Loads the brush's GUI widget. QWidget *loadGUI(QWidget *parent) override { return new QWidget(parent); } // Sets the ImageProcessor instance for the brush. void setProcessor(ImageProcessor **p) override { m_processor = p; } // Returns the path to the brush's icon. QString getIcon() override { return ":/icons/my_brush.png"; } // Returns the name of the brush. QString getName() override { return "My Brush"; } // Returns the brush sprite (currently empty). QImage getBrushSprite() override { return QImage(); } // Returns the QObject pointer for the plugin. QObject *getObject() override { return this; } signals: // Signal emitted when the selected state changes. void selected_changed(BrushInterface *brush); }; // Compile as a Qt plugin shared library (.so/.dll/.dylib) and install via // Laigter → Plugins → Install Plugin ``` ``` -------------------------------- ### Include Statement Format Source: https://github.com/azagaya/laigter/blob/master/CONTRIBUTING.md Defines the preferred order and formatting for include statements in C++ code. ```cpp //include files #include "filename.h" //include std lib #include //include QT lib #include Qtxxxxx ``` -------------------------------- ### Paint Custom Normal Overlay with ImageProcessor Source: https://context7.com/azagaya/laigter/llms.txt Use QPainter to draw custom normal directions onto an overlay image. The ImageProcessor automatically re-composites this overlay when generating the final normal map. ```cpp ImageProcessor p; bool ok; QImage diffuse = ImageLoader::loadImage("character.png", &ok); p.loadImage("character.png", diffuse); p.recalculate_timer.stop(); p.calculate(); // Read back the current overlay QImage normalOv = p.get_normal_overlay(); // RGBA, initially all transparent // Paint a custom normal direction onto a 16x16 region (pointing right: +X) QPainter painter(&normalOv); QColor rightNormal(255, 128, 128, 255); // R=1, G=0.5, B=0.5 → (+1, 0, 0) painter.fillRect(QRect(10, 10, 16, 16), rightNormal); painter.end(); // Push the overlay back; the normal map is automatically re-composited p.set_normal_overlay(normalOv); p.generate_normal_map(true, true, true); // Result: the painted region has the manually specified normal direction p.get_normal()->save("character_n_painted.png"); // Similarly for heightmap overlay (controls bevel/distance normals) QImage heightOv = p.get_heightmap_overlay(); // ... paint height information ... p.set_heightmap_overlay(heightOv); ``` -------------------------------- ### Operator Formatting Source: https://github.com/azagaya/laigter/blob/master/CONTRIBUTING.md Shows the standard formatting for common operators in C++. ```cpp char assignment = 'a'; int add = 1 + 1; int sub = 1 - 1; int mul = 1*1; int div = 1/1; ``` -------------------------------- ### PresetsManager Source: https://context7.com/azagaya/laigter/llms.txt Utilities for saving and applying image processing presets. ```APIDOC ## `PresetsManager` — Save and Apply Processing Presets Presets store all 34 map-generation parameters of an `ImageProcessor` in a plain-text file. They can be applied to any processor to instantly reproduce a look, and are also embedded in project files. The static helpers work without a GUI. ### Save All Presets Saves all current settings of a processor to a .presets file. ```cpp PresetsManager::SaveAllPresets(processor, "/presets/stone_wall.presets"); ``` ### Apply Presets from File Applies a preset file to a processor. This is useful for GUI-less operations like CLI batch mode. ```cpp QString path = "/presets/stone_wall.presets"; PresetsManager::applyPresets(path, *processor); processor->calculate(); // re-run with restored settings ``` ### Apply Preset Settings from Raw Data Applies preset settings directly from raw byte data, typically used when loading from a project ZIP file. ```cpp QByteArray presetData = /* read from zip */ QByteArray(); PresetsManager::applyPresetSettings(presetData, *processor); ``` ### Preset Parameter Mapping Preset codes (indices 0–33) map to specific parameters. For a full list, refer to `PresetsManager::get_preset_codes()`. ``` // Example mappings: // [0] normal_depth [8] parallax_type // [1] normal_blur_radius [9] parallax_max (thresh) // [2] normal_bisel_depth [10] parallax_min // [3] normal_bisel_distance [11] specular_thresh ``` ``` -------------------------------- ### Load Custom Height and Specular Maps Source: https://context7.com/azagaya/laigter/llms.txt Override auto-derived height and specular information by providing custom grayscale images. The processor scales the input to match sprite size and recalculates maps. Providing the same path as the diffuse texture resets to auto-derivation. ```cpp ImageProcessor p; bool ok; QImage diffuse = ImageLoader::loadImage("brick.png", &ok); QImage heightmap = ImageLoader::loadImage("brick_h.png", &ok); // custom height QImage specBase = ImageLoader::loadImage("brick_s.png", &ok); // custom specular base p.loadImage("brick.png", diffuse); // Override auto-derived height with an explicit grayscale heightmap p.loadHeightMap("brick_h.png", heightmap); // path == diffuse path → resets to auto-derive from diffuse // Override specular base p.loadSpecularMap("brick_s.png", specBase); // Retrieve resulting normal map (uses the custom height data) p.get_normal()->save("brick_n.png"); ``` -------------------------------- ### Save and Apply Image Processing Presets with PresetsManager Source: https://context7.com/azagaya/laigter/llms.txt Use PresetsManager to save current image processor settings to a file or apply them from a file or raw data. The applyPresets function is useful for GUI-less operations like CLI batch mode. ```cpp // Save all current settings of a processor to a .presets file PresetsManager::SaveAllPresets(processor, "/presets/stone_wall.presets"); ``` ```cpp // Apply a preset file to a processor (GUI-less, used in CLI batch mode) QString path = "/presets/stone_wall.presets"; PresetsManager::applyPresets(path, *processor); processor->calculate(); // re-run with restored settings ``` ```cpp // Apply from a raw string (used when loading from a project ZIP) QByteArray presetData = /* read from zip */ QByteArray(); PresetsManager::applyPresetSettings(presetData, *processor); ``` -------------------------------- ### Enable Seamless Tiling Mode Source: https://context7.com/azagaya/laigter/llms.txt Enable tileable mode to ensure textures wrap correctly across edges, producing seamless results. This mode reconstructs a 3x3 canvas of the texture before calculations. Note that `set_tile_x` and `set_tile_y` control OpenGL preview tiling, not map generation. ```cpp ImageProcessor p; bool ok; QImage grass = ImageLoader::loadImage("grass.png", &ok); p.loadImage("grass.png", grass); p.recalculate_timer.stop(); // Enable tileability p.set_tileable(true); // rebuilds neighbour canvas + triggers full recalc p.calculate(); // The produced maps can be tiled edge-to-edge without seams p.get_normal()->save("grass_n_tileable.png"); // Individual axis tiling (for preview only, not map generation) p.set_tile_x(true); p.set_tile_y(true); // ^ These control the OpenGL preview tiling, not map calculation ``` -------------------------------- ### Load Animated Image Frames with ImageLoader Source: https://context7.com/azagaya/laigter/llms.txt Loads all frames from an animated image format like GIF or APNG. Useful for sprite sheet discovery and animation sequences. ```cpp // Load all frames of an animated image format (e.g. animated GIF/APNG) QList frames = ImageLoader::loadImages("/sprites/explosion.png"); qDebug() << "Frame count:" << frames.count(); ``` -------------------------------- ### Class Declaration Format Source: https://github.com/azagaya/laigter/blob/master/CONTRIBUTING.md Specifies the formatting for class declarations, including member variables and methods. ```cpp class Name { //member variables first public: int m_var; private: int m_var2; //methods public: Name(); ~Name(); //other (protected, slots, etc etc) } ``` -------------------------------- ### ImageProcessor::loadHeightMap and ImageProcessor::loadSpecularMap Source: https://context7.com/azagaya/laigter/llms.txt Allows users to supply dedicated grayscale maps for height and specular information instead of deriving them from the diffuse texture's luminance. Both methods scale the provided image to match the sprite size and trigger a full recalculation. ```APIDOC ## `ImageProcessor::loadHeightMap` / `loadSpecularMap` — Custom Input Maps Allows users to supply dedicated grayscale maps for height and specular information instead of deriving them from the diffuse texture's luminance. Both methods scale the provided image to match the sprite size and trigger a full recalculation. ### Method - `loadHeightMap(const QString &path, const QImage &image)` - `loadSpecularMap(const QString &path, const QImage &image)` ### Parameters #### `loadHeightMap` - **path** (QString) - The path of the image, used for comparison to reset to auto-derivation. - **image** (QImage) - The custom height map image. #### `loadSpecularMap` - **path** (QString) - The path of the image. - **image** (QImage) - The custom specular base image. ### Request Example ```cpp ImageProcessor p; bool ok; QImage diffuse = ImageLoader::loadImage("brick.png", &ok); QImage heightmap = ImageLoader::loadImage("brick_h.png", &ok); // custom height QImage specBase = ImageLoader::loadImage("brick_s.png", &ok); // custom specular base p.loadImage("brick.png", diffuse); // Override auto-derived height with an explicit grayscale heightmap p.loadHeightMap("brick_h.png", heightmap); // path == diffuse path → resets to auto-derive from diffuse // Override specular base p.loadSpecularMap("brick_s.png", specBase); ``` ### Response This method modifies the internal state of the `ImageProcessor` and does not return a direct value. The effect is seen in the generated normal map. ``` -------------------------------- ### Statement Codeblock Formatting Source: https://github.com/azagaya/laigter/blob/master/CONTRIBUTING.md Illustrates the required formatting for code blocks associated with control flow statements like if, for, and while, as well as function definitions. ```cpp if (statement) { } else { } for (int i = 0; i <= 10; i++) { } void foo() { } ``` -------------------------------- ### ImageProcessor::set_tileable Source: https://context7.com/azagaya/laigter/llms.txt Enables tileable mode, which processes the texture by building a 3x3 canvas of neighbors to ensure gradient calculations wrap correctly at tile edges, resulting in a seamless texture. ```APIDOC ## `ImageProcessor::set_tileable` — Seamless / Tileable Mode When tileable mode is enabled, the processor builds a 3×3 canvas of the texture (the "neighbours" image) before computing all maps, so gradient calculations at tile edges wrap correctly across boundaries. The result is a seamless texture that tiles without visible seams. ### Method - `set_tileable(bool enable)` - `set_tile_x(bool enable)` - `set_tile_y(bool enable)` ### Parameters - **enable** (bool) - `true` to enable tileable mode, `false` to disable. ### Request Example ```cpp ImageProcessor p; bool ok; QImage grass = ImageLoader::loadImage("grass.png", &ok); p.loadImage("grass.png", grass); p.recalculate_timer.stop(); // Enable tileability p.set_tileable(true); // rebuilds neighbour canvas + triggers full recalc p.calculate(); // The produced maps can be tiled edge-to-edge without seams p.get_normal()->save("grass_n_tileable.png"); // Individual axis tiling (for preview only, not map generation) p.set_tile_x(true); p.set_tile_y(true); // ^ These control the OpenGL preview tiling, not map calculation ``` ### Response This method modifies the internal state of the `ImageProcessor` to enable or disable tileable mode. The effect is visible in the generated maps and the OpenGL preview. ``` -------------------------------- ### Upscale Images to Match Maximum Size Source: https://context7.com/azagaya/laigter/llms.txt Iterates through a list of images and upscales any smaller frames to match the determined maximum bounding size, maintaining aspect ratio by expanding. ```cpp for (QImage &frame : frames) { // Upscale smaller frames to match the largest if (frame.size() != maxSize) frame = frame.scaled(maxSize, Qt::KeepAspectRatioByExpanding); } ``` -------------------------------- ### Calculate Maximum Image Size from a List Source: https://context7.com/azagaya/laigter/llms.txt Computes the maximum bounding size across a list of QImage objects. This is useful for normalizing sprite sheets to a common canvas size. ```cpp // Find the maximum bounding size across a set of images // (useful when normalizing sprite sheets to a common canvas size) QSize maxSize = ImageLoader::maxImagesSize(frames); qDebug() << "Max size:" << maxSize.width() << "x" << maxSize.height(); ``` -------------------------------- ### ImageProcessor::splitInFrames Source: https://context7.com/azagaya/laigter/llms.txt Supports sprite sheets by splitting them into an HxV grid of individual frames, each processed independently. Animation sequences can be defined on top of these frames. ```APIDOC ## `ImageProcessor::splitInFrames` — Sprite Sheet Support Splits a sprite sheet into an H×V grid of individual frames, each of which is processed independently. Animation sequences can be defined on top of frame collections, and the active frame is selectable at runtime. ### Method - `splitInFrames(int H, int V)` - `get_frame_count()` - `set_current_frame_id(int id)` - `getAnimation(const QString &name)` - `setCurrentAnimation(const QString &name)` - `setAnimationRate(int rate)` - `playAnimation(bool play)` ### Parameters #### `splitInFrames` - **H** (int) - The number of horizontal frames. - **V** (int) - The number of vertical frames. #### `set_current_frame_id` - **id** (int) - The index of the frame to set as current. #### `getAnimation` - **name** (QString) - The name of the animation to retrieve. #### `setCurrentAnimation` - **name** (QString) - The name of the animation to set as current. #### `setAnimationRate` - **rate** (int) - The animation playback rate in frames per second. #### `playAnimation` - **play** (bool) - `true` to start playback, `false` to stop. ### Request Example ```cpp ImageProcessor p; bool ok; QImage sheet = ImageLoader::loadImage("hero_walk.png", &ok); // 512×128, 4 frames wide p.loadImage("hero_walk.png", sheet); p.recalculate_timer.stop(); // Split into 4 horizontal × 1 vertical frames p.splitInFrames(4, 1); p.reset_neighbours(); // rebuilds neighbour canvas for all frames p.calculate(); // Access frame count and select a specific frame qDebug() << "Frames:" << p.get_frame_count(); // → 4 p.set_current_frame_id(2); // select frame index 2 p.get_normal()->save("hero_walk_frame2_n.png"); // Define and play an animation Animation *anim = p.getAnimation("Default"); anim->frames_id = {0, 1, 2, 3}; // all four walk frames p.setCurrentAnimation("Default"); p.setAnimationRate(8); // 8 fps p.playAnimation(true); // starts QTimer-driven frame cycling // connect p.frameChanged(int) to react to frame advances ``` ### Response This method modifies the internal state of the `ImageProcessor` to support sprite sheets and animations. The `get_frame_count()` method returns the total number of frames. Individual frames can be accessed and processed, and animations can be defined and played. ``` -------------------------------- ### Generate Normal Map with Fine-Grained Control Source: https://context7.com/azagaya/laigter/llms.txt Regenerate specific components of the normal map (emboss, bevel, distance) for fine-tuned updates. This is useful when only certain aspects of the texture properties have changed. The computation is OpenMP-parallelized and runs on a background thread. ```cpp // Fine-grained control: regenerate only specific sub-components ImageProcessor p; bool ok; p.loadImage("tile.png", ImageLoader::loadImage("tile.png", &ok)); p.recalculate_timer.stop(); p.calculate(); // initial full calculation // Later, only the emboss component changed (depth slider moved): p.set_normal_depth(300); // sets enhance_requested = true, normal_counter = 1 // Manually trigger regeneration of only emboss + distance (not bevel distance): p.generate_normal_map( /*updateEnhance=*/ true, // re-run emboss component /*updateBump=*/ false, // skip bevel recalc /*updateDistance=*/ false, // skip distance transform /*rect=*/ QRect(0, 0, 0, 0) // full image ); // Retrieve and inspect the RGB normal map (Z-up, packed [0,255]) QImage *nm = p.get_normal(); // Pixel (x,y) normal vector: // nx = (R/255.0) * 2 - 1 // ny = (G/255.0) * 2 - 1 // nz = (B/255.0) * 2 - 1 (always positive, Z-up) QColor c = nm->pixelColor(64, 64); float nx = c.redF() * 2.0f - 1.0f; float ny = c.greenF() * 2.0f - 1.0f; float nz = c.blueF() * 2.0f - 1.0f; qDebug() << "Normal at (64,64):" << nx << ny << nz; ``` -------------------------------- ### ImageProcessor::generate_normal_map Source: https://context7.com/azagaya/laigter/llms.txt Generates the normal map by combining an emboss normal, a bevel/distance normal, and an optional manual height-overlay normal. The computation is parallelized and runs on a background thread. ```APIDOC ## `ImageProcessor::generate_normal_map` — Normal Map Generation Generates the normal map by combining three components: an emboss normal (from luminance gradient), a bevel/distance normal (from edge distance transform), and an optional manual height-overlay normal. The computation runs on a background thread and is OpenMP-parallelized per pixel. Results are stored in the internal `Sprite` and broadcast via the `processed()` signal. ### Method - `generate_normal_map(bool updateEnhance, bool updateBump, bool updateDistance, const QRect &rect)` ### Parameters - **updateEnhance** (bool) - Whether to re-run the emboss component. - **updateBump** (bool) - Whether to re-run the bevel component. - **updateDistance** (bool) - Whether to re-run the distance transform. - **rect** (QRect) - The rectangle area to recalculate. A rect of (0, 0, 0, 0) indicates the full image. ### Request Example ```cpp // Fine-grained control: regenerate only specific sub-components ImageProcessor p; bool ok; p.loadImage("tile.png", ImageLoader::loadImage("tile.png", &ok)); p.recalculate_timer.stop(); p.calculate(); // initial full calculation // Later, only the emboss component changed (depth slider moved): p.set_normal_depth(300); // sets enhance_requested = true, normal_counter = 1 // Manually trigger regeneration of only emboss + distance (not bevel distance): p.generate_normal_map( /*updateEnhance=*/ true, // re-run emboss component /*updateBump=*/ false, // skip bevel recalc /*updateDistance=*/ false, // skip distance transform /*rect=*/ QRect(0, 0, 0, 0) // full image ); ``` ### Response This method modifies the internal state of the `ImageProcessor`. The result is the updated normal map, accessible via `get_normal()`. ``` -------------------------------- ### Sprite Sheet Support for Animation Source: https://context7.com/azagaya/laigter/llms.txt Split a sprite sheet into a grid of frames for independent processing and animation. This allows defining animation sequences and selecting frames at runtime. Ensure `reset_neighbours()` is called after splitting frames and before calculation. ```cpp ImageProcessor p; bool ok; QImage sheet = ImageLoader::loadImage("hero_walk.png", &ok); // 512×128, 4 frames wide p.loadImage("hero_walk.png", sheet); p.recalculate_timer.stop(); // Split into 4 horizontal × 1 vertical frames p.splitInFrames(4, 1); p.reset_neighbours(); // rebuilds neighbour canvas for all frames p.calculate(); // Access frame count and select a specific frame qDebug() << "Frames:" << p.get_frame_count(); // → 4 p.set_current_frame_id(2); // select frame index 2 p.get_normal()->save("hero_walk_frame2_n.png"); // Define and play an animation Animation *anim = p.getAnimation("Default"); anim->frames_id = {0, 1, 2, 3}; // all four walk frames p.setCurrentAnimation("Default"); p.setAnimationRate(8); // 8 fps p.playAnimation(true); // starts QTimer-driven frame cycling // connect p.frameChanged(int) to react to frame advances ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.