diff --git a/assets/Data/entity/items/debug_tools.json b/assets/Data/entity/items/debug_tools.json index e34892ed..23306fb4 100644 --- a/assets/Data/entity/items/debug_tools.json +++ b/assets/Data/entity/items/debug_tools.json @@ -132,7 +132,7 @@ "tokens" : [ "GRAVITY", "TARGETABLE", - "CURSOR" + "CURSOR_FAB" ], "equipData": { "equipClass" : "tool" diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 15414786..b7d761c5 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1544,6 +1544,8 @@ Exporting block prefabs to compressed files Minor block fab improvements Fab selection tool Fab selection tool actually loads fab files +Fix fab file reading +Fab tool can show transparent, loaded version of fab file diff --git a/src/main/java/electrosphere/client/block/BlockChunkData.java b/src/main/java/electrosphere/client/block/BlockChunkData.java index d84b8e26..56718b46 100644 --- a/src/main/java/electrosphere/client/block/BlockChunkData.java +++ b/src/main/java/electrosphere/client/block/BlockChunkData.java @@ -2,12 +2,13 @@ package electrosphere.client.block; import org.joml.Vector3i; +import electrosphere.renderer.meshgen.BlockMeshgenData; import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; /** * Stores data about a chunk of blocks */ -public class BlockChunkData { +public class BlockChunkData implements BlockMeshgenData { /** * Number of blocks in each dimension of a chunk @@ -283,7 +284,7 @@ public class BlockChunkData { * @return true if empty, false otherwise */ public boolean isEmpty(int x, int y, int z){ - boolean empty = this.getType(x,y,z) == 0; + boolean empty = this.getType(x,y,z) == BlockChunkData.BLOCK_TYPE_EMPTY; return empty; } @@ -391,4 +392,13 @@ public class BlockChunkData { this.setHomogenousValue((short)homogenousValue); } + @Override + public Vector3i getDimensions() { + return new Vector3i( + BlockChunkData.CHUNK_DATA_WIDTH, + BlockChunkData.CHUNK_DATA_WIDTH, + BlockChunkData.CHUNK_DATA_WIDTH + ); + } + } diff --git a/src/main/java/electrosphere/client/block/ClientBlockSelection.java b/src/main/java/electrosphere/client/block/ClientBlockSelection.java index 8c541749..4928b16e 100644 --- a/src/main/java/electrosphere/client/block/ClientBlockSelection.java +++ b/src/main/java/electrosphere/client/block/ClientBlockSelection.java @@ -115,7 +115,7 @@ public class ClientBlockSelection { BlockFab fab = BlockFab.create(dimensions, types, metadata); File exportLoc = new File("./assets/Data/fab/struct.block"); - fab.save(exportLoc); + fab.write(exportLoc); } } diff --git a/src/main/java/electrosphere/client/ui/menu/ingame/FabMenus.java b/src/main/java/electrosphere/client/ui/menu/ingame/FabMenus.java index b52e9d5a..1de4ba15 100644 --- a/src/main/java/electrosphere/client/ui/menu/ingame/FabMenus.java +++ b/src/main/java/electrosphere/client/ui/menu/ingame/FabMenus.java @@ -58,6 +58,7 @@ public class FabMenus { fabSelectionPanelWindow.addChild(FabSelectionPanel.createFabSelectionPanel((File selectedFile) -> { BlockFab fab = BlockFab.read(selectedFile); LoggerInterface.loggerEngine.WARNING("" + fab.getDimensions()); + Globals.cursorState.setSelectedFab(fab); })); Globals.signalSystem.post(SignalType.YOGA_APPLY,fabSelectionPanelWindow); diff --git a/src/main/java/electrosphere/controls/cursor/CursorState.java b/src/main/java/electrosphere/controls/cursor/CursorState.java index 054aefd7..1ee18d41 100644 --- a/src/main/java/electrosphere/controls/cursor/CursorState.java +++ b/src/main/java/electrosphere/controls/cursor/CursorState.java @@ -11,13 +11,16 @@ import electrosphere.client.interact.select.AreaSelection; import electrosphere.collision.CollisionEngine; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.AssetDataStrings; +import electrosphere.engine.assetmanager.queue.QueuedModel; import electrosphere.entity.DrawableUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; +import electrosphere.game.data.block.BlockFab; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorTextureMask; +import electrosphere.renderer.meshgen.BlockMeshgen; import electrosphere.renderer.ui.events.ScrollEvent; /** @@ -40,6 +43,11 @@ public class CursorState { */ public static final String CURSOR_AREA_TOKEN = "CURSOR_AREA"; + /** + * Cursor that displays a fab + */ + public static final String CURSOR_FAB_TOKEN = "CURSOR_FAB"; + /** * Minimum size of the block cursor */ @@ -65,6 +73,11 @@ public class CursorState { */ private AreaSelection areaCursorSelection = null; + /** + * The fab cursor + */ + static Entity playerFabCursor; + /** * Creates the cursor entities */ @@ -95,6 +108,14 @@ public class CursorState { DrawableUtils.makeEntityTransparent(Globals.playerAreaCursor); EntityUtils.getScale(Globals.playerAreaCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER); Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE); + + //player's fab cursor + playerFabCursor = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(playerFabCursor, AssetDataStrings.UNITCUBE); + Actor fabCursorActor = EntityUtils.getActor(playerFabCursor); + fabCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"}))); + DrawableUtils.makeEntityTransparent(playerFabCursor); + Globals.clientSceneWrapper.getScene().removeEntityFromTag(playerFabCursor, EntityTags.DRAWABLE); } /** @@ -119,6 +140,7 @@ public class CursorState { //clamp block cursor to nearest voxel cursorPos.set(this.clampPositionToNearestBlock(cursorPos)); EntityUtils.getPosition(Globals.playerBlockCursor).set(cursorPos); + EntityUtils.getPosition(CursorState.playerFabCursor).set(cursorPos); } } @@ -126,8 +148,7 @@ public class CursorState { * Makes the real position cursor visible */ public static void makeRealVisible(){ - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE); - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE); + CursorState.hide(); Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerCursor, EntityTags.DRAWABLE); } @@ -135,8 +156,7 @@ public class CursorState { * Makes the block position cursor visible */ public static void makeBlockVisible(){ - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE); - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE); + CursorState.hide(); Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerBlockCursor, EntityTags.DRAWABLE); } @@ -144,11 +164,18 @@ public class CursorState { * Makes the area position cursor visible */ public static void makeAreaVisible(){ - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE); - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE); + CursorState.hide(); Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerAreaCursor, EntityTags.DRAWABLE); } + /** + * Makes the fab placement cursor visible + */ + public static void makeFabVisible(){ + CursorState.hide(); + Globals.clientSceneWrapper.getScene().registerEntityToTag(CursorState.playerFabCursor, EntityTags.DRAWABLE); + } + /** * Hides the cursor */ @@ -156,6 +183,7 @@ public class CursorState { Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE); Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE); Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerAreaCursor, EntityTags.DRAWABLE); + Globals.clientSceneWrapper.getScene().removeEntityFromTag(CursorState.playerFabCursor, EntityTags.DRAWABLE); } /** @@ -258,6 +286,23 @@ public class CursorState { } EntityUtils.getScale(Globals.playerBlockCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER * this.blockSize); } + + /** + * Sets the block fab cursor's current fab + * @param fab The fab + */ + public void setSelectedFab(BlockFab fab){ + QueuedModel queuedModel = new QueuedModel(() -> { + return BlockMeshgen.generateBlockModel(BlockMeshgen.rasterize(fab)); + }); + Globals.assetManager.queuedAsset(queuedModel); + EntityCreationUtils.makeEntityDrawablePreexistingModel(playerFabCursor, queuedModel.getPromisedPath()); + Actor fabCursorActor = EntityUtils.getActor(playerFabCursor); + fabCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"}))); + DrawableUtils.makeEntityTransparent(playerFabCursor); + + CursorState.makeFabVisible(); + } /** * Gets the size of the block cursor diff --git a/src/main/java/electrosphere/game/data/block/BlockFab.java b/src/main/java/electrosphere/game/data/block/BlockFab.java index ab7fd5e9..ca35667b 100644 --- a/src/main/java/electrosphere/game/data/block/BlockFab.java +++ b/src/main/java/electrosphere/game/data/block/BlockFab.java @@ -10,12 +10,13 @@ import org.joml.Vector3i; import electrosphere.client.block.BlockChunkData; import electrosphere.logger.LoggerInterface; +import electrosphere.renderer.meshgen.BlockMeshgenData; import electrosphere.util.FileUtils; /** * A collection of blocks */ -public class BlockFab { +public class BlockFab implements BlockMeshgenData { /** * File version format @@ -63,10 +64,10 @@ public class BlockFab { } /** - * Saves this fab to a file + * Writes this fab to a file * @param file The file */ - public void save(File file){ + public void write(File file){ int blockCount = dimensions.x * dimensions.y * dimensions.z; @@ -122,6 +123,14 @@ public class BlockFab { for(int y = 0; y < dims.y; y++){ for(int z = 0; z < dims.z; z++){ types[i] = shortView.get(); + i++; + } + } + } + i = 0; + for(int x = 0; x < dims.x; x++){ + for(int y = 0; y < dims.y; y++){ + for(int z = 0; z < dims.z; z++){ metadata[i] = shortView.get(); i++; } @@ -163,4 +172,15 @@ public class BlockFab { return metadata; } + @Override + public boolean isEmpty(int x, int y, int z){ + boolean empty = this.getType(x,y,z) == BlockChunkData.BLOCK_TYPE_EMPTY; + return empty; + } + + @Override + public short getType(int x, int y, int z) { + return this.types[x * dimensions.y * dimensions.z + y * dimensions.z + z]; + } + } diff --git a/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java b/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java index 872e2341..49fd0a8f 100644 --- a/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java +++ b/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java @@ -9,6 +9,7 @@ import java.util.List; import org.joml.Vector2f; import org.joml.Vector3f; +import org.joml.Vector3i; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL40; @@ -66,16 +67,17 @@ public class BlockMeshgen { /** - * Calculates the quad meshes for the provided chunk data + * Calculates the quad meshes for the provided data * @param quadMeshes The quad mesh list to fill - * @param chunkData The chunk data + * @param data The block data */ - protected static void fillQuadMeshes(List quadMeshes, BlockChunkData chunkData){ - for(int z = 0; z < BlockChunkData.CHUNK_DATA_WIDTH; z++){ - for(int x = 0; x < BlockChunkData.CHUNK_DATA_WIDTH; x++){ + protected static void fillQuadMeshes(List quadMeshes, BlockMeshgenData data){ + Vector3i dimensions = data.getDimensions(); + for(int z = 0; z < dimensions.z; z++){ + for(int x = 0; x < dimensions.x; x++){ QuadMesh currentQuad = null; - for(int y = 0; y < BlockChunkData.CHUNK_DATA_WIDTH; y++){ - if(chunkData.isEmpty(x, y, z)){ + for(int y = 0; y < dimensions.y; y++){ + if(data.isEmpty(x, y, z)){ if(currentQuad == null){ continue; } else { @@ -101,12 +103,15 @@ public class BlockMeshgen { currentQuad.z = z; currentQuad.w = 1; currentQuad.h = 1; - currentQuad.type = chunkData.getType(x, y, z); + currentQuad.type = data.getType(x, y, z); } else { continue; } } } + if(currentQuad != null){ + quadMeshes.add(currentQuad); + } } } } @@ -327,7 +332,7 @@ public class BlockMeshgen { * @param chunkData The block chunk data * @return The mesh data */ - public static BlockMeshData rasterize(BlockChunkData chunkData){ + public static BlockMeshData rasterize(BlockMeshgenData chunkData){ BlockMeshData rVal = new BlockMeshData(); //calculate quad meshes diff --git a/src/main/java/electrosphere/renderer/meshgen/BlockMeshgenData.java b/src/main/java/electrosphere/renderer/meshgen/BlockMeshgenData.java new file mode 100644 index 00000000..131d1216 --- /dev/null +++ b/src/main/java/electrosphere/renderer/meshgen/BlockMeshgenData.java @@ -0,0 +1,34 @@ +package electrosphere.renderer.meshgen; + +import org.joml.Vector3i; + +/** + * Interface for data that can be pased to the block meshgen function + */ +public interface BlockMeshgenData { + + /** + * Checks if the data is empty at a position + * @param x The x position + * @param y The y position + * @param z The z position + * @return true if it is empty, false otherwise + */ + public boolean isEmpty(int x, int y, int z); + + /** + * Gets the type at a given position + * @param x The x position + * @param y The y position + * @param z The z position + * @return The type + */ + public short getType(int x, int y, int z); + + /** + * Gets the dimensions of this data + * @return The dimensions + */ + public Vector3i getDimensions(); + +}