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 }