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 }