1 /**
2 Copyright: Copyright (c) 2017-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.world.mesh.sidemeshers.utils;
7 
8 import voxelman.math : ubvec3;
9 import voxelman.container.buffer : Buffer;
10 import voxelman.world.mesh.vertex : MeshVertex;
11 import voxelman.world.mesh.config;
12 
13 float random(uint num) pure nothrow
14 {
15 	uint x = num;
16 	x = ((x >> 16) ^ x) * 0x45d9f3b;
17 	x = ((x >> 16) ^ x) * 0x45d9f3b;
18 	x = (x >> 16) ^ x;
19 	return (cast(float)x / uint.max);
20 }
21 
22 float calcRandomTint(ushort index) pure nothrow
23 {
24 	return random(index)*0.1+0.9;
25 }
26 
27 ubvec3 calcColor(ushort index, ubvec3 color) pure nothrow
28 {
29 	float randomTint = calcRandomTint(index);
30 	return ubvec3(
31 		color.r * randomTint,
32 		color.g * randomTint,
33 		color.b * randomTint);
34 }
35 
36 immutable float[] shadowMultipliers = [
37 	0.85, 0.9, 0.75, 0.8, 1, 0.7,
38 ];
39 
40 struct SideParams
41 {
42 	ubvec3 blockPos;
43 	ubvec3 color;
44 	ubyte[2] uv;
45 	ubyte rotation;
46 	Buffer!MeshVertex* buffer;
47 }
48 
49 enum AO_VALUE_0 = 0.70f;
50 enum AO_VALUE_1 = 0.80f;
51 enum AO_VALUE_2 = 0.9f;
52 enum AO_VALUE_3 = 1.0f;
53 
54 immutable float[] occlusionTable = [
55 	            // * C LT - center, corner, left, top
56 	AO_VALUE_3, //   0 00 case 3
57 	AO_VALUE_2, //   0 01 case 2
58 	AO_VALUE_2, //   0 10 case 2
59 	AO_VALUE_0, //   0 11 case 0
60 	AO_VALUE_2, //   1 00 case 2
61 	AO_VALUE_1, //   1 01 case 1
62 	AO_VALUE_1, //   1 10 case 1
63 	AO_VALUE_0, //   1 11 case 0
64 
65 	AO_VALUE_2, // 1 0 00
66 	AO_VALUE_1, // 1 0 01
67 	AO_VALUE_1, // 1 0 10
68 	AO_VALUE_0, // 1 0 11
69 	AO_VALUE_0, // 1 1 00
70 	AO_VALUE_1, // 1 1 01
71 	AO_VALUE_1, // 1 1 10
72 	AO_VALUE_0, // 1 1 11
73 ];
74 
75 enum AO_COLOR_0 = Colors.violet;
76 enum AO_COLOR_1 = Colors.red;
77 enum AO_COLOR_2 = Colors.orange;
78 enum AO_COLOR_3 = Colors.white;
79 
80 import voxelman.graphics.color;
81 immutable Color4ub[] aoDebugColors = [
82 	            // * C LT - center, corner, left, top
83 	AO_COLOR_3, //   0 00 case 3
84 	AO_COLOR_2, //   0 01 case 2
85 	AO_COLOR_2, //   0 10 case 2
86 	AO_COLOR_0, //   0 11 case 0
87 	AO_COLOR_2, //   1 00 case 2
88 	AO_COLOR_1, //   1 01 case 1
89 	AO_COLOR_1, //   1 10 case 1
90 	AO_COLOR_0, //   1 11 case 0
91 
92 	AO_COLOR_2, // 1 0 00
93 	AO_COLOR_1, // 1 0 01
94 	AO_COLOR_1, // 1 0 10
95 	AO_COLOR_0, // 1 0 11
96 	AO_COLOR_0, // 1 1 00
97 	AO_COLOR_1, // 1 1 01
98 	AO_COLOR_1, // 1 1 10
99 	AO_COLOR_0, // 1 1 11
100 ];
101 
102 ubyte[3][4] getDebugAOColors(ubyte[4] cornerOcclusion)
103 {
104 	return [
105 		aoDebugColors[cornerOcclusion[0]].rgb.arrayof,
106 		aoDebugColors[cornerOcclusion[1]].rgb.arrayof,
107 		aoDebugColors[cornerOcclusion[2]].rgb.arrayof,
108 		aoDebugColors[cornerOcclusion[3]].rgb.arrayof,
109 	];
110 }
111 
112 //pragma(inline, true)
113 void meshOccludedQuad(T)(
114 	ref Buffer!MeshVertex buffer,
115 	ubyte[4] cornerOcclusion,
116 	const float[3] color,
117 	ubyte[2] uv,
118 	const ubvec3 offset,
119 	const ubyte[4] indices,
120 	const T[3]* vertieces)
121 {
122 	// Ambient occlusion multipliers
123 	ubyte vert0AoMult = cast(ubyte)(255 * occlusionTable[cornerOcclusion[0]]);
124 	ubyte vert1AoMult = cast(ubyte)(255 * occlusionTable[cornerOcclusion[1]]);
125 	ubyte vert2AoMult = cast(ubyte)(255 * occlusionTable[cornerOcclusion[2]]);
126 	ubyte vert3AoMult = cast(ubyte)(255 * occlusionTable[cornerOcclusion[3]]);
127 
128 	//static if (AO_DEBUG_ENABLED)
129 	//	immutable ubyte[3][4] finalColors = getDebugAOColors(cornerOcclusion);
130 	//else
131 	//	immutable ubyte[3][4] finalColors = [
132 	//		[cast(ubyte)(vert0AoMult * color[0]), cast(ubyte)(vert0AoMult * color[1]), cast(ubyte)(vert0AoMult * color[2])],
133 	//		[cast(ubyte)(vert1AoMult * color[0]), cast(ubyte)(vert1AoMult * color[1]), cast(ubyte)(vert1AoMult * color[2])],
134 	//		[cast(ubyte)(vert2AoMult * color[0]), cast(ubyte)(vert2AoMult * color[1]), cast(ubyte)(vert2AoMult * color[2])],
135 	//		[cast(ubyte)(vert3AoMult * color[0]), cast(ubyte)(vert3AoMult * color[1]), cast(ubyte)(vert3AoMult * color[2])]];
136 	immutable ubyte[4] finalColors = [vert0AoMult, vert1AoMult, vert2AoMult, vert3AoMult];
137 	immutable ubyte[2][4] uvs = [uv, [uv[0], cast(ubyte)(uv[1]+1)], [cast(ubyte)(uv[0]+1), cast(ubyte)(uv[1]+1)], [cast(ubyte)(uv[0]+1), uv[1]]];
138 
139 	if(vert0AoMult + vert2AoMult > vert1AoMult + vert3AoMult)
140 	{
141 		meshQuadUvGray!true(buffer, finalColors, uvs, offset, indices, vertieces);
142 	}
143 	else
144 	{
145 		meshQuadUvGray!false(buffer, finalColors, uvs, offset, indices, vertieces);
146 	}
147 }
148 
149 //pragma(inline, true)
150 void meshColoredQuad(bool flipped, T)(
151 	ref Buffer!MeshVertex buffer,
152 	ref const ubyte[3][4] cornerColors,
153 	const ubvec3 offset,
154 	const ubyte[4] indices,
155 	const T[3]* vertieces)
156 {
157 	// index order
158 	static if (flipped)
159 		enum ind {i0=1, i1=2, i2=0, i3=0, i4=2, i5=3}
160 	else
161 		enum ind {i0=1, i1=3, i2=0, i3=1, i4=2, i5=3}
162 
163 	buffer.put(
164 		MeshVertex(
165 			vertieces[indices[ind.i0]][0] + offset.x,
166 			vertieces[indices[ind.i0]][1] + offset.y,
167 			vertieces[indices[ind.i0]][2] + offset.z,
168 			cornerColors[ind.i0]),
169 		MeshVertex(
170 			vertieces[indices[ind.i1]][0] + offset.x,
171 			vertieces[indices[ind.i1]][1] + offset.y,
172 			vertieces[indices[ind.i1]][2] + offset.z,
173 			cornerColors[ind.i1]),
174 		MeshVertex(
175 			vertieces[indices[ind.i2]][0] + offset.x,
176 			vertieces[indices[ind.i2]][1] + offset.y,
177 			vertieces[indices[ind.i2]][2] + offset.z,
178 			cornerColors[ind.i2]),
179 		MeshVertex(
180 			vertieces[indices[ind.i3]][0] + offset.x,
181 			vertieces[indices[ind.i3]][1] + offset.y,
182 			vertieces[indices[ind.i3]][2] + offset.z,
183 			cornerColors[ind.i3]),
184 		MeshVertex(
185 			vertieces[indices[ind.i4]][0] + offset.x,
186 			vertieces[indices[ind.i4]][1] + offset.y,
187 			vertieces[indices[ind.i4]][2] + offset.z,
188 			cornerColors[ind.i4]),
189 		MeshVertex(
190 			vertieces[indices[ind.i5]][0] + offset.x,
191 			vertieces[indices[ind.i5]][1] + offset.y,
192 			vertieces[indices[ind.i5]][2] + offset.z,
193 			cornerColors[ind.i5])
194 	);
195 }
196 
197 void meshQuadUvGray(bool flipped, T)(
198 	ref Buffer!MeshVertex buffer,
199 	ref const ubyte[4] cornerColors,
200 	ref const ubyte[2][4] cornerUVs,
201 	const ubvec3 offset,
202 	const ubyte[4] indices,
203 	const T[3]* vertieces)
204 {
205 	// index order
206 	static if (flipped)
207 		enum ind {i0=1, i1=2, i2=0, i3=0, i4=2, i5=3}
208 	else
209 		enum ind {i0=1, i1=3, i2=0, i3=1, i4=2, i5=3}
210 
211 	MeshVertex[] buf = buffer.voidPut(6);
212 	buf[0].set(
213 		vertieces[indices[ind.i0]][0] + offset.x,
214 		vertieces[indices[ind.i0]][1] + offset.y,
215 		vertieces[indices[ind.i0]][2] + offset.z,
216 		cornerUVs[ind.i0],
217 		cornerColors[ind.i0]);
218 	buf[1].set(
219 		vertieces[indices[ind.i1]][0] + offset.x,
220 		vertieces[indices[ind.i1]][1] + offset.y,
221 		vertieces[indices[ind.i1]][2] + offset.z,
222 		cornerUVs[ind.i1],
223 		cornerColors[ind.i1]);
224 	buf[2].set(
225 		vertieces[indices[ind.i2]][0] + offset.x,
226 		vertieces[indices[ind.i2]][1] + offset.y,
227 		vertieces[indices[ind.i2]][2] + offset.z,
228 		cornerUVs[ind.i2],
229 		cornerColors[ind.i2]);
230 	buf[3].set(
231 		vertieces[indices[ind.i3]][0] + offset.x,
232 		vertieces[indices[ind.i3]][1] + offset.y,
233 		vertieces[indices[ind.i3]][2] + offset.z,
234 		cornerUVs[ind.i3],
235 		cornerColors[ind.i3]);
236 	buf[4].set(
237 		vertieces[indices[ind.i4]][0] + offset.x,
238 		vertieces[indices[ind.i4]][1] + offset.y,
239 		vertieces[indices[ind.i4]][2] + offset.z,
240 		cornerUVs[ind.i4],
241 		cornerColors[ind.i4]);
242 	buf[5].set(
243 		vertieces[indices[ind.i5]][0] + offset.x,
244 		vertieces[indices[ind.i5]][1] + offset.y,
245 		vertieces[indices[ind.i5]][2] + offset.z,
246 		cornerUVs[ind.i5],
247 		cornerColors[ind.i5]);
248 }