VOXCONVERT: added scripting support
|
@ -12,6 +12,7 @@ vengi (0.0.15.0-1) UNRELEASED; urgency=low
|
||||||
* Added option to keep the input file palette and don't perform quantization
|
* Added option to keep the input file palette and don't perform quantization
|
||||||
* Allow to export the palette to png
|
* Allow to export the palette to png
|
||||||
* Allow to generate models from heightmap images
|
* Allow to generate models from heightmap images
|
||||||
|
* Allow to run lua scripts to modify volumes
|
||||||
|
|
||||||
* Thumbnailer:
|
* Thumbnailer:
|
||||||
* Try to use the built-in palette for models
|
* Try to use the built-in palette for models
|
||||||
|
|
|
@ -18,6 +18,7 @@ VoxConvert:
|
||||||
- Added option to keep the input file palette and don't perform quantization
|
- Added option to keep the input file palette and don't perform quantization
|
||||||
- Allow to export the palette to png
|
- Allow to export the palette to png
|
||||||
- Allow to generate models from heightmap images
|
- Allow to generate models from heightmap images
|
||||||
|
- Allow to run lua scripts to modify volumes
|
||||||
|
|
||||||
Thumbnailer:
|
Thumbnailer:
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,29 @@
|
||||||
# Scripting api
|
# Scripting api
|
||||||
|
|
||||||
There is a console command (called `xs`) in voxedit to execute lua scripts for generating voxels. This command expects the lua script filename (`.lua` can be omitted) and the additional arguments for the `main()` method.
|
There is a console command (called `xs`) in [voxedit](voxedit/Index.md) and a command line parameter in [voxconvert](voxconvert/Index.md) to execute lua scripts for generating voxels. This command expects the lua script filename (`.lua` can be omitted) and the additional arguments for the `main()` method.
|
||||||
|
|
||||||
Calling `xs <script> help` will print the supported arguments for the given script.
|
---
|
||||||
|
|
||||||
|
> **voxedit**
|
||||||
|
>
|
||||||
|
> Calling `xs <script> help` (in the script console) will print the supported arguments for the given script file in voxedit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> **voxconvert**
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> ./vengi-voxconvert --script "<script> help" in.qb out.qb
|
||||||
|
> ```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
By default the script files will be searched in a `scripts` folder next to where the binary is located and in the usual search paths (see [configuration](Configuration.md) for more details). You can also give the full path to the script file.
|
||||||
|
|
||||||
There are two functions in each script. One is called `arguments` and one `main`. `arguments` returns a list of parameters for the `main` function. The default parameters for `main` are `volume`, `region` and `color`. `color` is the palette index starting from `0`.
|
There are two functions in each script. One is called `arguments` and one `main`. `arguments` returns a list of parameters for the `main` function. The default parameters for `main` are `volume`, `region` and `color`. `color` is the palette index starting from `0`.
|
||||||
|
|
||||||
|
Those functionalities that are marked with `voxedit` are not available outside of the editor (e.g. for the command line tools like [voxconvert](voxconvert/Index.md)).
|
||||||
|
|
||||||
# Example without parameters
|
# Example without parameters
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
@ -57,7 +75,7 @@ A `default` value can get set, too.
|
||||||
|
|
||||||
The order in the arguments table defines the order in which the arguments are passed over to the script.
|
The order in the arguments table defines the order in which the arguments are passed over to the script.
|
||||||
|
|
||||||
# LayerManager
|
# LayerManager (voxedit)
|
||||||
|
|
||||||
`layerMgr` lets you access different layers or create new ones.
|
`layerMgr` lets you access different layers or create new ones.
|
||||||
|
|
||||||
|
@ -67,7 +85,7 @@ The functions are:
|
||||||
|
|
||||||
* `get([layerId])`: Returns the `layer` for the given `layerId` - if the `layerId` is not given, it will return the current active layer. Which by default is the layer for the volume the script is currently executed for.
|
* `get([layerId])`: Returns the `layer` for the given `layerId` - if the `layerId` is not given, it will return the current active layer. Which by default is the layer for the volume the script is currently executed for.
|
||||||
|
|
||||||
# Layer
|
# Layer (voxedit)
|
||||||
|
|
||||||
* `name()`: Returns the current name of the layer.
|
* `name()`: Returns the current name of the layer.
|
||||||
|
|
||||||
|
@ -160,7 +178,7 @@ To get a full list of commands and cvars use the console command `cmdlist` and `
|
||||||
|
|
||||||
Generates perlin noise with the frequency and amplitude as parameters with the current selected color.
|
Generates perlin noise with the frequency and amplitude as parameters with the current selected color.
|
||||||
|
|
||||||
![noise](lua-noise.png)
|
![noise](img/lua-noise.png)
|
||||||
|
|
||||||
`xs noise.lua 0.3 1.0`
|
`xs noise.lua 0.3 1.0`
|
||||||
|
|
||||||
|
@ -168,7 +186,7 @@ Generates perlin noise with the frequency and amplitude as parameters with the c
|
||||||
|
|
||||||
Generates a new voxel on top of others with the current selected color and the specified height.
|
Generates a new voxel on top of others with the current selected color and the specified height.
|
||||||
|
|
||||||
![cover](lua-cover.png)
|
![cover](img/lua-cover.png)
|
||||||
|
|
||||||
`xs cover.lua 1`
|
`xs cover.lua 1`
|
||||||
|
|
||||||
|
@ -176,15 +194,15 @@ Generates a new voxel on top of others with the current selected color and the s
|
||||||
|
|
||||||
Generates a pyramid with the current selected color and with each level being 3 voxels high.
|
Generates a pyramid with the current selected color and with each level being 3 voxels high.
|
||||||
|
|
||||||
![pyramid](lua-pyramid.png)
|
![pyramid](img/lua-pyramid.png)
|
||||||
|
|
||||||
`xs pyramid.lua 3`
|
`xs pyramid.lua 3`
|
||||||
|
|
||||||
## thicken.lua
|
## thicken.lua (voxedit)
|
||||||
|
|
||||||
Thickens the voxel - take 1 voxel and convert to 8 voxels.
|
Thickens the voxel - take 1 voxel and convert to 8 voxels.
|
||||||
|
|
||||||
![thickenbefore](lua-thicken-before.png) ![thickenafter](lua-thicken-after.png)
|
![thickenbefore](img/lua-thicken-before.png) ![thickenafter](img/lua-thicken-after.png)
|
||||||
|
|
||||||
`xs thicken.lua 1`
|
`xs thicken.lua 1`
|
||||||
|
|
||||||
|
@ -192,6 +210,6 @@ Thickens the voxel - take 1 voxel and convert to 8 voxels.
|
||||||
|
|
||||||
Generate grass on top of voxels.
|
Generate grass on top of voxels.
|
||||||
|
|
||||||
![grass](grass.png)
|
![grass](img/grass.png)
|
||||||
|
|
||||||
`xs grass.lua`
|
`xs grass.lua`
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
@ -31,4 +31,4 @@ You can also use other user/password combinations by setting some cvars:
|
||||||
* **db_pw**
|
* **db_pw**
|
||||||
* **db_user**
|
* **db_user**
|
||||||
|
|
||||||
See the [configuration](Configuration.md) documentation for more details.
|
See the [configuration](../Configuration.md) documentation for more details.
|
||||||
|
|
|
@ -8,7 +8,7 @@ You can load and save a lot of different [voxel formats](../Formats.md).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* LUA [scripting](LUAScript.md) api
|
* LUA [scripting](../LUAScript.md) api
|
||||||
* Layer support
|
* Layer support
|
||||||
* Auto cropping volumes
|
* Auto cropping volumes
|
||||||
* Auto generate content like trees or noise volumes
|
* Auto generate content like trees or noise volumes
|
||||||
|
|
|
@ -24,9 +24,9 @@ nav:
|
||||||
- Configuration.md
|
- Configuration.md
|
||||||
- Formats.md
|
- Formats.md
|
||||||
- CHANGELOG.md
|
- CHANGELOG.md
|
||||||
|
- LUAScript.md
|
||||||
- VoxEdit:
|
- VoxEdit:
|
||||||
- voxedit/Index.md
|
- voxedit/Index.md
|
||||||
- voxedit/LUAScript.md
|
|
||||||
- Games:
|
- Games:
|
||||||
- OpenWorld: openworld/Index.md
|
- OpenWorld: openworld/Index.md
|
||||||
- Tools:
|
- Tools:
|
||||||
|
|
|
@ -4,4 +4,4 @@ set(SRCS
|
||||||
)
|
)
|
||||||
|
|
||||||
engine_add_executable(TARGET ${PROJECT_NAME} SRCS ${SRCS})
|
engine_add_executable(TARGET ${PROJECT_NAME} SRCS ${SRCS})
|
||||||
engine_target_link_libraries(TARGET ${PROJECT_NAME} DEPENDENCIES app voxelformat)
|
engine_target_link_libraries(TARGET ${PROJECT_NAME} DEPENDENCIES app voxelformat voxelgenerator)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/Color.h"
|
#include "core/Color.h"
|
||||||
#include "core/GameConfig.h"
|
#include "core/GameConfig.h"
|
||||||
#include "core/StringUtil.h"
|
#include "core/StringUtil.h"
|
||||||
|
#include "core/Tokenizer.h"
|
||||||
#include "core/Var.h"
|
#include "core/Var.h"
|
||||||
#include "command/Command.h"
|
#include "command/Command.h"
|
||||||
#include "image/Image.h"
|
#include "image/Image.h"
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#include "voxel/MaterialColor.h"
|
#include "voxel/MaterialColor.h"
|
||||||
#include "voxelformat/VolumeFormat.h"
|
#include "voxelformat/VolumeFormat.h"
|
||||||
#include "voxelformat/Format.h"
|
#include "voxelformat/Format.h"
|
||||||
|
#include "voxelgenerator/LUAGenerator.h"
|
||||||
#include "voxelutil/ImageUtils.h"
|
#include "voxelutil/ImageUtils.h"
|
||||||
#include "voxelutil/VolumeRescaler.h"
|
#include "voxelutil/VolumeRescaler.h"
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ app::AppState VoxConvert::onConstruct() {
|
||||||
registerArg("--scale").setShort("-s").setDescription("Scale layer to 50% of its original size");
|
registerArg("--scale").setShort("-s").setDescription("Scale layer to 50% of its original size");
|
||||||
registerArg("--force").setShort("-f").setDescription("Overwrite existing files");
|
registerArg("--force").setShort("-f").setDescription("Overwrite existing files");
|
||||||
registerArg("--export-palette").setDescription("Export the used palette data into an image. Use in combination with --src-palette");
|
registerArg("--export-palette").setDescription("Export the used palette data into an image. Use in combination with --src-palette");
|
||||||
|
registerArg("--script").setDefaultValue("script.lua").setDescription("Apply the given lua script to the output volume");
|
||||||
|
|
||||||
_mergeQuads = core::Var::get(cfg::VoxformatMergequads, "true", core::CV_NOPERSIST);
|
_mergeQuads = core::Var::get(cfg::VoxformatMergequads, "true", core::CV_NOPERSIST);
|
||||||
_mergeQuads->setHelp("Merge similar quads to optimize the mesh");
|
_mergeQuads->setHelp("Merge similar quads to optimize the mesh");
|
||||||
|
@ -51,6 +54,10 @@ app::AppState VoxConvert::onConstruct() {
|
||||||
_palette = core::Var::get("palette", voxel::getDefaultPaletteName());
|
_palette = core::Var::get("palette", voxel::getDefaultPaletteName());
|
||||||
_palette->setHelp("This is the NAME part of palette-<NAME>.png or absolute png file to use (1x256)");
|
_palette->setHelp("This is the NAME part of palette-<NAME>.png or absolute png file to use (1x256)");
|
||||||
|
|
||||||
|
if (!filesystem()->registerPath("scripts/")) {
|
||||||
|
Log::warn("Failed to register lua generator script path");
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +107,11 @@ app::AppState VoxConvert::onInit() {
|
||||||
}
|
}
|
||||||
Log::info("* infile: - %s", infile.c_str());
|
Log::info("* infile: - %s", infile.c_str());
|
||||||
Log::info("* outfile: - %s", outfile.c_str());
|
Log::info("* outfile: - %s", outfile.c_str());
|
||||||
|
core::String scriptParameters;
|
||||||
|
if (hasArg("--script")) {
|
||||||
|
scriptParameters = getArgVal("--script");
|
||||||
|
Log::info("* script: - %s", scriptParameters.c_str());
|
||||||
|
}
|
||||||
Log::info("* merge volumes: - %s", (mergeVolumes ? "true" : "false"));
|
Log::info("* merge volumes: - %s", (mergeVolumes ? "true" : "false"));
|
||||||
Log::info("* scale volumes: - %s", (scaleVolumes ? "true" : "false"));
|
Log::info("* scale volumes: - %s", (scaleVolumes ? "true" : "false"));
|
||||||
Log::info("* use source file palette: - %s", (srcPalette ? "true" : "false"));
|
Log::info("* use source file palette: - %s", (srcPalette ? "true" : "false"));
|
||||||
|
@ -204,6 +216,37 @@ app::AppState VoxConvert::onInit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!scriptParameters.empty()) {
|
||||||
|
voxelgenerator::LUAGenerator script;
|
||||||
|
if (!script.init()) {
|
||||||
|
Log::warn("Failed to initialize the script bindings");
|
||||||
|
} else {
|
||||||
|
core::DynamicArray<core::String> tokens;
|
||||||
|
core::string::splitString(scriptParameters, tokens);
|
||||||
|
const core::String &luaScript = script.load(tokens[0]);
|
||||||
|
if (luaScript.empty()) {
|
||||||
|
Log::error("Failed to load %s", tokens[0].c_str());
|
||||||
|
} else {
|
||||||
|
const voxel::Voxel voxel = voxel::createVoxel(voxel::VoxelType::Generic, 1);
|
||||||
|
core::DynamicArray<voxelgenerator::LUAParameterDescription> argsInfo;
|
||||||
|
if (!script.argumentInfo(luaScript, argsInfo)) {
|
||||||
|
Log::warn("Failed to get argument details");
|
||||||
|
}
|
||||||
|
core::DynamicArray<core::String> args(tokens.size() - 1);
|
||||||
|
for (size_t i = 1; i < tokens.size(); ++i) {
|
||||||
|
args[i - 1] = tokens[i];
|
||||||
|
}
|
||||||
|
Log::info("Execute script %s", tokens[0].c_str());
|
||||||
|
for (auto& v : volumes) {
|
||||||
|
voxel::RawVolumeWrapper wrapper(v.volume);
|
||||||
|
script.exec(luaScript, &wrapper, wrapper.region(), voxel, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
Log::debug("Save");
|
Log::debug("Save");
|
||||||
if (!voxelformat::saveFormat(outputFile, volumes)) {
|
if (!voxelformat::saveFormat(outputFile, volumes)) {
|
||||||
voxelformat::clearVolumes(volumes);
|
voxelformat::clearVolumes(volumes);
|
||||||
|
|