Created tutorials and API

This commit is contained in:
TinmanJuggernaut 2019-05-27 19:06:28 +09:00 committed by Cory Petkovsek
parent 9ee058b140
commit 0c37f2663c
32 changed files with 1948 additions and 24 deletions

View File

@ -1,35 +1,26 @@
Voxel Tools for Godot
=========================
C++ module for creating volumetric worlds in Godot Engine.
A C++ module for creating volumetric worlds in Godot Engine.
![Blocky example screenshot](screenshots/2016_05_04_0319_w800.png)
![Smooth example screenshot](screenshots/2019_05_05_1944_w800.png)
<img src="doc/images/blocky_screenshot.png" width="800" />
<img src="doc/images/smooth_screenshot.png" width="800" />
<img src="doc/images/textured-terrain.jpg" width="800" />
Setup
------
You need to get the source of Godot 3.1+ and recompile it with this module.
Install the contents of the repo in a folder under "modules/", named "voxel".
IMPORTANT: if you clone the repo, Git will create the folder as the repo name, "godot_voxel". But because Godot SCons scripts consider the folder name as the module's name, it will generate wrong function calls, so you must rename the folder "voxel".
For more info about Godot modules, see http://docs.godotengine.org/en/3.1/development/cpp/custom_modules_in_cpp.html
What this module provides
Features
---------------------------
- Fully editable terrain as long as you call the right functions (see demo: https://github.com/Zylann/voxelgame)
- Voxel storage using 8-bit channels like images for any general purpose
- Data paging using blocks of 16x16x16 voxels, so the world can be streamed with threads as you move
- Minecraft-style terrain with voxels as types, with multiple materials and baked ambient occlusion
- Smooth terrain with voxels as distance field (using extensions of marching cubes)
- Level of detail for smooth terrain (no edition support yet)
- Simple interface for custom terrain generators (block by block using threads)
- Realtime editable, 3D based terrain (Unlike a hightmap based terrain, this allows for overhangs, tunnels, and user creation/destruction)
- Full collision support
- Infinite terrains made by paging sections in and out
- Voxel data is streamed from a variety of sources, which includes the ability to write your own
- Minecraft-style blocky voxel terrain, with multiple materials and baked ambient occlusion
- Smooth terrain using Dual Marching Cubes
- Levels of details for smooth terrain (though not user editable yet)
- Voxel storage using 8-bit channels for any general purpose
What this module doesn't provides
What This Module Doesn't Provide
-----------------------------------
- Level of detail for blocky terrain
@ -37,7 +28,21 @@ What this module doesn't provides
- Editor tools (only a few things are exposed)
- Import and export of voxel formats
How To Install And Use
-------------------------
Voxel Tools is a custom C++ module for Godot 3.1+. It must be compiled into the engine to work.
Please see the [Getting Started Guide](doc/01_get-started.md) guide for instructions, or the [the demo](https://github.com/Zylann/voxelgame) for working examples.
Roadmap
---------
I work on this module whenever I want and add things I'd like to have, so the roadmap is pretty much depending on my personal agenda.
These are some ideas that may or may not be implemented in the future:
* LOD (in development)
* Support general voxel use (not just terrains)
* Transvoxel and other meshing algorithms
* GPU Offloading (Maybe when Godot 4+ supports compute shaders)

22
doc/01_get-started.md Normal file
View File

@ -0,0 +1,22 @@
# Getting Started With Voxel Tools For Godot
Voxel Tools for Godot is a C++ module that must be compiled into the engine. It requires version 3.1+. The following guide will give you a build of Godot that supports Voxel Tools and show you how to use it.
## Tutorials
* [Building Godot With Voxel Tools](02_build-voxel-tools.md)
* [Creating A Voxel Terrain](03_create-terrain.md)
* [Texturing & Materials](04_materials.md)
* [Collision](05_collision.md)
* [Custom Data Streams](06_custom-streams.md)
## API
* [Overview](07_api-overview.md)
* [API Class List](api/Class_List.md)
## External Reference
Find more information about related topics here.
* [Custom C++ modules in Godot](https://godot.readthedocs.io/en/latest/development/cpp/custom_modules_in_cpp.html)

View File

@ -0,0 +1,37 @@
# Building Godot With Voxel Tools
These steps will walk you through creating a custom build of Godot with the Voxel Tools module compiled into it.
## Build Godot From Source
1. Download and compile the [Godot source](https://github.com/godotengine/godot) by following [the official guide](https://docs.godotengine.org/en/latest/development/compiling/index.html). If you want to regularly update your build (recommended), clone the repository with Git instead of downloading a zip file.
1. Build Godot before adding this or any other modules and make sure it produces an executable.
1. Run the newly built executable found in `godot/bin`. Look under Help/About and confirm that the version string indicates you are running a development version (e.g. 3.2dev.custom_build.ee5ba3e).
## Add Voxel Tools
1. Download or clone the repository for [Voxel Tools](https://github.com/Zylann/godot_voxel). Use Git to clone the repository if you want to make it easy to update your builds (recommended).
1. Place the Voxel Tools directory inside your Godot source, in the `godot/modules` directory.
1. Rename the Voxel Tools folder to `voxel`. When correct, the files (e.g. README.md) will be located in `godot/modules/voxel`. **This is important!**
1. Rebuild Godot and make sure it produces an executable.
1. Test that your build has Voxel support:
1. Run your new build of Godot.
1. Create a new project.
1. Create a new 3D scene.
1. Add a new node, search for "Voxel" and see if "VoxelTerrain" appears. If so, you have a successful build. If not, review these instructions and your build logs to see if you missed a step or something failed along the way.
## Updating Your Build
If you cloned Godot and Voxel Tools, you can use git to update your local code.
1. Go to your local Godot source directory `godot` and run `git pull`. It will download all updates from the repository and merge them into your local source.
1. Go to `godot/modules/voxel` and run `git pull`. Git will update Voxel Tools.
1. Rebuild Godot.
**Note:**
Since you are pulling from two development branches, it's probable that on occasion your build won't compile, your project won't open, or your Voxel Tools won't work properly or even crash Godot. To minimize downtime, save your successful builds. Move them out of the build folder and rename them with the version number (e.g. godot-3.2-ee5ba3e.exe). This way, you can continue to use previously working builds until the Godot or Voxel developers fix whatever is broken. It is generally desired by all that code published to repositories will at least build.
---
* [Next Page](03_create-terrain.md)
* [Doc Index](01_get-started.md)

42
doc/03_create-terrain.md Normal file
View File

@ -0,0 +1,42 @@
# Creating A Voxel Terrain
Now that your Godot Engine has voxel support built in, you can either download the [Voxel Game demo](https://github.com/Zylann/voxelgame) and start playing with it, or start creating your own terrain.
## Create A Terrain In The Editor
1. Create a new project and a new 3D scene, with a Spatial type root node.
1. Add a Camera and elevate it by setting Transform Y = 75 and Rotation X = -25. The terrain starts generating around (0,0,0), but creates high hills, and may be invisible from underneath. We will be looking down from above.
1. Import a black and white heightmap texture such as [this one](https://github.com/Zylann/voxelgame/blob/master/project/blocky_terrain/noise_distorted.png) from the demo. Make sure that the file is imported as an Image and NOT a Texture on the Import panel. You'll likely have to re-import and restart.
1. Add a VoxelTerrain node and adjust the following settings:
1. Provider: New VoxelStreamImage. Then click VoxelStreamImage again.
1. Image: Load. Select your imported noise texture.
1. Decide on the type of terrain you want:
* Blocky: Set Channel = "Type" (or 0), and leave Smooth Meshing Enabled unchecked (lower down).
* Smooth: Set Channel = "SDF" (or 1), and enable Smooth Meshing Enabled.
1. Voxel Library: add a New VoxelLibrary
1. Set the Viewer Path, Assign, select your camera or player (the parent of your camera).
1. Play your scene and you should see a terrain.
![Generated voxel terrain](images/default-terrain.jpg)
## Create A Terrain With Code
Add your own camera and environment as desired, or from above. Then drop this into a script:
```
const HEIGHT_MAP = preload("res://blocky_terrain/noise_distorted.png")
var terrain = VoxelTerrain.new()
func _ready():
terrain.voxel_library = VoxelLibrary.new()
terrain.stream = VoxelStreamImage.new()
terrain.stream.image = HEIGHT_MAP
terrain.view_distance = 256
terrain.viewer_path = "/root/Spatial/Player" # Change to the path of your camera or player node
add_child(terrain) # Add the terrain to the tree so Godot will render it
```
---
* [Next Page](04_materials.md)
* [Doc Index](01_get-started.md)

74
doc/04_materials.md Normal file
View File

@ -0,0 +1,74 @@
# Materials
The terrain can be textured simply by adding a material to channel 0 in the material section.
Here are some notes for better results.
## Recommended Reading
* [SpatialMatieral](https://docs.godotengine.org/en/3.1/tutorials/3d/spatial_material.html) - demonstrates many of the shader options available in Godot.
* [Shading Index](https://docs.godotengine.org/en/3.1/tutorials/shading/index.html) - tutorials and the shader language API
* Shader API Reference - some of the most frequently accessed references
* [Shading Language](https://docs.godotengine.org/en/3.1/tutorials/shading/shading_reference/shading_language.html)
* [SpatialShader](https://docs.godotengine.org/en/3.1/tutorials/shading/shading_reference/spatial_shader.html)
## Triplanar Mapping
Projecting a flat, 2D image texture onto a rounded terrain is like wrapping a piece of paper wrapped around a sphere. It often warps the texture in undesirable ways. Triplanar mapping is a wrapping method that provides a reasonable result for spheres and terrains.
The method involves projecting the texture onto only part of object that faces the X-axis directly. Then projecting it on the sides that face the Y-axis directly. Then again for the Z-axis. The edges of these projections are then blended together with a specified sharpness.
Look at how the brick textures are blended together on the top right sphere.
![Triplanar mapping image](https://docs.godotengine.org/en/3.1/_images/spatial_material25.png)
Read about [triplanar mapping in Godot](https://docs.godotengine.org/en/3.1/tutorials/3d/spatial_material.html?highlight=triplanar%20#triplanar-mapping).
The algorithm to implement this is a little complicated, which gets far worse if you also wish to add normal maps and others. However there is a very easy way to do this in the section below.
## Creating A Material
Rather than writing your own shader from scratch, especially with triplanar mapping code, the recommended process is to create a SpatialMaterial, then optionally convert it to a ShaderMaterial.
1. Create a new SpatialMaterial.
1. Add an albedo texture, and if desired, normal map, ambient occlusion, etc.
1. Under UV1, turn on triplanar mapping and adjust triplanar sharpness as desired.
1. Scale and style the material as desired.
If you want to start without a texture and just want to use a color, try turning down roughness, or adding some metalic to give the surface some reflectivity. This will allow light to reflect off the curves of the terrain in the distance. Otherwise you'll just see an undifferentiated mass of color.
### How To View Live Changes To Materials
You can't see the terrain in the viewport, so there are two options to view your material live while making changes:
* Add a sphere or cube with the same material, then adjust the material. This option is OK, but the UV scale is usually different than the terrain, so it's not ideal.
* Run your scene, focus the camera on the terrain, move the window to the side, and adjust the material in the editor window. All edits to a SpatialMaterial (or shader parameters if using a ShaderMaterial) will update live.
### Convert To Shader Code
The SpatialMaterial is a very good base, but can only go so far. If you need further customization, you'll want to convert it to shader code.
1. Add the material to any object.
1. In the inspector for that object, click the down arrow next to the material.
1. Click convert to ShaderMaterial.
Your material now has shader code that produces the same material your SpatialMaterial did, including code for triplanar albedo and normal maps!
Note, you can't edit the shader code and see live changes. You must stop and restart your scene. However you can change shader parameters live.
## Advanced Shading
What if you want to have multiple materials, such as grass on the top and rock on the sides?
What if you want to have two materials, each with their own triplanar mapped albedo normal and AO maps, then blend them together based on if their normal faces the upward direction or the sides?
You can find a working example of that in this [development demo](https://github.com/tinmanjuggernaut/voxelgame/tree/fps_demo/project), under fps_demo, or see the [shader](https://github.com/tinmanjuggernaut/voxelgame/blob/fps_demo/project/fps_demo/materials/triplanar.shader) itself. (*Editor-* update these links after publishing demo)
In the shader parameters, add your two albedo maps, and optionally normal, and AO maps. Then play with the `AB Mix 1` and `AB Mix 2` sliders to adjust how the top and sides blend together. The other settings should be self explanatory. The screenshot below also has a little bit of fog and far DOF added.
![textured terrain](images/textured-terrain.jpg)
---
* [Next Page](05_collision.md)
* [Doc Index](01_get-started.md)

71
doc/05_collision.md Normal file
View File

@ -0,0 +1,71 @@
# Collision
Physics based collision is enabled by default.
You can turn it on or off by setting the `generate_collision` option on any of the terrain nodes. Or you can enable or disable it in code.
The collision is built along with the mesh. So any blocks that have already been built will not be affected by the setting unless they are regenerated.
There are some alternative collision related tools available:
## Axis Aligned Bounding Box (Blocky only)
VoxelBoxMover has a function that can test AABB collision. The code below shows how to use it, but see the [blocky demo](https://github.com/Zylann/voxelgame/tree/master/project/blocky_terrain) for the full code.
Example:
```
var box_mover = VoxelBoxMover.new()
var aabb = AABB(Vector3(-0.4, -0.9, -0.4), Vector3(0.8, 1.8, 0.8))
var terrain = get_node("VoxelTerrain")
func _physics_process(delta):
/* Input commands that set velocity go here. */
var motion = velocity * delta
motion = box_mover.get_motion(get_translation(), motion, aabb, terrain)
global_translate(motion)
velocity = motion / delta
```
## Raycasting (Blocky or Smooth)
You can manually send out raycasts from your character to see how far away from the terrain it is. You can also do this with any of your objects.
_Note: Raycasting in VoxelLodTerrain requires the merging of [PR #29](https://github.com/Zylann/godot_voxel/pull/29), which is a work in progress. It works fine on LOD 0, but not the others._
Here's an example of how it can work. For a character 2 units tall, this runs a raycast directly down to prevent the character from sinking into the ground. `on_ground` is a boolean that tells the jump function whether it can fire or not.
```
# Apply gravity to downward velocity
velocity.y += delta*GRAVITY
# But clamp it if we hit the ground
if terrain.raycast(head_position, Vector3(0,-1,0), PLAYER_HEIGHT):
velocity.y = clamp(velocity.y, 0, 999999999)
on_ground = true
```
Then for lateral motion, you can test with something like this. We run a raycast at foot/knee level, then a little higher up (head level, since the granularity provided by the raycast is not very fine).
If it's clear at head level, but not at foot level then we're looking at a sloped terrain. We move the character up a little bit to help it traverse the terrain. It is a little rough, but serves as a working example.
```
func test_and_move(pos, dir) -> Vector3:
# If raycast hits at knee level (-1.5)
if terrain.raycast(Vector3(pos.x, pos.y-1.5, pos.z), dir, 1):
# Then test at head level and move character up a little if clear
if !terrain.raycast(pos, dir, 1) :
translate(Vector3(0,.15,0))
return dir
# Both hit, can't move
return Vector3(0,0,0)
# Otherwise, free to move
else:
return dir
```
---
* [Next Page](06_custom-streams.md)
* [Doc Index](01_get-started.md)

40
doc/06_custom-streams.md Normal file
View File

@ -0,0 +1,40 @@
# Create Your Own Voxel Data Stream
You can provide your own stream of voxel data by extending VoxelStream either in GDScript or C++.
Note: Your stream must be thread safe.
Create MyStream.gd with the following contents:
```
extends VoxelStream
func emerge_block(buffer:VoxelBuffer, origin:Vector3, lod:int) -> void:
if lod != 0: return
if origin.y < 0: buffer.fill(1, 0)
if origin.x==origin.z and origin.y < 1: buffer.fill(1,0)
```
In your terrain generation script, add this:
```
const MyStream = preload ("MyStream.gd")
var terrain = VoxelTerrain.new()
func _ready():
terrain.stream = MyStream.new()
terrain.voxel_library = VoxelLibrary.new()
terrain.view_distance = 256
terrain.viewer_path = "/root/Spatial/Player" # Set this path to your player/camera
add_child(terrain)
```
![Custom Data Stream](images/custom-stream.jpg)
`VoxelBuffer.fill()` is probably not what you want to use. Emerge_block generally gives you a block of 16x16x16 cubes to fill all at once, so you probably want to use `VoxelBuffer.set_voxel()` to specify each one. See the API here or in the editor for up to date function definitions.
You should review the [C++ code](../streams) for the built-in streams to see how they utilize the API to fill the buffers one voxel at a time.
---
* [Next Page](07_api-overview.md)
* [Doc Index](01_get-started.md)

191
doc/07_api-overview.md Normal file
View File

@ -0,0 +1,191 @@
# Voxel Tools API Overview
The Voxel Tools API is under development and has not yet settled. This document contains the following:
1. GDScript API reference
1. Terminology used throughout the codebase
1. A description of classes exposed to GDScript
# API Reference
You can refer to the API that is exposed to GDScript in two places:
* You'll find class definitions in the [docs/api](api/Class_List.md) directory.
* Within the Godot editor, access the definitions in the help:
1. Click *Search Help* in the GDScript editor.
1. Type "Voxel".
1. Browse through the classes, methods, and properties exposed to GDScript.
# Terminology Used Throughout The Codebase
**Voxel** - A 3D pixel in a Euclidean world where the coordinates (X, Y, Z) are restricted to integers. That is, space is a 3D grid where each point in space can only be an integer (...-3, -2, -1, 0, 1, 2, 3...) and there is no infinite space between points. As an example, from (0,0,0), the next point in space along the X axis is (1,0,0). There is no (0.5, 0, 0) or (0.25, 0, 0). Each point in space is a cube.
In Minecraft type games, building blocks are cubes. However, they do not have to be full cubes. Minecraft has half-cubes, etc. They can also be smoother shapes, as described below under Smooth [Terrain].
Note that the engine and your graphics card do not work with voxels. They are converted and drawn as triangles like all other meshes at render time. This means you can use voxels and polygonal meshes simultaneously.
**Block** - While a voxel is a single unit of space, a block refers to an N\*N\*N voxel chunk of terrain, where N is 8, 16(default), or 32. Blocks of voxels are paged in and out by the terrain, depending their distance to the viewer. Blocks are therefore much larger than voxels, and the project maintains two grids: voxel space and block space. The latter is 8/16/32 times larger.
**Voxel Data** - This refers to a high resolution source of data, often coming from the real world or an analog source. Imagine an airplane with it's smooth, aerodynamic curves. If we 3D scanned this plane, that would be high resolution voxel data. If we built that airplane out of Legos, that would be a low resolution, blocky representation of the source voxel data. See Blocky below.
**Blocky [Terrain]** - An algorithm that uses full cubes to approximate Voxel data. This is Minecraft, building an airplane out of Legos, or representing a bell curve with a bar chart. It is better suited for man-made shapes with hard corners.
**Smooth [Terrain]** - One of many isometric surface extraction algorithms that attempts to represent voxel data with smoother surfaces and is a better fit for organic shapes. Rather than using a full cube to describe the surface, a cube with one or more planes at potentially any angle is used to provide a far more accurate representation of the source data. As an example if you took a Lego block and sanded down the sharp corners to better represent the airplane curves, or sanded down the tops of the bar chart to better represent the bell curve. However you can only sand down to flat planes, no curves within the cubes.
Voxel Tools supports Dual Marching Cubes, Transvoxel (WIP) and is structured to support other algorithms in the future. Some are faster, use less memory, provide manifold meshes (cleaner meshes), and/or provide more accurate representations of the voxel data.
**LOD - Level of Detail** - As the camera gets further away, detail decreases to improve performance.
# Description of Classes
What follows are notes and descriptions about each of the classes that have been exposed to GDScript.
## Scene Node Classes
These nodes can be added to your scene.
Note: Terrains use their VoxelStream and VoxelMeshers from multiple threads. Access is granted in the editor because I turned off terrain generation specifically here, but at runtime some things (like getting the stream from the terrain and asking it to generate a block) are prone to undefined behavior. I still need to add locks here to suspend threads while configurations are changed.
### VoxelTerrain
An infinite, paged terrain made of voxel blocks, all with the same level of detail. Voxels are polygonized around the viewer by distance in a large cubic space.
* Voxel data is streamed using a VoxelStream (e.g. noise image, 3D noise texture, etc).
* Stores a terrain in a VoxelMap.
* Supports blocky and smooth terrains.
* Handles the main Godot \_process() call to update the terrain, load and unload voxel blocks, and generate the mesh and collision.
* Supports raycasts (for manual collision and click detection).
### VoxelLodTerrain
A (not yet infinite) paged terrain made of voxel blocks with a variable level of detail. Designed for high view distances. Voxels are polygonized around the viewer by distance in a very large sphere, usually extending beyond the cameras Far clip.
* Data is streamed using a VoxelStream, which must support LOD.
* Stores a terrain in a VoxelMap.
* Handles the main Godot \_process() call to update the terrain, load and unload voxel blocks, and generate the mesh and collision.
* Supports only smooth terrains.
* Does not yet support raycasts (PR #29 pending).
* Manages Levels of detail (LOD).
## Voxel Data Provider Classes
These classes provide the source voxel data.
### VoxelStream
Base class to provide infinite, paged voxel data as blocks. Doesn't provide data itself, but can be extended with GDScript.
If you choose to implement your own stream that does not offer LOD, it is recommended to `assert(lod == 0)`. It will be executed in a separate thread, so access the main thread with care.
The classes below provide voxel data.
### VoxelStreamTest
Provides a flat plane or 2D sine waves.
* Blocky only.
### VoxelStreamImage
Creates a heightmap based on a user provided, black and white image.
This class expects the image to be imported as an Image. By default, image files are imported as a Texture, which are stored in video RAM and are not accessible to the engine. On the Import tab, you need to change the import method of your image to Image and may need to restart Godot before VoxelStreamImage will recognize your file.
* Blocky or smooth.
### VoxelStreamNoise
Generates 3D noise via OpenSimplexNoise.
* Smooth only.
## Mesher Classes
These classes use full cubes or an isometric surface extraction algorithm to represent the source voxel data. They polygonize arbitrary-sized chunks of voxels.
Note: Their initial use case was for terrains, so the input data must be padded by a certain amount of voxels to work (get_minimum_padding() gives you that number. It's usually 1 or 2).
### VoxelMesher
Abstract base class to build a polygonal terrain mesh from a given VoxelBuffer. Unlike VoxelStream, this class cannot be implemented with a script. You must extend it with a C++ class to implement another meshing algorithm.
### VoxelMesherBlocky
Builds a mesh using full cubes only. Looks like Minecraft.
* The fastest mesher.
* No LOD support currently.
* Offers baked ambient occlusion around edges.
* Has the capability to support any kind of shape inside the block, (e.g. half-cubes, grass shapes, etc), but this API is not yet tested or exposed very well or at all.
### VoxelMesherDMC
Builds a smooth mesh using the Dual Marching Cubes algorithm.
* Supports LOD by simply scaling up the result.
* Uses marching squares skirts to hide the cracks between sections with a different LOD.
### VoxelMesherTransvoxel
Builds a smooth mesh using the Transvoxel algorithm.
* Development is on hold for now. Use DMC.
* Partial implementation, which may or may not be broken.
## Storage Classes
### VoxelMap
Where Terrains store their voxels, as an infinite, 3D, sparse grid. It can be thought of as the infinite equivalent of VoxelBuffer.
* Stores a 3D grid in a HashMap containing integer vector3s as keys, and VoxelBlocks as values. i.e. key:Vector3int => value:VoxelBlock pairs.
* Provides functions to convert between the voxel grid coordinates and block grid coordinates, which is 8/16/32 times larger.
* The default grid size is 16 and while some support is there for 8 and 32, this setting is not yet adjustable.
Note: There are two grid coordinate systems. One addresses voxels individually, the other addresses blocks. It was initially required to allow streaming of the world, because loading voxels individually would have been very expensive. So instead I load chunks (like Minecraft), and those chunks lie in a grid having a step 16 times larger (because each block contains 16\*16\*16 voxels). When LOD is considered, there are even multiple block grids, but each having a scale higher by powers of two.
### VoxelBlock (Unregistered)
Internal structure for holding a reference to mesh visuals, collision, and a block of voxel data. Not available to GDScript, but supports both the above and below classes.
* Stores 3D grid position and LOD index.
* Creates StaticBody and Shapes to enable collision, and CollisionShapes to support the editor `Debug\Visual Collsion Shapes` feature.
* References a VoxelBuffer and a Mesh.
### VoxelBuffer
The underlying storage for voxels. Also used to pass voxels between functions.
* Stores an arbitrary number of voxels (Vector3int specifying how many in each direction).
* Stores up to 8 channels of arbitrary data per voxel. Each channel is allocated only upon use. (e.g. R,G,B,A, game play types (type, state, light), etc).
## Supporting Classes
### VoxelIsoSurfaceTool
Provides functions to add or remove smooth terrain. Currently supported shapes are sphere, plane, cube, heightmap.
* You can generate a 2D heightmap and ask the tool to "rasterize" that portion of the world in a VoxelBuffer, which is what you will have to fill when implementing a custom VoxelStream.
* Since Godot does not support 3D images, a custom shape could be added using an existing VoxelBuffer as input. This is not yet implemented.
### VoxelBoxMover
Provides Axis Aligned Bounding Box based collision. (blocky only)
### Voxel
A basic voxel unit. Creating Voxels with VoxelLibrary is recommended. (blocky only)
* Stores ID, name, material, transparency and type
### VoxelLibrary
A factory for creating Voxels. (blocky only)
---
* [API Class List](api/Class_List.md)
* [Doc Index](01_get-started.md)

24
doc/api/Class_List.md Normal file
View File

@ -0,0 +1,24 @@
# Voxel Tools Class List
These classes are exposed to GDScript. This information is also available within the Godot script editor by searching help.
* [Voxel.md](Voxel.md)
* [VoxelBoxMover.md](VoxelBoxMover.md)
* [VoxelBuffer.md](VoxelBuffer.md)
* [VoxelIsoSurfaceTool.md](VoxelIsoSurfaceTool.md)
* [VoxelLibrary.md](VoxelLibrary.md)
* [VoxelLodTerrain.md](VoxelLodTerrain.md)
* [VoxelMap.md](VoxelMap.md)
* [VoxelMesher.md](VoxelMesher.md)
* [VoxelMesherBlocky.md](VoxelMesherBlocky.md)
* [VoxelMesherDMC.md](VoxelMesherDMC.md)
* [VoxelMesherTransvoxel.md](VoxelMesherTransvoxel.md)
* [VoxelStream.md](VoxelStream.md)
* [VoxelStreamImage.md](VoxelStreamImage.md)
* [VoxelStreamNoise.md](VoxelStreamNoise.md)
* [VoxelStreamTest.md](VoxelStreamTest.md)
* [VoxelTerrain.md](VoxelTerrain.md)
---
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

99
doc/api/Voxel.md Normal file
View File

@ -0,0 +1,99 @@
# Class: Voxel
Inherits: Resource
_Godot version: 3.2_
## Online Tutorials:
## Constants:
#### » GeometryType.GEOMETRY_NONE = 0
#### » GeometryType.GEOMETRY_CUBE = 1
#### » GeometryType.GEOMETRY_MAX = 2
#### » ChannelMode.CHANNEL_TYPE = 0
#### » ChannelMode.CHANNEL_ISOLEVEL = 1
#### » ChannelMode.CHANNEL_DATA = 2
## Properties:
#### » Color color
`set_color (value)` setter
`get_color ()` getter
#### » int Voxel.GeometryType.geometry_type
`set_geometry_type (value)` setter
`get_geometry_type ()` getter
#### » int material_id
`set_material_id (value)` setter
`get_material_id ()` getter
#### » bool transparent
`set_transparent (value)` setter
`is_transparent ()` getter
#### » String voxel_name
`set_voxel_name (value)` setter
`get_voxel_name ()` getter
## Methods:
#### » int get_id ( ) const
#### » Voxel set_color ( Color color )
#### » Voxel set_id ( int id )
#### » Voxel set_material_id ( int id )
#### » Voxel set_transparent ( bool transparent=true )
#### » Voxel set_voxel_name ( String name )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

31
doc/api/VoxelBoxMover.md Normal file
View File

@ -0,0 +1,31 @@
# Class: VoxelBoxMover
Inherits: Reference
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
## Methods:
#### » Vector3 get_motion ( Vector3 pos, Vector3 motion, AABB aabb, Node terrain )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

109
doc/api/VoxelBuffer.md Normal file
View File

@ -0,0 +1,109 @@
# Class: VoxelBuffer
Inherits: Reference
_Godot version: 3.2_
## Online Tutorials:
## Constants:
#### » ChannelId.CHANNEL_TYPE = 0
#### » ChannelId.CHANNEL_ISOLEVEL = 1
#### » ChannelId.CHANNEL_DATA2 = 2
#### » ChannelId.CHANNEL_DATA3 = 3
#### » ChannelId.CHANNEL_DATA4 = 4
#### » ChannelId.CHANNEL_DATA5 = 5
#### » ChannelId.CHANNEL_DATA6 = 6
#### » ChannelId.CHANNEL_DATA7 = 7
#### » ChannelId.MAX_CHANNELS = 8
## Properties:
## Methods:
#### » void clear ( )
#### » void copy_from ( VoxelBuffer other, int channel=0 )
#### » void copy_from_area ( VoxelBuffer other, Vector3 src_min, Vector3 src_max, Vector3 dst_min, int channel=0 )
#### » void create ( int sx, int sy, int sz )
#### » void fill ( int value, int channel=0 )
#### » void fill_area ( int value, Vector3 min, Vector3 max, int channel=0 )
#### » void fill_f ( float value, int channel=0 )
#### » Vector3 get_size ( ) const
#### » int get_size_x ( ) const
#### » int get_size_y ( ) const
#### » int get_size_z ( ) const
#### » int get_voxel ( int x, int y, int z, int channel=0 ) const
#### » float get_voxel_f ( int x, int y, int z, int channel=0 ) const
#### » bool is_uniform ( int channel ) const
#### » void optimize ( )
#### » void set_voxel ( int value, int x, int y, int z, int channel=0 )
#### » void set_voxel_f ( float value, int x, int y, int z, int channel=0 )
#### » void set_voxel_v ( int value, Vector3 pos, int channel=0 )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,67 @@
# Class: VoxelIsoSurfaceTool
Inherits: Reference
_Godot version: 3.2_
## Online Tutorials:
## Constants:
#### » Operation.OP_ADD = 0
#### » Operation.OP_SUBTRACT = 1
#### » Operation.OP_SET = 2
## Properties:
## Methods:
#### » void do_cube ( Transform transform, Vector3 extents, int op=0 )
#### » void do_heightmap ( Image heightmap, Vector3 offset, float vertical_scale, int op=0 )
#### » void do_plane ( Plane plane, int op=0 )
#### » void do_sphere ( Vector3 center, float radius, int op=0 )
#### » VoxelBuffer get_buffer ( ) const
#### » float get_iso_scale ( ) const
#### » Vector3 get_offset ( ) const
#### » void set_buffer ( VoxelBuffer voxel_buffer )
#### » void set_iso_scale ( float iso_scale )
#### » void set_offset ( Vector3 offset )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

41
doc/api/VoxelLibrary.md Normal file
View File

@ -0,0 +1,41 @@
# Class: VoxelLibrary
Inherits: Resource
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
#### » int atlas_size
`set_atlas_size (value)` setter
`get_atlas_size ()` getter
## Methods:
#### » Voxel create_voxel ( int id, String name )
#### » Voxel get_voxel ( int id )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,89 @@
# Class: VoxelLodTerrain
Inherits: Spatial
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
#### » bool generate_collision
`set_generate_collision (value)` setter
`get_generate_collision ()` getter
#### » int lod_count
`set_lod_count (value)` setter
`get_lod_count ()` getter
#### » float lod_split_scale
`set_lod_split_scale (value)` setter
`get_lod_split_scale ()` getter
#### » Material material
`set_material (value)` setter
`get_material ()` getter
#### » VoxelStream stream
`set_stream (value)` setter
`get_stream ()` getter
#### » int view_distance
`set_view_distance (value)` setter
`get_view_distance ()` getter
#### » NodePath viewer_path
`set_viewer_path (value)` setter
`get_viewer_path ()` getter
## Methods:
#### » Dictionary get_block_info ( Vector3 block_pos, int lod ) const
#### » int get_block_region_extent ( ) const
#### » Dictionary get_stats ( ) const
#### » Vector3 voxel_to_block_position ( Vector3 lod_index, int arg1 ) const
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

70
doc/api/VoxelMap.md Normal file
View File

@ -0,0 +1,70 @@
# Class: VoxelMap
Inherits: Reference
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
## Methods:
#### » Vector3 block_to_voxel ( Vector3 block_pos ) const
#### » int get_block_size ( ) const
#### » void get_buffer_copy ( Vector3 min_pos, VoxelBuffer out_buffer, int channel=0 )
#### » int get_default_voxel ( int channel=0 )
#### » int get_voxel ( int x, int y, int z, int c=0 )
#### » float get_voxel_f ( int x, int y, int z, int c=1 )
#### » int get_voxel_v ( Vector3 pos, int c=0 )
#### » bool has_block ( int x, int y, int z )
#### » void set_block_buffer ( Vector3 block_pos, VoxelBuffer buffer )
#### » void set_default_voxel ( int value, int channel=0 )
#### » void set_voxel ( int value, int x, int y, int z, int c=0 )
#### » void set_voxel_f ( float value, int x, int y, int z, int c=1 )
#### » void set_voxel_v ( int value, Vector3 pos, int c=0 )
#### » Vector3 voxel_to_block ( Vector3 voxel_pos ) const
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

31
doc/api/VoxelMesher.md Normal file
View File

@ -0,0 +1,31 @@
# Class: VoxelMesher
Inherits: Reference
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
## Methods:
#### » Mesh build_mesh ( VoxelBuffer voxel_buffer )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,49 @@
# Class: VoxelMesherBlocky
Inherits: VoxelMesher
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
## Methods:
#### » VoxelLibrary get_library ( ) const
#### » float get_occlusion_darkness ( ) const
#### » bool get_occlusion_enabled ( ) const
#### » Dictionary get_profiling_info ( ) const
#### » void set_library ( VoxelLibrary voxel_library )
#### » void set_occlusion_darkness ( float value )
#### » void set_occlusion_enabled ( bool enable )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

82
doc/api/VoxelMesherDMC.md Normal file
View File

@ -0,0 +1,82 @@
# Class: VoxelMesherDMC
Inherits: VoxelMesher
_Godot version: 3.2_
## Online Tutorials:
## Constants:
#### » MeshMode.MESH_NORMAL = 0
#### » MeshMode.MESH_WIREFRAME = 1
#### » MeshMode.MESH_DEBUG_OCTREE = 2
#### » MeshMode.MESH_DEBUG_DUAL_GRID = 3
#### » SimplifyMode.SIMPLIFY_OCTREE_BOTTOM_UP = 0
#### » SimplifyMode.SIMPLIFY_OCTREE_TOP_DOWN = 1
#### » SimplifyMode.SIMPLIFY_NONE = 2
#### » SeamMode.SEAM_NONE = 0
#### » SeamMode.SEAM_MARCHING_SQUARE_SKIRTS = 1
## Properties:
## Methods:
#### » float get_geometric_error ( ) const
#### » int get_mesh_mode ( ) const
#### » int get_seam_mode ( ) const
#### » int get_simplify_mode ( ) const
#### » Dictionary get_stats ( ) const
#### » void set_geometric_error ( float error )
#### » void set_mesh_mode ( int mode )
#### » void set_seam_mode ( int mode )
#### » void set_simplify_mode ( int mode )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,28 @@
# Class: VoxelMesherTransvoxel
Inherits: VoxelMesher
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
## Methods:
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

34
doc/api/VoxelStream.md Normal file
View File

@ -0,0 +1,34 @@
# Class: VoxelStream
Inherits: Resource
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
## Methods:
#### » void emerge_block ( VoxelBuffer out_buffer, Vector3 origin_in_voxels, int lod )
#### » void immerge_block ( VoxelBuffer buffer, Vector3 origin_in_voxels, int lod )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,42 @@
# Class: VoxelStreamImage
Inherits: VoxelStream
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
#### » int VoxelBuffer.ChannelId.channel
`set_channel (value)` setter
`get_channel ()` getter
#### » Image image
`set_image (value)` setter
`get_image ()` getter
## Methods:
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,49 @@
# Class: VoxelStreamNoise
Inherits: VoxelStream
_Godot version: 3.2_
## Online Tutorials:
## Constants:
## Properties:
#### » float height_range
`set_height_range (value)` setter
`get_height_range ()` getter
#### » float height_start
`set_height_start (value)` setter
`get_height_start ()` getter
#### » OpenSimplexNoise noise
`set_noise (value)` setter
`get_noise ()` getter
## Methods:
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

@ -0,0 +1,62 @@
# Class: VoxelStreamTest
Inherits: VoxelStream
_Godot version: 3.2_
## Online Tutorials:
## Constants:
#### » Mode.MODE_FLAT = 0
#### » Mode.MODE_WAVES = 1
## Properties:
#### » int VoxelStreamTest.Mode.mode
`set_mode (value)` setter
`get_mode ()` getter
#### » Vector3 pattern_offset
`set_pattern_offset (value)` setter
`get_pattern_offset ()` getter
#### » Vector3 pattern_size
`set_pattern_size (value)` setter
`get_pattern_size ()` getter
#### » int voxel_type
`set_voxel_type (value)` setter
`get_voxel_type ()` getter
## Methods:
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

115
doc/api/VoxelTerrain.md Normal file
View File

@ -0,0 +1,115 @@
# Class: VoxelTerrain
Inherits: Spatial
_Godot version: 3.2_
## Online Tutorials:
## Constants:
#### » BlockDirtyState.BLOCK_NONE = 0
#### » BlockDirtyState.BLOCK_LOAD = 1
#### » BlockDirtyState.BLOCK_UPDATE_NOT_SENT = 2
#### » BlockDirtyState.BLOCK_UPDATE_SENT = 3
#### » BlockDirtyState.BLOCK_IDLE = 4
## Properties:
#### » bool generate_collision
`set_generate_collision (value)` setter
`get_generate_collision ()` getter
#### » bool smooth_meshing_enabled
`set_smooth_meshing_enabled (value)` setter
`is_smooth_meshing_enabled ()` getter
#### » VoxelStream stream
`set_stream (value)` setter
`get_stream ()` getter
#### » int view_distance
`set_view_distance (value)` setter
`get_view_distance ()` getter
#### » NodePath viewer_path
`set_viewer_path (value)` setter
`get_viewer_path ()` getter
#### » VoxelLibrary voxel_library
`set_voxel_library (value)` setter
`get_voxel_library ()` getter
## Methods:
#### » Vector3 block_to_voxel ( Vector3 block_pos )
#### » int get_block_state ( Vector3 block_pos ) const
#### » Material get_material ( int id ) const
#### » Dictionary get_statistics ( ) const
#### » VoxelMap get_storage ( )
#### » void make_area_dirty ( AABB aabb )
#### » void make_voxel_dirty ( Vector3 pos )
#### » Variant raycast ( Vector3 origin, Vector3 direction, float max_distance=100 )
#### » void set_material ( int id, Material material )
#### » Vector3 voxel_to_block ( Vector3 voxel_pos )
## Signals:
---
* [Class List](Class_List.md)
* [Doc Index](../01_get-started.md)
_Generated on Aug 02, 2019_

View File

Before

Width:  |  Height:  |  Size: 774 KiB

After

Width:  |  Height:  |  Size: 774 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

195
doc/tools/build.py Executable file
View File

@ -0,0 +1,195 @@
#!/usr/bin/python
# coding: utf-8
# Builds Voxel Tools GDScript API
#
# Requires Python 3.4+
# Run with --help for usage
#
# Configure these variables for your system or specify on the command line
OUT="../api" # Path to output the gdscript files
GD="" # Path to Godot binary, specify on command line, or we will search
import sys
if(sys.version_info<(3,4)):
print("Please upgrade python to version 3.4 or higher.")
print("Your version: %s\n" %sys.version_info)
sys.exit(1)
from pathlib import Path
import os
import re
import glob
import getopt
import shutil
import tempfile
import subprocess
from time import gmtime, strftime
from xmlproc import process_xml
def build_gdscript_api(verbose=False):
# Make temp dirs
tmp_d = tempfile.mkdtemp()
if verbose:
print ("Making temp directories in %s" % tmp_d)
os.makedirs(tmp_d + "/doc/classes")
os.makedirs(tmp_d + "/modules/voxel/doc_classes")
# Last is not currently used, but will be once VT starts using doc_classes.
# Make output dir and remove old files
if not os.path.isdir(OUT):
if verbose:
print ("Making output directory: " + OUT)
os.makedirs(OUT)
for i in glob.glob(OUT + "*.md"):
if verbose:
print ("Removing old: ", i)
os.remove(i)
# Dump XML files from Godot
args = [GD, ' --doctool ', tmp_d ]
if verbose:
print ("Running: ", args)
result = subprocess.run (args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
if verbose:
print (result.stdout)
print("Disregard Godot's errors about files unless they are about Voxel*.")
# Convert files to MD
files = glob.glob(tmp_d + "/doc/classes/Voxel*.xml")
files += glob.glob(tmp_d + "/modules/voxel/doc_classes/*.xml")
count=0
for src in files:
dest = OUT + Path(src).stem + ".md"
if verbose:
print("Converting ", src, dest)
process_xml(src, dest)
count += 1
# Create Class index
index=OUT + "Class_List.md"
files = sorted(glob.glob(OUT+"Voxel*.md"))
str = "# Voxel Tools Class List\n\n"
str += "These classes are exposed to GDScript. This information is also available within the Godot script editor by searching help.\n\n"
for i in files:
f = Path(i).name
str += "* [%s](%s)\n" % (f, f)
str += "\n---\n"
str += "* [Doc Index](../01_get-started.md)\n"
str += "_Generated on " + strftime("%b %d, %Y", gmtime()) + "_\n"
if verbose:
print("Writing %s" % index)
outfile = open(index, 'a')
outfile.write(str)
count += 1
# Remove temporary files
if verbose:
print("Removing temp directory %s" % tmp_d)
shutil.rmtree (tmp_d, ignore_errors=True)
# Finished
print ("Generated %d files in %s." % (count, OUT))
def print_usage():
print("\nUsage: ", sys.argv[0], "[-v] [-g path_to_godot] [-o output_dir]");
print("\t-v -> Verbose");
print()
print("Current output directory: %s" %OUT);
print()
sys.exit(0)
def find_godot(godot):
# If godot was specified or hard coded, verify file
if godot != "":
if os.path.isfile(godot):
return godot
else:
print ("Error: %s is not a valid file." %godot)
print_usage()
# Otherwise search for it
# Match a filename like these
#godot.windows.opt.tools.64.exe
#godot.x11.opt.tools.64
#regex = r"godot\.(windows|x11|osx)(\.opt)?(\.tools)?\.(32|64)(\.exe)?"
bindir='../../../../bin/'
if sys.platform == "win32" or sys.platform == "cygwin":
filemask= 'godot.*.exe'
else:
filemask = 'godot.*.[36][24]'
binfiles = glob.glob(bindir+filemask)
if len(binfiles)>0:
return binfiles[0]
print ("Error: Godot binary not specified and none found in %s" %bindir)
print_usage()
###########################
## Main()
def main():
pass
# If called from command line
if __name__ == "__main__":
verbose = False
try:
opts, args = getopt.getopt(sys.argv[1:], "hvg:o:", "help")
except getopt.error as msg:
print ("Error: ", msg )
print_usage()
for opt, arg in opts:
if opt in ('-h', '--help'):
print_usage()
if opt == '-g':
GD = arg
if opt == '-o':
OUT = arg
if opt == '-v':
verbose = True
# Ensure output directory has a trailing slash
if OUT[-1:] != '/':
OUT += '/'
GD = find_godot(GD)
if verbose:
print ("Found Godot at: %s" %GD)
# Finished GD and directory checks. Build the files.
build_gdscript_api(verbose)

225
doc/tools/xmlproc.py Executable file
View File

@ -0,0 +1,225 @@
#!/usr/bin/python
# coding: utf-8
# Converts a Godot Class XML file to an MD file
#
# There is nothing configurable in this file
# Run it without arguments for usage
import sys
import re
import xml.etree.ElementTree as ET
from time import gmtime, strftime
########################################
## Functions
# Get an attribute of the specified node
# Returns "" on failure; safe for concatenation
#
# Apply prefix/suffix: "before %s after"
#
# Example use:
#
# Get i.attrib['name'] if it exists:
#
# get_attr(i, 'name')
#
# Get a child element of i called <return>, get its .attrib['type'],
# prepend " -> ", and append "\n", but only if <return> and 'type' exist.
#
# get_attr(i.find('return'), 'type', " -> %s\n")
#
def get_attr(node, key, string="%s"):
if node is None:
return ""
if key in node.attrib:
subs = string.split("%s", 1)
return subs[0] + node.attrib[key] + subs[1]
else:
return ""
# Gets the text from a block, or from a named child block (e.g <description>)
# Prefix/suffix string format: "before %s after"
# Returns "" on failure, safe for concatenation
def get_text(node, key, string="%s", reformat=True):
if node is None:
return ""
if key == "": # If no key, use the specified node
n = node
else:
n = node.find(key) # If key, search for first child named key
if n is not None:
if reformat:
out = n.text.strip()
out = re.sub(r'\s\s+', r'\n\n', out)
else:
out = n.text
if out != "":
subs = string.split("%s", 1)
return subs[0] + out + subs[1]
return ""
# Processes Godot's property/function/signals/constants xml
def dump_group (node, search, header):
output = "## " + header + "\n\n"
elems = node.findall(search)
for i in elems:
# Element delimeter
output += "#### » "
# Method return type
output += get_attr(i.find('return'), 'type', "%s ")
# Property Type
output += get_attr(i, 'type', "%s ")
# Enum Constant
output += get_attr(i, 'enum', "%s.")
# Name of element
output += get_attr(i, 'name')
# Method arguments, types, defaults, and qualifiers
if i.tag == 'method':
output += " ( "
args = i.findall('argument')
for j in args:
output += get_attr(j, 'type', "%s ") + get_attr(j, 'name')
output += get_attr(j, 'default', "=%s")
if j != args[-1]:
output += ", "
output += " ) " + get_attr(i, 'qualifiers', " %s")
output += "\n"
# Enum value
output += get_attr(i, 'value', " = %s\n")
# Properties: Setter/Getters
if i.tag=='member':
output += "\n"
output += get_attr(i, 'setter', "\n`%s (value)` setter\n")
output += get_attr(i, 'getter', "\n`%s ()` getter\n")
# Any text within the current block
output += get_text(i, '', "\n%s\n\n")
# Any <description> child
output += get_text(i, 'description', "\n%s\n\n")
output += "\n\n"
output += "\n"
return output
# Use '-' for f_out to print to stdout
def process_xml(f_xml, f_out):
# Parse XML and XSLT
tree = ET.parse(f_xml)
root = tree.getroot()
if root.tag != "class":
print ("Error: No class found. Not a valid Godot class XML file!\n")
sys.exit(1)
# Header
out = get_attr(root, 'name', "# Class: %s\n\n")
out += get_attr(root, 'inherits', "Inherits: %s\n\n")
out += get_attr(root, 'version', "_Godot version: %s_\n\n")
out += "\n"
out += get_text(tree, './/brief_description', "## Brief Description: \n\n%s\n\n\n")
out += get_text(tree, './/description', "## Class Description: \n\n%s\n\n\n")
e = tree.find(".//tutorials")
if e is not None:
out += "## Online Tutorials: \n\n"
out += get_text(e, '', "%s\n") # Any general text in tutorials
for i in e:
out += get_text(i, '', "* %s\n")
out += "\n\n"
# Main body sections
out += dump_group(tree, "constants/constant", "Constants:")
out += dump_group(tree, "members/member", "Properties:")
out += dump_group(tree, "methods/method", "Methods:")
out += dump_group(tree, "signals/signal", "Signals:")
# Format BB code
out = out.replace("[code]", "`")
out = out.replace("[/code]", "`")
out = out.replace("[b]", "**")
out = out.replace("[/b]", "**")
out = re.sub(r'\[method (\S+)\]', r'`\1()`', out)
out = re.sub(r'\[(member )?(\S+)\]', r'`\2`', out)
# Footer
out += "---\n* [Class List](Class_List.md)\n* [Doc Index](../01_get-started.md)\n\n"
out += "_Generated on " + strftime("%b %d, %Y", gmtime()) + "_\n"
#Full time stamp "%Y-%m-%d %H:%M:%S %z"
if f_out == '-':
print(out)
else:
outfile = open(f_out, 'a')
outfile.write(out)
###########################
## Main()
def main():
pass
# If called from command line
if __name__ == "__main__":
# Print usage if no args
if len(sys.argv) < 2:
print("Usage: %s infile [outfile]" % sys.argv[0]);
print("Prints to stdout if outfile is not specified.\n");
sys.exit(0)
# Input file
infile = sys.argv[1]
# Print to screen if no output
if len(sys.argv) < 3:
outfile = "-"
else:
outfile = sys.argv[2]
process_xml(infile, outfile)