1 /**
2 Copyright: Copyright (c) 2017 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.block.utils : MeshVertex2;
11 import voxelman.world.mesh.chunkmesh : MeshVertex;
12 import voxelman.world.mesh.config;
13 
14 float random(uint num) pure nothrow
15 {
16 	uint x = num;
17 	x = ((x >> 16) ^ x) * 0x45d9f3b;
18 	x = ((x >> 16) ^ x) * 0x45d9f3b;
19 	x = (x >> 16) ^ x;
20 	return (cast(float)x / uint.max);
21 }
22 
23 float calcRandomTint(ushort index) pure nothrow
24 {
25 	return random(index)*0.1+0.9;
26 }
27 
28 ubvec3 calcColor(ushort index, ubvec3 color) pure nothrow
29 {
30 	float randomTint = calcRandomTint(index);
31 	return ubvec3(
32 		color.r * randomTint,
33 		color.g * randomTint,
34 		color.b * randomTint);
35 }
36 
37 immutable(float[]) shadowMultipliers = [
38 	0.8, 0.85, 0.7, 0.75, 0.95, 0.65,
39 ];
40 
41 struct SideParams
42 {
43 	ubvec3 blockPos;
44 	ubvec3 color;
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 __gshared 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 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 	const ubvec3 offset,
118 	const ubyte[4] indices,
119 	const T[3]* vertieces)
120 {
121 	// Ambient occlusion multipliers
122 	float vert0AoMult = occlusionTable[cornerOcclusion[0]];
123 	float vert1AoMult = occlusionTable[cornerOcclusion[1]];
124 	float vert2AoMult = occlusionTable[cornerOcclusion[2]];
125 	float vert3AoMult = occlusionTable[cornerOcclusion[3]];
126 
127 	static if (AO_DEBUG_ENABLED)
128 		immutable ubyte[3][4] finalColors = getDebugAOColors(cornerOcclusion);
129 	else
130 		immutable ubyte[3][4] finalColors = [
131 			[cast(ubyte)(vert0AoMult * color[0]), cast(ubyte)(vert0AoMult * color[1]), cast(ubyte)(vert0AoMult * color[2])],
132 			[cast(ubyte)(vert1AoMult * color[0]), cast(ubyte)(vert1AoMult * color[1]), cast(ubyte)(vert1AoMult * color[2])],
133 			[cast(ubyte)(vert2AoMult * color[0]), cast(ubyte)(vert2AoMult * color[1]), cast(ubyte)(vert2AoMult * color[2])],
134 			[cast(ubyte)(vert3AoMult * color[0]), cast(ubyte)(vert3AoMult * color[1]), cast(ubyte)(vert3AoMult * color[2])]];
135 
136 	if(vert0AoMult + vert2AoMult > vert1AoMult + vert3AoMult)
137 	{
138 		meshColoredQuad!true(buffer, finalColors, offset, indices, vertieces);
139 	}
140 	else
141 	{
142 		meshColoredQuad!false(buffer, finalColors, offset, indices, vertieces);
143 	}
144 }
145 
146 pragma(inline, true)
147 void meshColoredQuad(bool flipped, T)(
148 	ref Buffer!MeshVertex buffer,
149 	ref const ubyte[3][4] cornerColors,
150 	const ubvec3 offset,
151 	const ubyte[4] indices,
152 	const T[3]* vertieces)
153 {
154 	// index order
155 	static if (flipped)
156 		enum ind {i0=1, i1=2, i2=0, i3=0, i4=2, i5=3}
157 	else
158 		enum ind {i0=1, i1=3, i2=0, i3=1, i4=2, i5=3}
159 
160 	buffer.put(
161 		cast(MeshVertex)MeshVertex2(
162 			vertieces[indices[ind.i0]][0] + offset.x,
163 			vertieces[indices[ind.i0]][1] + offset.y,
164 			vertieces[indices[ind.i0]][2] + offset.z,
165 			cornerColors[ind.i0]),
166 		cast(MeshVertex)MeshVertex2(
167 			vertieces[indices[ind.i1]][0] + offset.x,
168 			vertieces[indices[ind.i1]][1] + offset.y,
169 			vertieces[indices[ind.i1]][2] + offset.z,
170 			cornerColors[ind.i1]),
171 		cast(MeshVertex)MeshVertex2(
172 			vertieces[indices[ind.i2]][0] + offset.x,
173 			vertieces[indices[ind.i2]][1] + offset.y,
174 			vertieces[indices[ind.i2]][2] + offset.z,
175 			cornerColors[ind.i2]),
176 		cast(MeshVertex)MeshVertex2(
177 			vertieces[indices[ind.i3]][0] + offset.x,
178 			vertieces[indices[ind.i3]][1] + offset.y,
179 			vertieces[indices[ind.i3]][2] + offset.z,
180 			cornerColors[ind.i3]),
181 		cast(MeshVertex)MeshVertex2(
182 			vertieces[indices[ind.i4]][0] + offset.x,
183 			vertieces[indices[ind.i4]][1] + offset.y,
184 			vertieces[indices[ind.i4]][2] + offset.z,
185 			cornerColors[ind.i4]),
186 		cast(MeshVertex)MeshVertex2(
187 			vertieces[indices[ind.i5]][0] + offset.x,
188 			vertieces[indices[ind.i5]][1] + offset.y,
189 			vertieces[indices[ind.i5]][2] + offset.z,
190 			cornerColors[ind.i5])
191 	);
192 }