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 }