1 /** 2 Copyright: Copyright (c) 2016-2017 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module voxelman.edit.tools.filltool; 8 9 import voxelman.container.buffer; 10 import voxelman.log; 11 import voxelman.math; 12 import voxelman.geometry.cube; 13 import voxelman.core.config; 14 import voxelman.core.packets; 15 import voxelman.world.storage; 16 import voxelman.world.block.utils; 17 import voxelman.world.mesh.meshgenerator : SingleBlockMesher; 18 19 import voxelman.client.plugin; 20 import voxelman.worldinteraction.plugin; 21 import voxelman.graphics.plugin; 22 import voxelman.net.plugin; 23 24 import voxelman.edit.plugin; 25 26 final class FillTool : ITool 27 { 28 WorldInteractionPlugin worldInteraction; 29 NetClientPlugin connection; 30 BlockInfoTable blockInfos; 31 32 BlockIdAndMeta currentBlock = BlockIdAndMeta(4); 33 ubyte currentRotation = 0; 34 35 BlockWorldPos startingPos; 36 EditState state; 37 WorldBox selection; 38 bool showCursor = true; 39 Buffer!ColoredVertex cursorBuffer; 40 41 SingleBlockMesher blockMesher; 42 43 enum EditState 44 { 45 none, 46 placing, 47 removing 48 } 49 50 this() { name = "voxelman.edit.fill_tool"; } 51 52 override void onUpdate() { 53 if (currentCursorPos.w != startingPos.w) 54 { 55 startingPos = currentCursorPos; 56 } 57 selection = worldBoxFromCorners(startingPos.vector.xyz, currentCursorPos.vector.xyz, cast(DimensionId)currentCursorPos.w); 58 59 if (state != EditState.placing) 60 updateBlockRotation(); 61 } 62 63 override void onRender(GraphicsPlugin graphics) { 64 import derelict.opengl3.gl3; 65 drawSelection(graphics); 66 if (showCursor && !worldInteraction.cameraInSolidBlock) 67 { 68 //worldInteraction.drawCursor(worldInteraction.blockPos, Colors.red); 69 //worldInteraction.drawCursor(worldInteraction.sideBlockPos, Colors.blue); 70 71 blockMesher.meshBlock(blockInfos[currentBlock.id], currentBlock.metadata); 72 graphics.transparentBuffer.putMesh(blockMesher.geometry.data, vec3(worldInteraction.sideBlockPos.xyz)); 73 //graphics.drawBuffer3d(cursorBuffer.data, GL_TRIANGLES); 74 75 //foreach(ref vert; cursorBuffer.data) 76 // vert.color = Color4ub(0,0,0,255); 77 78 79 glEnable(GL_POLYGON_OFFSET_LINE); 80 glPolygonOffset(-1, 1); 81 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 82 //graphics.drawBuffer3d(cursorBuffer.data, GL_TRIANGLES); 83 84 //cursorBuffer.clear(); 85 cursorBuffer.putLineBlock(vec3(worldInteraction.blockPos.xyz), vec3(1,1,1), Colors.red); 86 cursorBuffer.putLineBlock(vec3(worldInteraction.sideBlockPos.xyz), vec3(1,1,1), Colors.blue); 87 graphics.drawBuffer3d(cursorBuffer.data, GL_LINES); 88 glPolygonOffset(0,0); 89 90 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 91 glDisable(GL_POLYGON_OFFSET_LINE); 92 93 cursorBuffer.clear(); 94 blockMesher.reset(); 95 } 96 } 97 98 BlockWorldPos currentCursorPos() @property { 99 final switch(state) { 100 case EditState.none: return worldInteraction.blockPos; 101 case EditState.placing: 102 return worldInteraction.sideBlockPos; 103 case EditState.removing: 104 return worldInteraction.blockPos; 105 } 106 } 107 108 void drawSelection(GraphicsPlugin graphics) { 109 final switch(state) { 110 case EditState.none: 111 break; 112 case EditState.placing: 113 graphics.debugBatch.putCube(vec3(selection.position) - cursorOffset, 114 vec3(selection.size) + cursorOffset, Colors.blue, false); 115 break; 116 case EditState.removing: 117 graphics.debugBatch.putCube(vec3(selection.position) - cursorOffset, 118 vec3(selection.size) + cursorOffset, Colors.red, false); 119 break; 120 } 121 } 122 123 override void onMainActionPress() { 124 if (state != EditState.none) return; 125 if (!worldInteraction.cursorHit) return; 126 state = EditState.removing; 127 startingPos = currentCursorPos; 128 showCursor = false; 129 } 130 131 override void onMainActionRelease() { 132 if (state != EditState.removing) return; 133 state = EditState.none; 134 showCursor = true; 135 136 if (worldInteraction.cursorHit) 137 { 138 worldInteraction.fillBox(selection, 1); 139 } 140 } 141 142 override void onSecondaryActionPress() { 143 if (state != EditState.none) return; 144 if (!worldInteraction.cursorHit) return; 145 state = EditState.placing; 146 startingPos = currentCursorPos; 147 showCursor = false; 148 } 149 150 override void onSecondaryActionRelease() { 151 if (state != EditState.placing) return; 152 state = EditState.none; 153 showCursor = true; 154 155 if (worldInteraction.cursorHit) 156 { 157 worldInteraction.fillBox(selection, currentBlock.id, currentBlock.metadata); 158 } 159 } 160 161 override void onTertiaryActionRelease() { 162 setCurrentBlock(worldInteraction.pickBlock()); 163 } 164 165 override void onRotateAction() { 166 currentRotation = (currentRotation + 1) % 4; 167 updateBlockRotation(); 168 } 169 170 void updateBlockRotation() { 171 if (auto handler = blockInfos[currentBlock.id].rotationHandler) 172 { 173 CubeSide side = oppSide[sideFromNormal(worldInteraction.hitNormal)]; 174 handler(currentBlock.metadata, currentRotation, side); 175 } 176 } 177 178 void setCurrentBlock(BlockIdAndMeta block) { 179 currentBlock = block; 180 } 181 }