Theming - rvandoosselaer/Blocks GitHub Wiki
In Blocks it's easy to change the default textures of the blocks. You can either overwrite the material of an existing type or you can create a theme that links to a directory with textures or material files.
There are 2 options to change the look and feel of a block.
Overriding the grass material
The easiest way of changing the look and feel of a block is by simply overriding the material of that type.
Material myGrassMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
myGrassMaterial.setColor("Color", ColorRGBA.Green);
TypeRegistry typeRegistry = BlocksConfig.getInstance().getTypeRegistry();
typeRegistry.register(TypeIds.GRASS, myGrassMaterial);
result:
full source code:
public class BlocksThemeTest extends SimpleApplication {
public static void main(String[] args) {
BlocksThemeTest blocksThemeTest = new BlocksThemeTest();
blocksThemeTest.start();
}
@Override
public void simpleInitApp() {
BlocksConfig.initialize(assetManager);
Material myGrassMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
myGrassMaterial.setColor("Color", ColorRGBA.Green);
TypeRegistry typeRegistry = BlocksConfig.getInstance().getTypeRegistry();
typeRegistry.register(TypeIds.GRASS, myGrassMaterial);
BlockRegistry blockRegistry = BlocksConfig.getInstance().getBlockRegistry();
Chunk chunk = Chunk.createAt(new Vec3i());
chunk.addBlock(0, 0, 0, blockRegistry.get(BlockIds.GRASS));
chunk.update();
chunk.createNode(BlocksConfig.getInstance().getChunkMeshGenerator());
rootNode.attachChild(chunk.getNode());
}
}
Using a theme
When you want to change the look and feel of multiple blocks, it's probably easier to use a theme to bundle the materials and/or textures of your blocks.
A theme can contain a material file for a type, the texture of a type or even different textures of a type.
In the following example we create a theme and change the look and feel of 3 blocks in different ways.
The first step is to create a theme and set it on the TypeRegistry
. When creating a theme, give it a name and the folder where the files are located.
BlocksTheme myNewTheme = BlocksTheme.builder()
.name("My awesome theme")
.path("/my-awesome-theme/")
.build();
TypeRegistry typeRegistry = BlocksConfig.getInstance().getTypeRegistry();
typeRegistry.setTheme(myNewTheme);
❗️ Make sure the asset manager can access the path where the textures are located!
The files that are loaded by the TypeRegistry
are retrieved from the folder of the theme based on the name of the type.
Material file
You can place a material file in the theme folder. The TypeRegistry
will locate the material file associated with the type and register it. When the type of the block is dirt
, the file dirt.j3m
will be loaded in the theme folder. Type names can be found in the TypeIds interface.
Create the material file in the my-awesome-theme
folder that should be used for the dirt
block.
dirt.j3m:
Material dirt : Common/MatDefs/Misc/Unshaded.j3md {
MaterialParameters {
Color: 0.25 0.16 0.10 1.0
}
}
Combined texture
When a material file couldn't be found for a type, the TypeRegistry
will look for textures associated with the type and register them using the default block material. When the type of the block is oak_log
, the textures oak_log.png
, oak_log-normal.png
and oak_log-parallax.png
will be used in the material. The normal and parallax textures are optional.
If the block should use different images for the top, side and bottom faces, the images should be combined in the same texture file using an image editor.
💡 Depending on the shape, you can use 3 images in the texture. The top, side and bottom images are all in the same texture file. The UV mapping is done so the top part of the texture is used for the top face of the cube, the middle part of the texture is used for the front, left, right and back faces of the cube, the bottom part of the texture is used for the bottom face of the cube.
In the my-awesome-theme
folder we place the texture that should be used for the oak_log
block.
oak_log.png:
Different images for a texture
The TypeRegistry
can combine a texture so you don't need to use an image editor to combine the top image, side image and bottom image into one texture.
When a material file and the texture couldn't be found for a type, the TypeRegistry
will look for images it can combine into a texture and register them using the default block material.
❗️ The images should have exactly the same size and colorspace!
If you want to use different images for the block that uses the grass
type, the image names should be: grass_top.png
, grass_side.png
and grass_bottom.png
.
This will also work for the optional normal and parallax textures. Those filenames should be: grass_top-normal.png
, grass_side-normal.png
, grass_bottom-normal.png
, grass_top-parallax.png
, grass_side-parallax.png
and grass_bottom-parallax.png
.
In the my-awesome-theme
folder we place the images that should be used for the grass
block.
grass_top.png:
grass_side.png:
grass_bottom.png:
The above examples will result in these 3 blocks:
Note that all the logic is handled in the TypeRegistry
. The only thing you need to do is create and set a theme!
💡 When you run your application and don't see the expected result, or a block still has the default texture, it will probably mean that the
TypeRegistry
couldn't locate some of the files. Turn on the logging and check the log of the application for more clues. TheTypeRegistry
creates a log entry for all actions it performs.
full source code:
public class BlocksThemeTest extends SimpleApplication {
public static void main(String[] args) {
BlocksThemeTest blocksThemeTest = new BlocksThemeTest();
blocksThemeTest.start();
}
@Override
public void simpleInitApp() {
BlocksConfig.initialize(assetManager);
assetManager.registerLocator("/Users/rvandoosselaer/.blocks", FileLocator.class);
BlocksTheme myNewTheme = BlocksTheme.builder()
.name("My awesome theme")
.path("/my-awesome-theme/")
.build();
TypeRegistry typeRegistry = BlocksConfig.getInstance().getTypeRegistry();
typeRegistry.setTheme(myNewTheme);
BlockRegistry blockRegistry = BlocksConfig.getInstance().getBlockRegistry();
Chunk chunk = Chunk.createAt(new Vec3i());
chunk.addBlock(0, 0, 0, blockRegistry.get(BlockIds.DIRT));
chunk.addBlock(2, 0, 0, blockRegistry.get(BlockIds.OAK_LOG));
chunk.addBlock(4, 0, 0, blockRegistry.get(BlockIds.GRASS));
chunk.createNode(BlocksConfig.getInstance().getChunkMeshGenerator());
rootNode.attachChild(chunk.getNode());
rootNode.addLight(new AmbientLight(new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f)));
rootNode.addLight(new DirectionalLight(new Vector3f(-0.1f, -1f, -0.1f).normalizeLocal(), ColorRGBA.White));
}
}
Theme folder:
$ cd /Users/rvandoosselaer/.blocks/my-awesome-theme
$ ls -l
dirt.j3m
grass_bottom.png
grass_side.png
grass_top.png
oak_log.png