Last active
April 26, 2021 19:54
-
-
Save Swyter/1a06baf7fe5c057d19229b176dbe34ca to your computer and use it in GitHub Desktop.
cmpxchg8b's TerrainGen code; generates a scene mesh from their respective terrain code, just like Mount&Blade Warband does. Recovered from a corrupted disk, these aren't the original filenames.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Perlin.h" | |
#include "Utils.h" | |
#include <cmath> | |
unsigned char g_perlinPermutationTable[256] = | |
{ | |
198, 12, 146, 95, 44, 18, 240, 28, 151, 32, 45, 20, 30, 23, 141, 248, | |
168, 254, 178, 85, 92, 216, 236, 175, 47, 88, 67, 136, 234, 1, 72, 106, | |
79, 220, 24, 171, 26, 224, 128, 137, 223, 16, 105, 195, 231, 183, 29, 132, | |
241, 122, 252, 135, 5, 181, 130, 213, 49, 204, 70, 176, 144, 35, 64, 104, | |
19, 39, 46, 13, 246, 233, 9, 177, 31, 61, 154, 117, 129, 75, 139, 118, | |
68, 42, 207, 86, 112, 27, 158, 8, 247, 250, 109, 163, 242, 52, 160, 164, | |
43, 83, 62, 190, 57, 155, 169, 98, 6, 51, 38, 150, 80, 84, 114, 14, | |
253, 194, 4, 138, 101, 25, 60, 97, 167, 188, 148, 209, 77, 192, 131, 227, | |
36, 191, 237, 76, 214, 17, 251, 81, 71, 123, 119, 232, 0, 244, 87, 53, | |
66, 126, 187, 110, 107, 2, 212, 93, 74, 211, 249, 63, 102, 113, 255, 11, | |
173, 197, 166, 157, 226, 124, 90, 199, 59, 10, 100, 140, 89, 208, 221, 37, | |
33, 230, 121, 174, 189, 165, 149, 34, 179, 15, 108, 40, 55, 91, 7, 200, | |
147, 120, 134, 56, 184, 133, 115, 202, 245, 94, 82, 152, 116, 143, 210, 206, | |
145, 203, 193, 127, 180, 125, 22, 159, 142, 156, 219, 111, 99, 217, 96, 41, | |
162, 228, 3, 161, 58, 229, 153, 235, 215, 54, 205, 50, 218, 103, 69, 21, | |
48, 186, 170, 73, 65, 222, 238, 225, 78, 172, 185, 196, 182, 239, 201, 243, | |
}; | |
float g_perlinGradientTable[256 * 3] = | |
{ | |
-0.382332f, 0.045987f, 0.412422f, 0.322819f, -0.523555f, 0.155692f, -0.599637f, 0.610314f, 0.204491f, -0.326772f, 0.183249f, 0.170122f, 0.137437f, 0.159912f, 0.346638f, 0.012269f, | |
-0.149943f, -0.247321f, 0.421695f, -0.031413f, 0.22226f, 0.269062f, 0.312575f, -0.166291f, -0.74937f, -0.184944f, 0.331976f, 0.029522f, 0.484716f, 0.374884f, 0.651325f, 0.0f, | |
0.325664f, 0.237639f, -0.077213f, 0.0f, -0.599967f, -0.599965f, 0.0f, -0.106802f, 0.12898f, 0.262476f, 0.539146f, -0.54082f, -0.294115f, -0.40226f, -0.235177f, 0.513393f, | |
-0.047496f, -0.238059f, -0.11023f, -0.04151f, 0.047293f, 0.08302f, 0.031514f, -0.065262f, -0.051344f, 0.036846f, 0.514855f, -0.309666f, 0.312743f, -0.15927f, -0.225656f, 0.473331f, | |
-0.343894f, 0.361597f, -0.352909f, 0.079702f, -0.477326f, -0.180476f, 0.212372f, 0.185283f, -0.080332f, 0.006545f, 0.049649f, -0.337633f, 0.364485f, -0.607989f, -0.179383f, 0.380025f, | |
-0.126611f, 0.229949f, -0.167068f, 0.789544f, -0.879327f, 0.0f, -0.104328f, 0.061701f, 0.558347f, 0.643778f, -0.016567f, -0.00871f, -0.026806f, 0.036742f, -0.082902f, -0.210578f, | |
-0.686211f, 0.498557f, 0.205545f, 0.05053f, -0.184377f, -0.10106f, -0.396777f, 0.114284f, 0.142954f, -0.39971f, -0.370211f, 0.799427f, 0.010625f, -0.360047f, -0.285405f, -0.57573f, | |
0.45687f, 0.222734f, 0.564252f, 0.774509f, -0.124628f, -0.175417f, -0.05755f, 0.049107f, 0.126588f, 0.389595f, -0.119535f, -0.006558f, -0.190696f, 0.038741f, 0.090039f, -0.048335f, | |
-0.180079f, -0.043774f, 0.029059f, -0.011331f, 0.073884f, -0.145004f, 0.0f, -0.488167f, -0.489682f, 0.266305f, -0.048211f, -0.254391f, -0.078009f, 0.301849f, 0.074496f, -0.133721f, | |
-0.378882f, 0.449358f, -0.252802f, -0.026044f, 0.080153f, 0.069205f, -0.05561f, -0.107745f, 0.073953f, 0.022285f, 0.0f, 0.321538f, -0.000819f, 0.286642f, -0.076246f, 0.042583f, | |
0.058611f, 0.0f, -0.454821f, 0.260599f, 0.665373f, 0.08596f, -0.01242f, -0.292721f, -0.08383f, -0.35935f, 0.107285f, -0.163418f, 0.11873f, -0.878918f, -0.215777f, -0.389136f, | |
-0.211051f, -0.307529f, 0.0f, -0.322809f, -0.623562f, 0.172665f, -0.57749f, -0.424905f, 0.082658f, -0.205316f, 0.083868f, 0.258113f, -0.753892f, -0.319969f, 0.0f, -0.725878f, | |
-0.006615f, 0.004806f, -0.072567f, 0.464495f, -0.077344f, 0.35127f, -0.016793f, -0.093071f, -0.166656f, 0.060751f, 0.840006f, -0.362233f, -0.198387f, 0.225023f, 0.936188f, -0.444758f, | |
-0.11514f, -0.354659f, 0.014497f, -0.029373f, -0.046912f, 0.526206f, -0.445624f, -0.362435f, -0.231729f, -0.289542f, 0.182363f, 0.12552f, -0.057606f, -0.044101f, 0.055588f, -0.049504f, | |
-0.082013f, -0.845759f, -0.470834f, -0.068169f, 0.082669f, 0.041471f, 0.013118f, 0.259258f, 0.157987f, 0.511734f, 0.276396f, -0.134263f, -0.265539f, 0.500715f, 0.231015f, 0.445317f, | |
-0.311734f, 0.103178f, 0.137202f, 0.011978f, -0.152683f, -0.413649f, -0.013775f, 0.217392f, -0.341425f, 0.287605f, -0.131299f, 0.022249f, -0.023086f, 0.0f, -0.081268f, 0.059899f, | |
0.004714f, 0.0f, -0.284805f, -0.603364f, -0.20102f, 0.140391f, 0.316763f, -0.804606f, 0.426147f, -0.103548f, 0.111007f, -0.276499f, -0.264919f, -0.271293f, 0.821277f, 0.124308f, | |
0.4558f, -0.632242f, -0.694367f, 0.167233f, 0.013052f, 0.025603f, 0.018478f, 0.070566f, -0.104252f, -0.063714f, 0.028317f, 0.023133f, 0.034385f, 0.501435f, -0.430703f, -0.475005f, | |
-0.17456f, -0.766047f, 0.349119f, -0.164142f, 0.056665f, -0.38817f, -0.763245f, 0.388889f, 0.0f, 0.444891f, -0.079174f, 0.390493f, 0.15998f, -0.057249f, 0.13463f, 0.163417f, | |
-0.229607f, -0.192898f, 0.288537f, -0.390402f, -0.284583f, -0.075388f, -0.805658f, 0.565244f, -0.193679f, -0.078991f, 0.024717f, -0.045931f, 0.111235f, -0.074319f, -0.665672f, -0.344944f, | |
0.411413f, -0.096546f, -0.583653f, -0.324629f, 0.40793f, 0.10454f, 0.660048f, -0.820568f, 0.267792f, 0.112261f, 0.66301f, -0.575374f, -0.320677f, -0.573242f, 0.416483f, -0.437923f, | |
0.029031f, 0.562818f, -0.514251f, -0.688641f, 0.3112f, 0.134575f, -0.113951f, -0.185842f, 0.588785f, 0.07939f, -0.03214f, 0.023769f, 0.221999f, -0.259927f, 0.0f, 0.816506f, | |
0.454549f, 0.065812f, 0.003058f, 0.003097f, 0.000617f, 0.149211f, 0.008463f, -0.140542f, 0.353697f, -0.301407f, -0.286977f, -0.444848f, 0.388932f, -0.262564f, 0.10957f, -0.237067f, | |
0.383215f, -0.843997f, -0.164186f, -0.407824f, 0.748646f, -0.176676f, 0.310143f, 0.017268f, 0.448852f, 0.085881f, 0.001312f, 0.013876f, 0.043496f, -0.031838f, -0.277795f, 0.019677f, | |
0.037472f, -0.974004f, 0.186361f, -0.596817f, 0.433611f, -0.329135f, -0.1038f, 0.016461f, -0.067573f, 0.602512f, 0.60251f, 0.0f, 0.055517f, 0.517075f, -0.111035f, -0.193866f, | |
0.04815f, 0.028228f, -0.073225f, -0.07015f, 0.178692f, 0.231196f, -0.405436f, 0.534878f, -0.008113f, -0.024969f, -0.092419f, -0.51487f, -0.415516f, -0.472159f, 0.483225f, 0.254046f, | |
0.781881f, -0.016453f, 0.123169f, -0.312721f, -0.182725f, -0.214054f, -0.760135f, 0.574751f, -0.381369f, -0.209033f, -0.370622f, 0.39484f, 0.54037f, -0.221661f, -0.523415f, -0.207639f, | |
0.165177f, -0.508353f, -0.330354f, 0.292668f, 0.900738f, 0.0f, 0.093909f, 0.023324f, -0.013674f, -0.413931f, -0.048747f, -0.189258f, -0.045809f, -0.386021f, 0.313923f, 0.457278f, | |
0.591863f, 0.592619f, -0.361923f, 0.08765f, 0.390406f, 0.09321f, 0.250343f, -0.057607f, 0.256967f, 0.037128f, -0.875059f, -0.258041f, 0.382945f, 0.640064f, 0.004503f, -0.005276f, | |
0.018734f, -0.124908f, -0.20383f, 0.0f, -0.165268f, 0.240234f, -0.299769f, 0.72198f, 0.396683f, 0.17599f, 0.528949f, -0.214708f, 0.342476f, 0.47955f, -0.122894f, 0.775932f, | |
-0.030996f, 0.0f, 0.134868f, -0.014594f, 0.044915f, -0.017316f, 0.58016f, -0.498274f, 0.471095f, 0.160296f, 0.142754f, -0.236497f, 0.074791f, -0.142261f, -0.046224f, 0.412773f, | |
-0.479527f, -0.25511f, -0.228631f, 0.399995f, 0.164699f, 0.299747f, -0.53561f, -0.495665f, -0.039875f, -0.02897f, 0.05948f, -0.259657f, 0.18865f, 0.336903f, -0.13525f, -0.416248f, | |
0.472116f, -0.127893f, 0.074129f, -0.343279f, -0.005685f, 0.009164f, -0.001274f, -0.691049f, -0.350751f, 0.298473f, -0.031537f, 0.217033f, 0.063074f, -0.186958f, 0.404504f, -0.653873f, | |
0.041271f, -0.576689f, -0.346857f, -0.132702f, -0.041688f, 0.095206f, 0.249581f, 0.181331f, 0.332778f, 0.046968f, -0.034124f, 0.515215f, -0.576599f, -0.07244f, 0.304896f, -0.494652f, | |
-0.673044f, 0.349003f, 0.763427f, 0.277402f, 0.164917f, -0.131499f, 0.064191f, -0.288233f, 0.34798f, 0.096356f, 0.32227f, -0.131006f, 0.137525f, 0.477995f, 0.194294f, 0.112615f, | |
0.521505f, 0.173785f, 0.070542f, 0.11252f, 0.143387f, 0.129961f, -0.245641f, 0.545331f, -0.273569f, 0.086535f, -0.067099f, 0.04875f, -0.120032f, 0.309317f, 0.224729f, -0.532433f, | |
0.217197f, 0.157801f, -0.609051f, 0.032277f, -0.002693f, -0.004582f, 0.016443f, -0.005291f, 0.004595f, 0.06551f, -0.534217f, 0.255287f, 0.385232f, -0.61746f, -0.201973f, 0.049956f, | |
0.036295f, -0.217366f, -0.071771f, -0.155923f, -0.077943f, 0.396951f, -0.05768f, -0.574478f, -0.188498f, 0.053955f, 0.27177f, 0.49011f, 0.581275f, 0.327016f, -0.002596f, -0.003844f, | |
0.000942f, -0.276486f, 0.352783f, 0.026408f, -0.067877f, 0.614233f, -0.708215f, -0.014551f, -0.095078f, 0.058666f, -0.552212f, 0.696821f, 0.296471f, 0.029568f, -0.091002f, 0.265439f, | |
0.740368f, -0.154013f, -0.270329f, -0.115748f, 0.135523f, 0.0f, 0.423776f, 0.370509f, 0.250127f, -0.248043f, -0.484951f, -0.209789f, -0.000314f, -0.05746f, -0.024009f, 0.273355f, | |
-0.259453f, 0.137294f, -0.037477f, -0.115346f, -0.575826f, 0.274724f, 0.142359f, -0.169791f, 0.037665f, -0.027365f, -0.031991f, -0.35933f, 0.636097f, 0.051412f, 0.101262f, 0.209703f, | |
-0.164983f, -0.200361f, -0.278973f, -0.143513f, -0.133635f, 0.166975f, 0.105166f, -0.272142f, -0.19772f, 0.353101f, 0.520612f, 0.708366f, -0.367319f, 0.273803f, -0.126571f, 0.369126f, | |
-0.034668f, -0.165782f, -0.214985f, 0.167786f, -0.905754f, -0.335573f, 0.741254f, 0.239782f, 0.101324f, 0.673682f, 0.276876f, -0.184366f, -0.079911f, 0.058058f, 0.468966f, -0.09032f, | |
-0.10712f, -0.060264f, -0.476929f, -0.48766f, -0.632836f, 0.020207f, 0.574117f, -0.040414f, -0.503039f, 0.365478f, -0.510581f, 0.115311f, 0.130793f, -0.544152f, 0.056282f, 0.794572f, | |
-0.112563f, 0.488661f, 0.497362f, -0.166646f, -0.215566f, 0.385861f, 0.540876f, 0.795336f, -0.403683f, -0.343516f, -0.234981f, 0.723209f, -0.380219f, -0.045123f, 0.306946f, 0.287834f, | |
0.031085f, 0.083707f, -0.00629f, 0.311298f, -0.22617f, 0.171675f, -0.137457f, 0.224179f, 0.710243f, -0.279656f, 0.499711f, 0.462443f, 0.831447f, 0.131686f, 0.0f, -0.309519f, | |
-0.109618f, 0.619045f, 0.159594f, 0.046698f, -0.131755f, -0.17193f, 0.147663f, -0.139609f, -0.261018f, -0.127415f, -0.572127f, -0.181165f, -0.557579f, -0.707514f, -0.709104f, 0.170238f, | |
0.0f, 0.01268f, 0.039026f, 0.077985f, -0.316095f, -0.03802f, 0.340972f, 0.167454f, 0.51538f, 0.495246f, 0.126888f, 0.136979f, 0.228492f, 0.214834f, 0.456259f, -0.107739f, | |
}; | |
Vector4 PerlinOctave(float frequency, float gain, int numOctaves, const Vector4 &in) | |
{ | |
Vector4 noiseSum = 0.0f; | |
float amplitude = 1.0f; | |
float norm = 0.0f; | |
for (int i = 0; i <= numOctaves; ++i) | |
{ | |
noiseSum += Perlin(amplitude * frequency, in) * amplitude; | |
norm += amplitude; | |
amplitude *= gain; | |
gain = 0.61f; // ??? | |
} | |
return noiseSum / norm; | |
} | |
Vector4 Perlin(float factor, const Vector4 &in) | |
{ | |
Vector4 out = 0.0f; | |
if (factor == 0.0f) | |
return out; | |
float xd = (in.x + 1.0f) / factor; | |
float yd = (in.y + 1.0f) / factor; | |
float zd = (in.z + 1.0f) / factor; | |
int xdi = (int)floor(xd); | |
int ydi = (int)floor(yd); | |
int zdi = (int)floor(zd); | |
float xm = xd - xdi; | |
float ym = yd - ydi; | |
float zm = zd - zdi; | |
float xm1 = xm - 1.0f; | |
float ym1 = ym - 1.0f; | |
float zm1 = zm - 1.0f; | |
float xmm = xm * xm; | |
float ymm = ym * ym; | |
float zmm = zm * zm; | |
float xm1m = xm1 * xm1; | |
float ym1m = ym1 * ym1; | |
float zm1m = zm1 * zm1; | |
unsigned char xp = PERLIN_PERMUTATION(xdi); | |
unsigned char xp1 = PERLIN_PERMUTATION(xdi + 1); | |
unsigned char xpy = PERLIN_PERMUTATION(xp + ydi); | |
unsigned char xpy1 = PERLIN_PERMUTATION(xp + ydi + 1); | |
unsigned char xp1y = PERLIN_PERMUTATION(xp1 + ydi); | |
unsigned char xp1y1 = PERLIN_PERMUTATION(xp1 + ydi + 1); | |
unsigned char zp = PERLIN_CLAMP(zdi); | |
unsigned char zp1 = PERLIN_CLAMP(zdi + 1); | |
float xmm3m = 1.0f - 3.0f * xmm + (xmm * 2) * xm; | |
float ymm3m = 1.0f - 3.0f * ymm + (ymm * 2) * ym; | |
float zmm3m = 1.0f - 3.0f * zmm + (zmm * 2) * zm; | |
float xm1m3m = 1.0f - 3.0f * xm1m - (xm1m * 2) * xm1; | |
float ym1m3m = 1.0f - 3.0f * ym1m - (ym1m * 2) * ym1; | |
float zm1m3m = 1.0f - 3.0f * zm1m - (zm1m * 2) * zm1; | |
float pxyz = xmm3m * ymm3m * zmm3m; | |
float pxyz1 = xmm3m * ymm3m * zm1m3m; | |
float pxy1z = xmm3m * ym1m3m * zmm3m; | |
float pxy1z1 = xmm3m * ym1m3m * zm1m3m; | |
float px1yz = xm1m3m * ymm3m * zmm3m; | |
float px1yz1 = xm1m3m * ymm3m * zm1m3m; | |
float px1y1z = xm1m3m * ym1m3m * zmm3m; | |
float px1y1z1 = xm1m3m * ym1m3m * zm1m3m; | |
float *p3d; | |
p3d = PERLIN_GRADIENT(xpy + zp); | |
out.x += xm * pxyz * p3d[0]; | |
out.y += ym * pxyz * p3d[1]; | |
out.z += zm * pxyz * p3d[2]; | |
p3d = PERLIN_GRADIENT(xpy + zp1); | |
out.x += xm * pxyz1 * p3d[0]; | |
out.y += ym * pxyz1 * p3d[1]; | |
out.z += zm1 * pxyz1 * p3d[2]; | |
p3d = PERLIN_GRADIENT(xpy1 + zp); | |
out.x += xm * pxy1z * p3d[0]; | |
out.y += ym1 * pxy1z * p3d[1]; | |
out.z += zm * pxy1z * p3d[2]; | |
p3d = PERLIN_GRADIENT(xpy1 + zp1); | |
out.x += xm * pxy1z1 * p3d[0]; | |
out.y += ym1 * pxy1z1 * p3d[1]; | |
out.z += zm1 * pxy1z1 * p3d[2]; | |
p3d = PERLIN_GRADIENT(xp1y + zp); | |
out.x += xm1 * px1yz * p3d[0]; | |
out.y += ym * px1yz * p3d[1]; | |
out.z += zm * px1yz * p3d[2]; | |
p3d = PERLIN_GRADIENT(xp1y + zp1); | |
out.x += xm1 * px1yz1 * p3d[0]; | |
out.y += ym * px1yz1 * p3d[1]; | |
out.z += zm1 * px1yz1 * p3d[2]; | |
p3d = PERLIN_GRADIENT(xp1y1 + zp); | |
out.x += xm1 * px1y1z * p3d[0]; | |
out.y += ym1 * px1y1z * p3d[1]; | |
out.z += zm * px1y1z * p3d[2]; | |
p3d = PERLIN_GRADIENT(xp1y1 + zp1); | |
out.x += xm1 * px1y1z1 * p3d[0]; | |
out.y += ym1 * px1y1z1 * p3d[1]; | |
out.z += zm1 * px1y1z1 * p3d[2]; | |
return out; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "Vector4.h" | |
extern unsigned char g_perlinPermutationTable[256]; | |
extern float g_perlinGradientTable[256 * 3]; | |
#define PERLIN_CLAMP(x) ((unsigned char)(x)) | |
#define PERLIN_PERMUTATION(x) g_perlinPermutationTable[PERLIN_CLAMP(x)] | |
#define PERLIN_GRADIENT(x) &g_perlinGradientTable[3 * PERLIN_PERMUTATION(x)] | |
Vector4 PerlinOctave(float frequency, float gain, int numOctaves, const Vector4 &in); | |
Vector4 Perlin(float factor, const Vector4 &in); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "TerrainGenerator.h" | |
#include "Perlin.h" | |
#include "Utils.h" | |
int g_possibleMoves[9][2] = | |
{ | |
{ 0, 1 }, | |
{ 1, 1 }, | |
{ 1, 0 }, | |
{ 1, -1 }, | |
{ 0, -1 }, | |
{ -1, -1 }, | |
{ -1, 0 }, | |
{ -1, 1 }, | |
{ 0, 0 }, | |
}; | |
int g_possibleMoveDistances[8] = | |
{ | |
{ 2 }, | |
{ 1 }, | |
{ 2 }, | |
{ 1 }, | |
{ 2 }, | |
{ 1 }, | |
{ 2 }, | |
{ 1 }, | |
}; | |
void TerrainVertex::initialize(const Vector4 &position) | |
{ | |
m_position = position; | |
m_slope = 1.0f; | |
m_terrainLayerFlags = 0; | |
m_riverCurveNo = -1; | |
m_riverDirection = Vector2(0.0f, 1.0f); | |
for (int i = 0; i < NUM_TERRAIN_LAYERS; ++i) | |
{ | |
m_layerIntensities[i] = 0.0f; | |
} | |
m_layerIntensities[tlt_rock] = 1.0f; | |
} | |
void TerrainFace::initialize() | |
{ | |
m_orientation = 0; | |
m_layerNos[0] = 0; | |
m_layerNos[1] = 0; | |
m_normals[0] = Vector4(0.0f, 0.0f, 1.0f); | |
m_normals[1] = Vector4(0.0f, 0.0f, 1.0f); | |
for (int i = 0; i < NUM_TERRAIN_LAYERS; ++i) | |
{ | |
m_layerIntensities[i] = 0; | |
} | |
} | |
void TerrainLayer::setGroundSpec(int groundSpecNo) | |
{ | |
m_groundSpecNo = groundSpecNo; | |
if (groundSpecNo >= 0) | |
m_terrainType = -1; | |
} | |
TerrainGenerator::TerrainGenerator() | |
{ | |
m_detail = 2.0f; | |
m_terrainBlockSize = 40; | |
m_placeRiver = false; | |
m_numRiverPasses = 2; | |
initialize(); | |
} | |
void TerrainGenerator::initialize() | |
{ | |
for (int i = 0; i < NUM_TERRAIN_LAYERS; ++i) | |
{ | |
m_layers[i].m_groundSpecNo = ground_gray_stone; | |
m_layers[i].m_terrainType = 0; | |
} | |
} | |
std::string TerrainGenerator::getTerrainCode() | |
{ | |
char buf[51]; | |
sprintf_s(buf, "0x%.8x%.8x%.8x%.8x%.8x%.8x", m_keys[5], m_keys[4], m_keys[3], m_keys[2], m_keys[1], m_keys[0]); | |
return buf; | |
} | |
void TerrainGenerator::setTerrainCode(const std::string &code) | |
{ | |
for (int i = 0; i < NUM_TERRAIN_KEYS; ++i) | |
{ | |
m_keys[i] = 0; | |
} | |
int startPos = 0; | |
int key = 0; | |
if (code[0] == '0' && (code[1] == 'x' || code[1] == 'X')) | |
startPos = 2; | |
for (int i = code.length(); i >= startPos && key < NUM_TERRAIN_KEYS; i -= 8) | |
{ | |
int start = Max(i - 8, startPos); | |
std::string keyCode = code.substr(start, i - start); | |
unsigned int keyValue = 0; | |
for (size_t j = 0; j < keyCode.length(); ++j) | |
{ | |
char c = keyCode[j]; | |
int val = 0; | |
if (c - '0' <= 9) | |
val = c - '0'; | |
else if (c - 'a' <= 5) | |
val = c - 'W'; | |
else if (c - 'A' <= 5) | |
val = c - '7'; | |
keyValue = keyValue * 16 + val; | |
} | |
m_keys[key++] = keyValue; | |
} | |
} | |
void TerrainGenerator::setShadeOccluded(int value) | |
{ | |
m_keys[3] &= ~(0x1 << 30); | |
m_keys[3] |= (Min(value, 1) << 30); | |
} | |
void TerrainGenerator::setDisableGrass(int value) | |
{ | |
m_keys[5] &= ~(0x3 << 2); | |
m_keys[5] |= (Min(value, 3) << 2); | |
} | |
void TerrainGenerator::setPlaceRiver(int value) | |
{ | |
m_keys[3] &= ~(0x1 << 31); | |
m_keys[3] |= (Min(value, 1) << 31); | |
} | |
void TerrainGenerator::setDeepWater(int value) | |
{ | |
m_keys[1] &= ~(0x1 << 31); | |
m_keys[1] |= (Min(value, 1) << 31); | |
} | |
void TerrainGenerator::setSizeX(float value) | |
{ | |
m_keys[3] &= ~(0x3FF << 0); | |
m_keys[3] |= (Min((int)value, 1023) << 0); | |
} | |
void TerrainGenerator::setSizeY(float value) | |
{ | |
m_keys[3] &= ~(0x3FF << 10); | |
m_keys[3] |= (Min((int)value, 1023) << 10); | |
} | |
void TerrainGenerator::setHillHeight(float value) | |
{ | |
m_keys[4] &= ~(0x7F << 7); | |
m_keys[4] |= (ClampExclusive(Round2(value), 0, 128) << 7); | |
} | |
void TerrainGenerator::setValley(float value) | |
{ | |
m_keys[4] &= ~(0x7F << 0); | |
m_keys[4] |= (ClampExclusive(Round(value * 100.0f), 0, 100) << 0); | |
} | |
void TerrainGenerator::setRuggedness(int value) | |
{ | |
m_keys[4] &= ~(0x7F << 14); | |
m_keys[4] |= (Min(value, 127) << 14); | |
} | |
void TerrainGenerator::setVegetation(float value) | |
{ | |
m_keys[4] &= ~(0x7F << 21); | |
m_keys[4] |= (ClampExclusive(Round(value * 100.0f), 0, 100) << 21); | |
} | |
void TerrainGenerator::setRegionType(int value) | |
{ | |
m_keys[4] &= ~(0xF << 28); | |
m_keys[4] |= (Min(value, 16) << 28); | |
} | |
void TerrainGenerator::setRegionDetail(int value) | |
{ | |
m_keys[5] &= ~(0x3 << 0); | |
m_keys[5] |= (Min(value, 3) << 0); | |
} | |
void TerrainGenerator::setSeed(int index, int value) | |
{ | |
m_keys[index] &= ~0x7FFFFFFF; | |
m_keys[index] |= Min(value, 0x7FFFFFFF); | |
} | |
int TerrainGenerator::getDisableGrass() | |
{ | |
return (m_keys[5] >> 2) & 0x3; | |
} | |
int TerrainGenerator::getPlaceRiver() | |
{ | |
return (m_keys[3] >> 31) & 0x1; | |
} | |
int TerrainGenerator::getDeepWater() | |
{ | |
return (m_keys[1] >> 31) & 0x1; | |
} | |
float TerrainGenerator::getSizeX() | |
{ | |
return (float)((m_keys[3] >> 0) & 0x3FF); | |
} | |
float TerrainGenerator::getSizeY() | |
{ | |
return (float)((m_keys[3] >> 10) & 0x3FF); | |
} | |
float TerrainGenerator::getHillHeight() | |
{ | |
return (float)((m_keys[4] >> 7) & 0x7F); | |
} | |
float TerrainGenerator::getValley() | |
{ | |
return (float)((m_keys[4] >> 0) & 0x7F) / 100.0f; | |
} | |
int TerrainGenerator::getRuggedness() | |
{ | |
return (m_keys[4] >> 14) & 0x7F; | |
} | |
float TerrainGenerator::getVegetation() | |
{ | |
return (float)((m_keys[4] >> 21) & 0x7F) / 100.0f; | |
} | |
int TerrainGenerator::getRegionType() | |
{ | |
return (m_keys[4] >> 28) & 0xF; | |
} | |
int TerrainGenerator::getRegionDetail() | |
{ | |
return (m_keys[5] >> 0) & 0x3; | |
} | |
int TerrainGenerator::getSeed(int index) | |
{ | |
return (m_keys[index] >> 0) & 0x7FFFFFFF; | |
} | |
void TerrainGenerator::generate() | |
{ | |
initialize(); | |
m_detail = getRegionDetail() + 2.0f; | |
srand(getSeed(0)); | |
m_placeRiver = getPlaceRiver() != 0; | |
m_size.x = getSizeX(); | |
m_size.y = getSizeY(); | |
m_numFaces[0] = ClampInclusive((int)(m_size.x / m_detail), MIN_NUM_TERRAIN_FACES_PER_AXIS, MAX_NUM_TERRAIN_FACES_PER_AXIS); | |
m_numFaces[1] = ClampInclusive((int)(m_size.y / m_detail), MIN_NUM_TERRAIN_FACES_PER_AXIS, MAX_NUM_TERRAIN_FACES_PER_AXIS); | |
m_size.x = m_numFaces[0] * m_detail; | |
m_size.y = m_numFaces[1] * m_detail; | |
generateLayers(); | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
m_vertices[x][y].initialize(Vector4(x * m_detail, y * m_detail, 0.0f)); | |
} | |
} | |
for (int y = 0; y < m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x < m_numFaces[0]; ++x) | |
{ | |
m_faces[x][y].initialize(); | |
} | |
} | |
generateTerrain(); | |
srand(getSeed(1)); | |
generateRiver(); | |
smoothHeight(); | |
computeNormals(); | |
computeVertexLayerIntensities(); | |
selectFaceOrientation(); | |
selectFaceLayers(); | |
roughenRockVertices(); | |
srand(getSeed(2)); | |
computeNormals(); | |
computeFaceLayerIntensities(); | |
} | |
void TerrainGenerator::generateLayers() | |
{ | |
for (int i = 0; i < NUM_TERRAIN_LAYERS; ++i) | |
{ | |
m_layers[i].m_groundSpecNo = -1; | |
} | |
int random = rand() % 2; | |
if (random == 1) | |
m_layers[tlt_rock].setGroundSpec(ground_brown_stone); | |
else if (random == 0) | |
m_layers[tlt_rock].setGroundSpec(ground_gray_stone); | |
rand(); | |
m_barrenness = 0.19f; | |
int earthGroundSpec = ground_earth; | |
int greenGroundSpec = ground_turf; | |
int multitexGroundSpec = -1; | |
switch (getRegionType()) | |
{ | |
case rt_plain: | |
earthGroundSpec = ground_earth; | |
greenGroundSpec = ground_turf; | |
multitexGroundSpec = ground_turf; | |
break; | |
case rt_steppe: | |
earthGroundSpec = ground_earth; | |
greenGroundSpec = ground_steppe; | |
multitexGroundSpec = ground_steppe; | |
rand(); | |
break; | |
case rt_snow: | |
case rt_snow_forest: | |
earthGroundSpec = ground_snow; | |
greenGroundSpec = -1; | |
multitexGroundSpec = -1; | |
break; | |
case rt_desert: | |
case rt_desert_forest: | |
earthGroundSpec = ground_desert; | |
greenGroundSpec = -1; | |
multitexGroundSpec = -1; | |
m_barrenness = 0.26f; | |
break; | |
case rt_forest: | |
earthGroundSpec = ground_forest; | |
greenGroundSpec = ground_turf; | |
multitexGroundSpec = ground_forest; | |
break; | |
case rt_steppe_forest: | |
earthGroundSpec = ground_forest; | |
greenGroundSpec = ground_steppe; | |
multitexGroundSpec = -1; | |
break; | |
} | |
m_layers[tlt_earth].setGroundSpec(earthGroundSpec); | |
m_layers[tlt_green].setGroundSpec(greenGroundSpec); | |
m_layers[tlt_riverbed].setGroundSpec(ground_pebbles); | |
} | |
void TerrainGenerator::generateTerrain() | |
{ | |
float sizeFactor = (m_size[1] + m_size[0]) * 0.5f * (Randf(1.0f, 1.5f)); | |
m_noiseFrequency = (m_size[1] + m_size[0]) * 0.2f * (Randf(1.0f, 1.5f)); | |
float valley = getValley(); | |
Vector4 positionRandomness; | |
positionRandomness.x = Randf(10000.0f); | |
positionRandomness.y = Randf(10000.0f); | |
positionRandomness.z = Randf(10000.0f); | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
Vector4 noise = PerlinOctave(m_noiseFrequency, 0.6f, 1, m_vertices[x][y].m_position + positionRandomness); | |
float slopeFactor = Clamp((noise.x + noise.y + noise.z) * valley * 9.0f, 0.0f, 1.0f); | |
m_vertices[x][y].m_slope = (cos(slopeFactor * PI) + 1.0f) * 0.45f + 0.1f; | |
} | |
} | |
float altitudeRandomness = Randf(7.0f, 10.0f); | |
for (int i = 0; i < 2; ++i) | |
{ | |
for (int j = 0; j < 13; ++j) | |
{ | |
if (m_numFaces[1 - i] >= 0) | |
{ | |
float altitudeFactor = sin((1.0f - j / 13.0f) * 3.2f) * altitudeRandomness; | |
for (int k = 0; k <= m_numFaces[1 - i]; ++k) | |
{ | |
int x1; | |
int y1; | |
int x2; | |
int y2; | |
if (i == 0) | |
{ | |
x1 = j; | |
x2 = m_numFaces[0] - j; | |
y1 = k; | |
y2 = k; | |
} | |
else | |
{ | |
x1 = k; | |
x2 = k; | |
y1 = j; | |
y2 = m_numFaces[1] - j; | |
} | |
TerrainVertex *vertex1 = &m_vertices[x1][y1]; | |
Vector4 noise1 = PerlinOctave(40.0f, 0.6f, 4, vertex1->m_position + positionRandomness); | |
float altitude1 = (noise1.z + noise1.z + 0.4f) * altitudeFactor; | |
if (altitude1 > vertex1->m_position.z) | |
vertex1->m_position.z = altitude1; | |
TerrainVertex *vertex2 = &m_vertices[x2][y2]; | |
Vector4 noise2 = PerlinOctave(40.0f, 0.6f, 4, vertex2->m_position + positionRandomness); | |
float altitude2 = (noise2.z + noise2.z + 0.4f) * altitudeFactor; | |
if (altitude2 > vertex2->m_position.z) | |
vertex2->m_position.z = altitude2; | |
} | |
} | |
} | |
} | |
float hillFactor = Max(sizeFactor / (pow(2.0f, (100 - ClampExclusive(getRuggedness(), 0, 100)) * 0.045f) * 4.0f), 2.0f); | |
int numPasses = (int)(log(hillFactor) * LOG2_E); | |
float heightFactor = 1.0f; | |
for (int i = 0; i <= numPasses; ++i) | |
{ | |
float densityFactor; | |
if (i == numPasses) | |
densityFactor = (hillFactor - BITSHIFT64(numPasses)) / BITSHIFT64(numPasses); | |
else | |
densityFactor = 1.0f; | |
generateHills(sizeFactor / BITSHIFT64(i), densityFactor, heightFactor); | |
heightFactor -= 0.05f; | |
} | |
float minHeight = 10000.0f; | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
minHeight = Min(minHeight, m_vertices[x][y].m_position.z); | |
} | |
} | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
m_vertices[x][y].m_position.z -= minHeight; | |
} | |
} | |
} | |
void TerrainGenerator::generateHills(float widthFactor, float densityFactor, float heightFactor) | |
{ | |
int numHills = (int)(Round(m_size[0] * densityFactor * m_size[1] / (widthFactor * widthFactor * 0.25f)) * Randf(0.4f, 0.6f) * 30.0f); | |
for (int i = 0; i < numHills; ++i) | |
{ | |
float radius = (getRandom4X() * 0.5f + 0.05f) * widthFactor; | |
Vector2 position; | |
position.y = (m_size[1] + (widthFactor * 2)) * Randf() - widthFactor; | |
position.x = (m_size[0] + (widthFactor * 2)) * Randf() - widthFactor; | |
generateHill(position, radius, Randf(0.2f, 0.3f) * radius * heightFactor); | |
} | |
} | |
void TerrainGenerator::generateHill(const Vector2 &position, float radius, float height) | |
{ | |
float hillHeight = getHillHeight(); | |
int min[2]; | |
int max[2]; | |
for (int i = 0; i < 2; ++i) | |
{ | |
min[i] = Max(Round(ceil((position[i] - radius) / m_detail)), 0); | |
max[i] = Min(Round(floor((position[i] + radius) / m_detail)), m_numFaces[i]); | |
} | |
for (int y = min[1]; y <= max[1]; ++y) | |
{ | |
for (int x = min[0]; x <= max[0]; ++x) | |
{ | |
TerrainVertex *vertex = &m_vertices[x][y]; | |
float centerDistance = (Vector2((float)x, (float)y) * m_detail - position).length() / radius; | |
if (centerDistance < 1.0f) | |
vertex->m_position.z += ((cos(centerDistance * PI) + 1.0f) * 0.5f * height * vertex->m_slope) * hillHeight * 0.01f; | |
} | |
} | |
} | |
void TerrainGenerator::generateRiver() | |
{ | |
bool riverPlaced = false; | |
int start[2]; | |
int end[2]; | |
start[0] = 0; | |
start[1] = 0; | |
if (m_placeRiver) | |
{ | |
for (int i = 0; i < 4 && !riverPlaced; ++i) | |
{ | |
int tries = 20; | |
int x; | |
int y; | |
float bestNoise = -10000.0f; | |
do | |
{ | |
if (Randf() >= 0.5f) | |
{ | |
x = Rand(m_numFaces[0] - 3) + 3; | |
y = rand() % 4 + 3; | |
if (Randf() < 0.5f) | |
y = m_numFaces[1] - y; | |
} | |
else | |
{ | |
x = rand() % 4 + 3; | |
if (Randf() < 0.5f) | |
x = m_numFaces[0] - x; | |
y = Rand(m_numFaces[1] - 3) + 3; | |
} | |
float noise = getVertexNoise(start[0], start[1]); | |
if (noise >= bestNoise) | |
{ | |
bestNoise = noise; | |
start[0] = x; | |
start[1] = y; | |
} | |
} | |
while (--tries); | |
bool endFound = false; | |
tries = 50; | |
while (tries && !endFound) | |
{ | |
if (Randf() >= 0.5f) | |
{ | |
end[1] = 0; | |
if (Randf() < 0.5f) | |
end[1] = m_numFaces[1] + 1; | |
end[0] = Rand(m_numFaces[0] + 1); | |
} | |
else | |
{ | |
end[0] = 0; | |
if (Randf() < 0.5f) | |
end[0] = m_numFaces[0] + 1; | |
end[1] = Rand(m_numFaces[1] + 1); | |
} | |
int distX = end[0] - start[0]; | |
if (distX < 0) | |
distX = -distX; | |
int distY = end[1] - start[1]; | |
if (distY < 0) | |
distY = -distY; | |
if ((m_numFaces[0] + m_numFaces[1]) * 0.7f < (distX + distY)) | |
endFound = true; | |
--tries; | |
} | |
if (endFound) | |
{ | |
if (placeRiver(start, end, rlt_base, 1.5f, 0.9f, true) >= 3.5f) | |
removeTerrainTypeFlags(BITSHIFT(rlt_base)|BITSHIFT(rlt_expanded)); | |
else | |
riverPlaced = true; | |
} | |
} | |
} | |
m_numRiverPasses = rand() % 3; | |
if (m_detail >= 2.1f && m_numRiverPasses > 1) | |
m_numRiverPasses = 1; | |
if (m_detail > 3.1f) | |
m_numRiverPasses = 0; | |
if (getDeepWater()) | |
m_numRiverPasses = 0; | |
if (riverPlaced) | |
{ | |
expandRiver(1, BITSHIFT(rlt_base), BITSHIFT(rlt_base)|BITSHIFT(rlt_expanded)); | |
for (int i = 0; i < m_numRiverPasses; ++i) | |
expandRiver(2, BITSHIFT(rlt_base), BITSHIFT(rlt_base)|BITSHIFT(rlt_expanded)); | |
expandRiver(2, BITSHIFT(rlt_base), BITSHIFT(rlt_expanded)); | |
expandRiver(2, BITSHIFT(rlt_expanded), BITSHIFT(rlt_expanded)); | |
setTerrainTypeDepth(rlt_base, getDeepWater() ? -2.3f : -1.3f); | |
smoothRiverHeight(rlt_base, 0.5f); | |
} | |
} | |
float TerrainGenerator::placeRiver(int *start, int *end, int terrainType, float globalDirectionFactor, float globalHeightFactor, bool modifyVertices) | |
{ | |
float depth = 10000.0f; | |
Vector2 direction((float)(end[0] - start[0]), (float)(end[1] - start[1])); | |
int curX = start[0]; | |
int curY = start[1]; | |
int numCurves = 0; | |
Vector2 possibleDirections[8]; | |
direction.normalize(); | |
for (int i = 0; i < 8; ++i) | |
{ | |
possibleDirections[i] = Vector2((float)g_possibleMoves[i][0], (float)g_possibleMoves[i][1]); | |
possibleDirections[i].normalize(); | |
} | |
int terrainTypeFlags = BITSHIFT(rlt_base); | |
TerrainVertex *startVertex = &m_vertices[start[0]][start[1]]; | |
TerrainVertex *curVertex = startVertex; | |
startVertex->m_terrainLayerFlags |= terrainTypeFlags; | |
if (modifyVertices) | |
startVertex->m_riverDirection = direction; | |
bool atEnd = false; | |
float hillHeight = getHillHeight(); | |
float directionLikeliness[8]; | |
while (true) | |
{ | |
Vector2 curDirection((float)(end[0] - curX), (float)(end[1] - curY)); | |
curDirection.normalize(); | |
for (int i = 0; i < 8; ++i) | |
{ | |
directionLikeliness[i] = 0.0f; | |
int nextX = curX + g_possibleMoves[i][0]; | |
int nextY = curY + g_possibleMoves[i][1]; | |
float placementFactor = 0.0f; | |
int distanceFromBounds = Max(20 - nextX, 0) + Max(nextX + 20 - m_numFaces[0], 0) + Max(20 - nextY, 0) + Max(nextY + 20 - m_numFaces[1], 0); | |
if (distanceFromBounds > 0) | |
{ | |
if (nextX <= 20 && possibleDirections[i].x <= 0.0f || | |
nextY <= 20 && possibleDirections[i].y <= 0.0f || | |
nextX >= m_numFaces[0] - 20 && possibleDirections[i].x >= 0.0f || | |
nextY >= m_numFaces[1] - 20 && possibleDirections[i].y >= 0.0f) | |
{ | |
placementFactor = Clamp((float)distanceFromBounds, 0.0f, 24.0f) * - 0.04f; | |
} | |
} | |
if (nextX < 0 || nextX > m_numFaces[0] || nextY < 0 || nextY > m_numFaces[1]) | |
{ | |
directionLikeliness[i] = (possibleDirections[i].dot(direction) + 1.0f) / 2; | |
} | |
else | |
{ | |
TerrainVertex *nextVertex = &m_vertices[nextX][nextY]; | |
if (!(nextVertex->m_terrainLayerFlags & terrainTypeFlags)) | |
{ | |
float heightFactor = (curVertex->m_position.z - nextVertex->m_position.z) * globalHeightFactor * 3.0f; | |
if (heightFactor < 0.0f) | |
heightFactor *= (0.25f - hillHeight * 0.0022f); | |
directionLikeliness[i] = heightFactor + ((direction.dot(possibleDirections[i]) + 0.7f) * 0.5f * globalDirectionFactor) + ((curDirection.dot(possibleDirections[i]) + 0.7f) * 0.5f) * 0.65f + placementFactor; | |
} | |
else | |
{ | |
if (nextVertex->m_riverCurveNo < numCurves - 30) | |
atEnd = true; | |
directionLikeliness[i] = -1.0f; | |
} | |
} | |
} | |
for (int i = 0; i < 8; ++i) | |
{ | |
if (directionLikeliness[i] > 0.0f) | |
directionLikeliness[i] = directionLikeliness[i] * directionLikeliness[i] * directionLikeliness[i]; | |
} | |
float threshold = 0.0f; | |
for (int i = 0; i < 8; ++i) | |
{ | |
if (directionLikeliness[i] > 0.0f) | |
threshold += directionLikeliness[i]; | |
} | |
threshold *= Randf(); | |
float totalLikeliness = 0.0f; | |
int selectedMove = -1; | |
for (int i = 0; i < 8; ++i) | |
{ | |
if (directionLikeliness[i] > 0.0f) | |
{ | |
if (totalLikeliness <= threshold && directionLikeliness[i] + totalLikeliness > threshold) | |
selectedMove = i; | |
totalLikeliness += directionLikeliness[i]; | |
} | |
} | |
if (selectedMove != -1) | |
{ | |
int newX = curX + g_possibleMoves[selectedMove][0]; | |
if (newX >= 3 && newX <= m_numFaces[0] - 3) | |
{ | |
int newY = curY + g_possibleMoves[selectedMove][1]; | |
if (newY >= 3 && newY <= m_numFaces[1] - 3) | |
{ | |
if (directionLikeliness[selectedMove] > 0.0f) | |
{ | |
curX = newX; | |
curY = newY; | |
direction = direction * 0.9f + possibleDirections[selectedMove] * 0.1f; | |
direction.normalize(); | |
numCurves++; | |
curVertex = &m_vertices[curX][curY]; | |
curVertex->m_terrainLayerFlags |= terrainTypeFlags; | |
curVertex->m_riverCurveNo = numCurves; | |
if (modifyVertices) | |
{ | |
curVertex->m_riverDirection = direction; | |
} | |
depth = Min(depth, curVertex->m_position.z); | |
if (numCurves != 100000 && !atEnd) | |
continue; | |
} | |
} | |
} | |
} | |
break; | |
} | |
return depth; | |
} | |
void TerrainGenerator::expandRiver(int pass, unsigned int srcTerrainTypeFlags, unsigned int dstTerrainTypeFlags) | |
{ | |
int modifiedVertices[MAX_NUM_TERRAIN_FACES_PER_AXIS + 1][MAX_NUM_TERRAIN_FACES_PER_AXIS + 1]; | |
int numDirections; | |
int directions[8]; | |
if (pass == 1) | |
{ | |
numDirections = 4; | |
directions[0] = 2; | |
directions[1] = 4; | |
directions[2] = 5; | |
directions[3] = 6; | |
} | |
else | |
{ | |
numDirections = 8; | |
directions[0] = 0; | |
directions[1] = 1; | |
directions[2] = 2; | |
directions[3] = 3; | |
directions[4] = 4; | |
directions[5] = 5; | |
directions[6] = 6; | |
directions[7] = 7; | |
} | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
modifiedVertices[x][y] = 0; | |
} | |
} | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
Vector2 avgRiverDirection = 0.0f; | |
int numMatches = 0; | |
TerrainVertex *vertex = &m_vertices[x][y]; | |
for (int i = 0; i < numDirections; ++i) | |
{ | |
int possibleX = x + g_possibleMoves[directions[i]][0]; | |
int possibleY = y + g_possibleMoves[directions[i]][1]; | |
if (possibleX >= 0 && possibleX <= m_numFaces[0]) | |
{ | |
if (possibleY >= 0 && possibleY <= m_numFaces[1]) | |
{ | |
TerrainVertex *possibleVertex = &m_vertices[possibleX][possibleY]; | |
if (possibleVertex->m_terrainLayerFlags & srcTerrainTypeFlags) | |
{ | |
numMatches++; | |
avgRiverDirection += possibleVertex->m_riverDirection; | |
} | |
} | |
} | |
} | |
if (numMatches) | |
{ | |
modifiedVertices[x][y] = 1; | |
vertex->m_riverDirection = avgRiverDirection / (float)numMatches; | |
vertex->m_riverDirection.normalize(); | |
} | |
} | |
} | |
if (dstTerrainTypeFlags) | |
{ | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
if (modifiedVertices[x][y]) | |
m_vertices[x][y].m_terrainLayerFlags |= dstTerrainTypeFlags; | |
} | |
} | |
} | |
} | |
void TerrainGenerator::smoothRiverHeight(int terrainType, float smoothFactor) | |
{ | |
unsigned int flag = BITSHIFT(terrainType); | |
float height; | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
TerrainVertex *vertex = &m_vertices[x][y]; | |
if (!(vertex->m_terrainLayerFlags & terrainType)) | |
{ | |
int smoothType = 0; | |
for (int i = 0; i < 8; ++i) | |
{ | |
int newX = x + g_possibleMoves[i][0]; | |
int newY = y + g_possibleMoves[i][1]; | |
if (newX >= 0 && newX <= m_numFaces[0]) | |
{ | |
if (newY >= 0 && newY <= m_numFaces[1]) | |
{ | |
if (m_vertices[newX][newY].m_terrainLayerFlags & flag) | |
{ | |
int newType = g_possibleMoveDistances[i]; | |
if (newType == 2 || (newType == 1 && smoothType == 0)) | |
smoothType = newType; | |
height = m_vertices[newX][newY].m_position.z; | |
} | |
} | |
} | |
} | |
if (smoothType) | |
{ | |
float factor = smoothFactor; | |
if (smoothType == 1) | |
factor *= 0.7f; | |
vertex->m_position.z += (height - vertex->m_position.z) * factor; | |
} | |
} | |
} | |
} | |
} | |
void TerrainGenerator::smoothHeight() | |
{ | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
TerrainVertex *vertex = &m_vertices[x][y]; | |
float heightSum = vertex->m_position.z; | |
float smoothAmount = 1.0f; | |
for (int i = 0; i < 8; ++i) | |
{ | |
int newX = x + g_possibleMoves[i][0]; | |
int newY = y + g_possibleMoves[i][1]; | |
if (newX >= 0 && newX <= m_numFaces[0]) | |
{ | |
if (newY >= 0 && newY <= m_numFaces[1]) | |
{ | |
heightSum += m_vertices[newX][newY].m_position.z; | |
smoothAmount += 1.0f; | |
} | |
} | |
} | |
float heightDiff = Clamp((heightSum / smoothAmount) - vertex->m_position.z, -10.0f, 2.0f); | |
vertex->m_position.z += Randf(0.2f, 0.6f) * heightDiff; | |
} | |
} | |
} | |
void TerrainGenerator::computeNormals() | |
{ | |
for (int y = 0; y < m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x < m_numFaces[0]; ++x) | |
{ | |
TerrainFace *face = &m_faces[x][y]; | |
for (int i = 0; i < 2; ++i) | |
{ | |
int vertex0[2]; | |
int vertex1[2]; | |
int vertex2[2]; | |
getVerticesForFace(x, y, i, vertex0, vertex1, vertex2); | |
face->m_normals[i] = MakeNormalFromPlane(m_vertices[vertex0[0]][vertex0[1]].m_position, m_vertices[vertex1[0]][vertex1[1]].m_position, m_vertices[vertex2[0]][vertex2[1]].m_position); | |
} | |
} | |
} | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
m_vertices[x][y].m_normal = 0.0f; | |
} | |
} | |
for (int y = 0; y < m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x < m_numFaces[0]; ++x) | |
{ | |
TerrainFace *face = &m_faces[x][y]; | |
for (int i = 0; i < 2; ++i) | |
{ | |
int vertex0[2]; | |
int vertex1[2]; | |
int vertex2[2]; | |
getVerticesForFace(x, y, i, vertex0, vertex1, vertex2); | |
m_vertices[vertex0[0]][vertex0[1]].m_normal += face->m_normals[i]; | |
m_vertices[vertex1[0]][vertex1[1]].m_normal += face->m_normals[i]; | |
m_vertices[vertex2[0]][vertex2[1]].m_normal += face->m_normals[i]; | |
} | |
} | |
} | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
m_vertices[x][y].m_normal.normalize(); | |
} | |
} | |
} | |
void TerrainGenerator::computeVertexLayerIntensities() | |
{ | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
TerrainVertex *vertex = &m_vertices[x][y]; | |
if ((m_layers[tlt_earth].m_terrainType == -1 || vertex->m_terrainLayerFlags & BITSHIFT(m_layers[tlt_earth].m_terrainType)) && vertex->m_position.z <= 10000.0f) | |
vertex->m_layerIntensities[tlt_earth] = 1.0f - Clamp(((1.0f - vertex->m_normal.z) - m_barrenness) * 12.0f, 0.0f, 1.0f); | |
if (m_layers[tlt_green].m_groundSpecNo >= 0) | |
{ | |
Vector4 noise = PerlinOctave(15.0f, 0.6f, 3, Vector4((float)x, (float)y, 0.0f)); | |
float intensity = Clamp((noise.x + noise.y + noise.z) * 4.5f + 0.7f, 0.0f, 1.0f); | |
vertex->m_layerIntensities[tlt_green] = vertex->m_layerIntensities[tlt_earth] * intensity; | |
if (intensity > 0.99f) | |
vertex->m_layerIntensities[tlt_earth] = 0.0f; | |
} | |
if (m_placeRiver && vertex->m_position.z < 0.0f) | |
vertex->m_layerIntensities[tlt_riverbed] = 1.0f; | |
} | |
} | |
} | |
void TerrainGenerator::selectFaceOrientation() | |
{ | |
int possibleDirections[] = { 8, 2, 1, 0 }; | |
int layerNos[4]; | |
for (int y = 0; y < m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x < m_numFaces[0]; ++x) | |
{ | |
TerrainFace *face = &m_faces[x][y]; | |
for (int i = 0; i < 4; ++i) | |
{ | |
int newX = x + g_possibleMoves[possibleDirections[i]][0]; | |
int newY = y + g_possibleMoves[possibleDirections[i]][1]; | |
if (newX >= 0 && newX <= m_numFaces[0] && newY >= 0 && newY <= m_numFaces[1]) | |
{ | |
TerrainVertex *newVertex = &m_vertices[newX][newY]; | |
layerNos[i] = 0; | |
for (int j = 1; j < NUM_TERRAIN_LAYERS; ++j) | |
{ | |
if (newVertex->m_layerIntensities[j] > 0.4f) | |
layerNos[i] = j; | |
} | |
} | |
else | |
{ | |
layerNos[i] = -1; | |
} | |
} | |
int numInverts = -1; | |
if (layerNos[1] != layerNos[0] && layerNos[3] != layerNos[0]) | |
numInverts = 0; | |
if (layerNos[2] != layerNos[1] && layerNos[0] != layerNos[1]) | |
numInverts = 1; | |
if (layerNos[3] != layerNos[2] && layerNos[1] != layerNos[2]) | |
numInverts = 2; | |
if (layerNos[0] == layerNos[3] || layerNos[2] == layerNos[3]) | |
{ | |
if (numInverts == -1) | |
{ | |
Vector4 upRight = m_vertices[x + 1][y + 1].m_position - m_vertices[x][y].m_position; | |
Vector4 right = m_vertices[x + 1][y].m_position - m_vertices[x][y].m_position; | |
Vector4 up = m_vertices[x][y + 1].m_position - m_vertices[x][y].m_position; | |
if (upRight.dot(right.cross(up)) > 0.0f) | |
face->m_orientation = 0; | |
else | |
face->m_orientation = 1; | |
} | |
else if (numInverts == 0 || numInverts == 2) | |
{ | |
face->m_orientation = 0; | |
} | |
else | |
{ | |
face->m_orientation = 1; | |
} | |
} | |
else | |
{ | |
face->m_orientation = 1; | |
} | |
} | |
} | |
} | |
void TerrainGenerator::selectFaceLayers() | |
{ | |
int possibleDirections[] = { 8, 2, 1, 0 }; | |
int layerNos[4]; | |
for (int y = 0; y < m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x < m_numFaces[0]; ++x) | |
{ | |
TerrainFace *face = &m_faces[x][y]; | |
for (int i = 0; i < 4; ++i) | |
{ | |
int newX = x + g_possibleMoves[possibleDirections[i]][0]; | |
int newY = y + g_possibleMoves[possibleDirections[i]][1]; | |
if (newX >= 0 && newX <= m_numFaces[0] && newY >= 0 && newY <= m_numFaces[1]) | |
{ | |
TerrainVertex *newVertex = &m_vertices[newX][newY]; | |
layerNos[i] = 0; | |
for (int j = 1; j < NUM_TERRAIN_LAYERS; ++j) | |
{ | |
if (newVertex->m_layerIntensities[j] > 0.4f) | |
layerNos[i] = j; | |
} | |
} | |
else | |
{ | |
layerNos[i] = -1; | |
} | |
} | |
if (face->m_orientation) | |
{ | |
if (layerNos[0] > 0) | |
face->m_layerNos[1] = layerNos[0]; | |
else if (layerNos[2] > 0) | |
face->m_layerNos[1] = layerNos[2]; | |
else | |
face->m_layerNos[1] = layerNos[3]; | |
if (layerNos[0] > 0) | |
face->m_layerNos[0] = layerNos[0]; | |
else if (layerNos[1] > 0) | |
face->m_layerNos[0] = layerNos[1]; | |
else | |
face->m_layerNos[0] = layerNos[2]; | |
} | |
else | |
{ | |
if (layerNos[1] > 0) | |
face->m_layerNos[1] = layerNos[1]; | |
else if (layerNos[2] > 0) | |
face->m_layerNos[1] = layerNos[2]; | |
else | |
face->m_layerNos[1] = layerNos[3]; | |
if (layerNos[1] > 0) | |
face->m_layerNos[0] = layerNos[1]; | |
else if (layerNos[3] > 0) | |
face->m_layerNos[0] = layerNos[3]; | |
else | |
face->m_layerNos[0] = layerNos[0]; | |
} | |
} | |
} | |
} | |
void TerrainGenerator::roughenRockVertices() | |
{ | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
TerrainVertex *vertex = &m_vertices[x][y]; | |
if (vertex->m_layerIntensities[tlt_green] + vertex->m_layerIntensities[tlt_earth] < 0.5f) | |
{ | |
float increase = Randf(-0.5f, 0.5f) * (1.0f - vertex->m_layerIntensities[tlt_earth]) * m_detail * 0.7f; | |
vertex->m_position.z += increase; | |
} | |
} | |
} | |
} | |
void TerrainGenerator::computeFaceLayerIntensities() | |
{ | |
int possibleDirections[] = { 8, 2, 1, 0 }; | |
int layerNos[4]; | |
for (int y = 0; y < m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x < m_numFaces[0]; ++x) | |
{ | |
TerrainFace *face = &m_faces[x][y]; | |
int numGreenLayers = 0; | |
float greenLayerIntensity = 0.0f; | |
for (int i = 0; i < 4; ++i) | |
{ | |
int newX = x + g_possibleMoves[possibleDirections[i]][0]; | |
int newY = y + g_possibleMoves[possibleDirections[i]][1]; | |
TerrainVertex *newVertex = &m_vertices[newX][newY]; | |
if (newX >= 0 && newX <= m_numFaces[0] && newY >= 0 && newY <= m_numFaces[1]) | |
{ | |
layerNos[i] = 0; | |
for (int j = 1; j < NUM_TERRAIN_LAYERS; ++j) | |
{ | |
if (newVertex->m_layerIntensities[j] > 0.4f) | |
layerNos[i] = j; | |
} | |
} | |
else | |
{ | |
layerNos[i] = -1; | |
} | |
if (layerNos[i] == tlt_green) | |
numGreenLayers++; | |
greenLayerIntensity += newVertex->m_layerIntensities[tlt_green]; | |
float intensity = 1.0f; | |
for (int j = NUM_TERRAIN_LAYERS - 1; j >= 0; --j) | |
{ | |
float val = newVertex->m_layerIntensities[j] * intensity; | |
face->m_layerIntensities[j] += val * 0.25f; | |
intensity -= val; | |
} | |
} | |
} | |
} | |
} | |
void TerrainGenerator::getVerticesForFace(int x, int y, int triangleNo, int *vertex0, int *vertex1, int *vertex2) | |
{ | |
TerrainFace *face = &m_faces[x][y]; | |
if (face->m_orientation) | |
{ | |
vertex0[0] = x; | |
vertex0[1] = y; | |
if (triangleNo == 0) | |
{ | |
vertex1[0] = x + 1; | |
vertex1[1] = y; | |
vertex2[0] = x + 1; | |
vertex2[1] = y + 1; | |
} | |
else | |
{ | |
vertex1[0] = x + 1; | |
vertex1[1] = y + 1; | |
vertex2[0] = x; | |
vertex2[1] = y + 1; | |
} | |
} | |
else | |
{ | |
vertex0[0] = x + 1; | |
vertex0[1] = y; | |
if (triangleNo == 0) | |
{ | |
vertex1[0] = x; | |
vertex1[1] = y + 1; | |
vertex2[0] = x; | |
vertex2[1] = y; | |
} | |
else | |
{ | |
vertex1[0] = x + 1; | |
vertex1[1] = y + 1; | |
vertex2[0] = x; | |
vertex2[1] = y + 1; | |
} | |
} | |
} | |
float TerrainGenerator::getRandom4X() | |
{ | |
return (Randf() + Randf() + Randf() + Randf()) / 4; | |
} | |
float TerrainGenerator::getVertexNoise(int x, int y) | |
{ | |
Vector4 noise = PerlinOctave(m_noiseFrequency, 0.5f, 1, m_positionNoiseRandomness + m_vertices[x][y].m_position); | |
return noise.x + noise.y + noise.z; | |
} | |
void TerrainGenerator::removeTerrainTypeFlags(unsigned int flags) | |
{ | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
m_vertices[x][y].m_terrainLayerFlags &= ~flags; | |
} | |
} | |
} | |
void TerrainGenerator::setTerrainTypeDepth(int type, float depth) | |
{ | |
for (int y = 0; y <= m_numFaces[1]; ++y) | |
{ | |
for (int x = 0; x <= m_numFaces[0]; ++x) | |
{ | |
if (m_vertices[x][y].m_terrainLayerFlags & BITSHIFT(type)) | |
m_vertices[x][y].m_position.z = depth; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string> | |
#include <vector> | |
#include "Vector2.h" | |
#include "Vector4.h" | |
#define NUM_TERRAIN_KEYS 6 | |
#define MIN_NUM_TERRAIN_FACES_PER_AXIS 40 | |
#define MAX_NUM_TERRAIN_FACES_PER_AXIS 250 | |
#define NUM_TERRAIN_LAYERS 15 | |
extern int g_possibleMoves[9][2]; | |
extern int g_possibleMoveDistances[8]; | |
enum RiverLayerType | |
{ | |
rlt_base = 2, | |
rlt_expanded = 4, | |
}; | |
enum TerrainLayerType | |
{ | |
tlt_rock = 0, | |
tlt_earth = 1, | |
tlt_green = 2, | |
tlt_riverbed = 3, | |
}; | |
enum RegionType | |
{ | |
rt_ocean = 0, | |
rt_mountain = 1, | |
rt_steppe = 2, | |
rt_plain = 3, | |
rt_snow = 4, | |
rt_desert = 5, | |
rt_bridge = 7, | |
rt_river = 8, | |
rt_mountain_forest = 9, | |
rt_steppe_forest = 10, | |
rt_forest = 11, | |
rt_snow_forest = 12, | |
rt_desert_forest = 13, | |
rt_shore = 21, | |
rt_foam = 22, | |
rt_waves = 23, | |
}; | |
enum GroundType | |
{ | |
ground_gray_stone = 0, | |
ground_brown_stone = 1, | |
ground_turf = 2, | |
ground_steppe = 3, | |
ground_snow = 4, | |
ground_earth = 5, | |
ground_desert = 6, | |
ground_forest = 7, | |
ground_pebbles = 8, | |
ground_village = 9, | |
ground_path = 10, | |
}; | |
class TerrainVertex | |
{ | |
public: | |
Vector4 m_position; | |
float m_slope; | |
unsigned int m_terrainLayerFlags; | |
Vector4 m_normal; | |
Vector2 m_riverDirection; | |
int m_riverCurveNo; | |
float m_layerIntensities[NUM_TERRAIN_LAYERS]; | |
public: | |
void initialize(const Vector4 &position); | |
}; | |
class TerrainFace | |
{ | |
public: | |
int m_orientation; | |
int m_layerNos[2]; | |
Vector4 m_normals[2]; | |
float m_layerIntensities[NUM_TERRAIN_LAYERS]; | |
public: | |
void initialize(); | |
}; | |
class TerrainLayer | |
{ | |
public: | |
int m_groundSpecNo; | |
int m_terrainType; | |
public: | |
void setGroundSpec(int groundSpecNo); | |
}; | |
class TerrainGenerator | |
{ | |
public: | |
unsigned int m_keys[6]; | |
TerrainLayer m_layers[NUM_TERRAIN_LAYERS]; | |
Vector2 m_size; | |
int m_numFaces[2]; | |
int m_numRiverPasses; | |
TerrainVertex m_vertices[MAX_NUM_TERRAIN_FACES_PER_AXIS + 1][MAX_NUM_TERRAIN_FACES_PER_AXIS + 1]; | |
TerrainFace m_faces[MAX_NUM_TERRAIN_FACES_PER_AXIS][MAX_NUM_TERRAIN_FACES_PER_AXIS]; | |
float m_detail; | |
float m_barrenness; | |
float m_noiseFrequency; | |
Vector4 m_positionNoiseRandomness; | |
int m_terrainBlockSize; | |
bool m_placeRiver; | |
public: | |
TerrainGenerator(); | |
void initialize(); | |
std::string getTerrainCode(); | |
void setTerrainCode(const std::string &code); | |
void setShadeOccluded(int value); | |
void setDisableGrass(int value); | |
void setPlaceRiver(int value); | |
void setDeepWater(int value); | |
void setSizeX(float value); | |
void setSizeY(float value); | |
void setHillHeight(float value); | |
void setValley(float value); | |
void setRuggedness(int value); | |
void setVegetation(float value); | |
void setRegionType(int value); | |
void setRegionDetail(int value); | |
void setSeed(int index, int value); | |
int getDisableGrass(); | |
int getPlaceRiver(); | |
int getDeepWater(); | |
float getSizeX(); | |
float getSizeY(); | |
float getHillHeight(); | |
float getValley(); | |
int getRuggedness(); | |
float getVegetation(); | |
int getRegionType(); | |
int getRegionDetail(); | |
int getSeed(int index); | |
void generate(); | |
void generateLayers(); | |
void generateTerrain(); | |
void generateHills(float widthFactor, float densityFactor, float heightFactor); | |
void generateHill(const Vector2 &position, float radius, float height); | |
void generateRiver(); | |
float placeRiver(int *start, int *end, int terrainType, float globalDirectionFactor, float globalHeightFactor, bool modifyVertices); | |
void expandRiver(int pass, unsigned int srcTerrainTypeFlags, unsigned int dstTerrainTypeFlags); | |
void smoothRiverHeight(int terrainType, float smoothFactor); | |
void smoothHeight(); | |
void computeNormals(); | |
void computeVertexLayerIntensities(); | |
void selectFaceOrientation(); | |
void selectFaceLayers(); | |
void roughenRockVertices(); | |
void computeFaceLayerIntensities(); | |
void getVerticesForFace(int x, int y, int triangleNo, int *vertex0, int *vertex1, int *vertex2); | |
float getRandom4X(); | |
float getVertexNoise(int x, int y); | |
void removeTerrainTypeFlags(unsigned int flags); | |
void setTerrainTypeDepth(int type, float depth); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Utils.h" | |
#include <cstdlib> | |
#include <cmath> | |
unsigned int g_randSeed; | |
float Min(float a, float b) | |
{ | |
return a <= b ? a : b; | |
} | |
int Min(int a, int b) | |
{ | |
return a <= b ? a : b; | |
} | |
int Min(unsigned int a, unsigned int b) | |
{ | |
return a <= b ? a : b; | |
} | |
float Max(float a, float b) | |
{ | |
return a >= b ? a : b; | |
} | |
int Max(int a, int b) | |
{ | |
return a >= b ? a : b; | |
} | |
unsigned int Max(unsigned int a, unsigned int b) | |
{ | |
return a >= b ? a : b; | |
} | |
float Clamp(float value, float min, float max) | |
{ | |
if (value < min) | |
return min; | |
if (value > max) | |
return max; | |
return value; | |
} | |
int ClampExclusive(int value, int min, int max) | |
{ | |
if (value < min) | |
return min; | |
if (value >= max) | |
return max - 1; | |
return value; | |
} | |
int ClampInclusive(int value, int min, int max) | |
{ | |
if (value < min) | |
return min; | |
if (value > max) | |
return max; | |
return value; | |
} | |
unsigned int ClampExclusive(unsigned int value, unsigned int min, unsigned int max) | |
{ | |
if (value < min) | |
return min; | |
if (value >= max) | |
return max - 1; | |
return value; | |
} | |
unsigned int ClampInclusive(unsigned int value, unsigned int min, unsigned int max) | |
{ | |
if (value < min) | |
return min; | |
if (value > max) | |
return max; | |
return value; | |
} | |
float Randf() | |
{ | |
return rand() % 15817 / 15817.0f; | |
} | |
float Randf(float max) | |
{ | |
return Randf() * max; | |
} | |
float Randf(float min, float max) | |
{ | |
return Randf() * (max - min) + min; | |
} | |
int Rand(int mod) | |
{ | |
return mod > 1 ? (rand() % mod) : 0; | |
} | |
float DegToRad(float degrees) | |
{ | |
return degrees * 0.0174532925f; | |
} | |
float RadToDeg(float radians) | |
{ | |
return radians * 57.2957795f; | |
} | |
int Round(float value) | |
{ | |
float f = floor(value); | |
return (value - f > 0.5f) ? (int)f + 1 : (int)f; | |
} | |
int Round1(float value) | |
{ | |
if (value <= 0.0f) | |
return (int)ceil(value - 0.00000001f); | |
else | |
return (int)ceil(value + 0.00000001f); | |
} | |
int Round2(float value) | |
{ | |
if (value <= 0.0f) | |
return (int)(value - 0.9999999f); | |
else | |
return (int)value; | |
} | |
__int64 Round64(float value) | |
{ | |
float f = floor(value); | |
return (value - f > 0.5f) ? (__int64)f + 1 : (__int64)f; | |
} | |
bool Between(int value, int min, int max) | |
{ | |
return value >= min && value < max; | |
} | |
bool Between(float value, float min, float max) | |
{ | |
return value >= min && value < max; | |
} | |
Vector4 MakeNormalFromPlane(const Vector4 &p0, const Vector4 &p1, const Vector4 &p2) | |
{ | |
Vector4 normal = (p1 - p0).cross(p2 - p0); | |
normal.normalize(); | |
return normal; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#if !defined _MSC_VER // need exact MSVC implementation of rand | |
extern unsigned int g_randSeed; | |
void srand(unsigned int seed) | |
{ | |
g_randSeed = seed; | |
} | |
int rand() | |
{ | |
g_randSeed = 214013 * g_randSeed + 2531011; | |
return (g_randSeed >> 16) & 0x7FFF; | |
} | |
#endif | |
#include "Vector4.h" | |
#define PI 3.14159265f | |
#define LOG2_E 1.44269504f | |
#define BITSHIFT64(x) (1ULL << (x)) | |
#define BITSHIFT(x) (1 << (x)) | |
float Min(float a, float b); | |
int Min(int a, int b); | |
int Min(unsigned int a, unsigned int b); | |
float Max(float a, float b); | |
int Max(int a, int b); | |
unsigned int Max(unsigned int a, unsigned int b); | |
float Clamp(float value, float min, float max); | |
int ClampExclusive(int value, int min, int max); | |
int ClampInclusive(int value, int min, int max); | |
unsigned int ClampExclusive(int value, unsigned int min, unsigned int max); | |
unsigned int ClampInclusive(int value, unsigned int min, unsigned int max); | |
float Randf(); | |
float Randf(float max); | |
float Randf(float min, float max); | |
int Rand(int mod); | |
float DegToRad(float degrees); | |
float RadToDeg(float radians); | |
int Round(float value); | |
int Round1(float value); | |
int Round2(float value); | |
__int64 Round64(float value); | |
bool Between(int value, int min, int max); | |
bool Between(float value, float min, float max); | |
Vector4 MakeNormalFromPlane(const Vector4 &p0, const Vector4 &p1, const Vector4 &p2); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Vector2.h" | |
#include "Utils.h" | |
#include <cmath> | |
const Vector2 Vector2::Zero = Vector2(0.0f); | |
const Vector2 Vector2::One = Vector2(1.0f); | |
Vector2::Vector2() | |
{ | |
} | |
Vector2::Vector2(float f) | |
{ | |
x = f; | |
y = f; | |
} | |
Vector2::Vector2(float fx, float fy) | |
{ | |
x = fx; | |
y = fy; | |
} | |
float Vector2::dot(const Vector2 &v) const | |
{ | |
return x * v.x + y * v.y; | |
} | |
float Vector2::length() const | |
{ | |
return sqrt(x * x + y * y); | |
} | |
float Vector2::lengthSquared() const | |
{ | |
return x * x + y * y; | |
} | |
float Vector2::normalize() | |
{ | |
float len = length(); | |
if (len <= 0.0f) | |
{ | |
x = 0.0f; | |
y = 1.0f; | |
} | |
else | |
{ | |
x /= len; | |
y /= len; | |
} | |
return len; | |
} | |
Vector2 Vector2::operator +(float f) const | |
{ | |
return Vector2(x + f, y + f); | |
} | |
Vector2 Vector2::operator +(const Vector2 &v) const | |
{ | |
return Vector2(x + v.x, y + v.y); | |
} | |
Vector2 Vector2::operator -() const | |
{ | |
return Vector2(-x, -y); | |
} | |
Vector2 Vector2::operator -(float f) const | |
{ | |
return Vector2(x - f, y - f); | |
} | |
Vector2 Vector2::operator -(const Vector2 &v) const | |
{ | |
return Vector2(x - v.x, y - v.y); | |
} | |
Vector2 Vector2::operator *(float f) const | |
{ | |
return Vector2(x * f, y * f); | |
} | |
Vector2 Vector2::operator *(const Vector2 &v) const | |
{ | |
return Vector2(x * v.x, y * v.y); | |
} | |
Vector2 Vector2::operator /(float f) const | |
{ | |
return Vector2(x / f, y / f); | |
} | |
Vector2 Vector2::operator /(const Vector2 &v) const | |
{ | |
return Vector2(x / v.x, y / v.y); | |
} | |
void Vector2::operator +=(float f) | |
{ | |
x += f; | |
y += f; | |
} | |
void Vector2::operator +=(const Vector2 &v) | |
{ | |
x += v.x; | |
y += v.y; | |
} | |
void Vector2::operator -=(float f) | |
{ | |
x -= f; | |
y -= f; | |
} | |
void Vector2::operator -=(const Vector2 &v) | |
{ | |
x -= v.x; | |
y -= v.y; | |
} | |
void Vector2::operator *=(float f) | |
{ | |
x *= f; | |
y *= f; | |
} | |
void Vector2::operator *=(const Vector2 &v) | |
{ | |
x *= v.x; | |
y *= v.y; | |
} | |
void Vector2::operator /=(float f) | |
{ | |
x /= f; | |
y /= f; | |
} | |
void Vector2::operator /=(const Vector2 &v) | |
{ | |
x /= v.x; | |
y /= v.y; | |
} | |
bool Vector2::operator ==(float f) const | |
{ | |
return x == f && y == f; | |
} | |
bool Vector2::operator ==(const Vector2 &v) const | |
{ | |
return x == v.x && y == v.y; | |
} | |
bool Vector2::operator !=(float f) const | |
{ | |
return x != f || y != f; | |
} | |
bool Vector2::operator !=(const Vector2 &v) const | |
{ | |
return x != v.x || y != v.y; | |
} | |
bool Vector2::operator >=(const Vector2 &v) const | |
{ | |
return x >= v.x && y >= v.y; | |
} | |
bool Vector2::operator <=(const Vector2 &v) const | |
{ | |
return x <= v.x && y <= v.y; | |
} | |
bool Vector2::operator >(const Vector2 &v) const | |
{ | |
return x > v.x && y > v.y; | |
} | |
bool Vector2::operator <(const Vector2 &v) const | |
{ | |
return x < v.x && y < v.y; | |
} | |
Vector2::operator float *() | |
{ | |
return (float *)this; | |
} | |
Vector2::operator float *() const | |
{ | |
return (float *)this; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
class Vector2 | |
{ | |
public: | |
static const Vector2 Zero; | |
static const Vector2 One; | |
public: | |
float x; | |
float y; | |
public: | |
Vector2(); | |
Vector2(float f); | |
Vector2(float fx, float fy); | |
float dot(const Vector2 &v) const; | |
float length() const; | |
float lengthSquared() const; | |
float normalize(); | |
Vector2 operator +(float f) const; | |
Vector2 operator +(const Vector2 &v) const; | |
Vector2 operator -() const; | |
Vector2 operator -(float f) const; | |
Vector2 operator -(const Vector2 &v) const; | |
Vector2 operator *(float f) const; | |
Vector2 operator *(const Vector2 &v) const; | |
Vector2 operator /(float f) const; | |
Vector2 operator /(const Vector2 &v) const; | |
void operator +=(float f); | |
void operator +=(const Vector2 &v); | |
void operator -=(float f); | |
void operator -=(const Vector2 &v); | |
void operator *=(float f); | |
void operator *=(const Vector2 &v); | |
void operator /=(float f); | |
void operator /=(const Vector2 &v); | |
bool operator ==(float f) const; | |
bool operator ==(const Vector2 &v) const; | |
bool operator !=(float f) const; | |
bool operator !=(const Vector2 &v) const; | |
bool operator >=(const Vector2 &v) const; | |
bool operator <=(const Vector2 &v) const; | |
bool operator >(const Vector2 &v) const; | |
bool operator <(const Vector2 &v) const; | |
operator float *(); | |
operator float *() const; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Vector4.h" | |
#include "Utils.h" | |
#include <cmath> | |
const Vector4 Vector4::Zero = Vector4(0.0f); | |
const Vector4 Vector4::One = Vector4(1.0f); | |
Vector4::Vector4() | |
{ | |
} | |
Vector4::Vector4(float f) | |
{ | |
x = f; | |
y = f; | |
z = f; | |
} | |
Vector4::Vector4(float fx, float fy, float fz) | |
{ | |
x = fx; | |
y = fy; | |
z = fz; | |
} | |
Vector4::Vector4(float fx, float fy, float fz, float fw) | |
{ | |
x = fx; | |
y = fy; | |
z = fz; | |
w = fw; | |
} | |
Vector4 Vector4::cross(const Vector4 &v) const | |
{ | |
return Vector4(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); | |
} | |
float Vector4::dot(const Vector4 &v) const | |
{ | |
return x * v.x + y * v.y + z * v.z; | |
} | |
float Vector4::length() const | |
{ | |
return std::sqrt(x * x + y * y + z * z); | |
} | |
float Vector4::lengthSquared() const | |
{ | |
return x * x + y * y + z * z; | |
} | |
float Vector4::normalize() | |
{ | |
float len = length(); | |
if (len <= 0.0000000001f) | |
{ | |
x = 0.0f; | |
y = 1.0f; | |
z = 0.0f; | |
} | |
else | |
{ | |
x /= len; | |
y /= len; | |
z /= len; | |
} | |
return len; | |
} | |
Vector4 Vector4::normalized() | |
{ | |
Vector4 vec = *this; | |
vec.normalize(); | |
return vec; | |
} | |
Vector2 Vector4::vec2() const | |
{ | |
return Vector2(x, y); | |
} | |
Vector4 Vector4::operator +(float f) const | |
{ | |
return Vector4(x + f, y + f, z + f); | |
} | |
Vector4 Vector4::operator +(const Vector4 &v) const | |
{ | |
return Vector4(x + v.x, y + v.y, z + v.z); | |
} | |
Vector4 Vector4::operator -() const | |
{ | |
return Vector4(-x, -y, -z); | |
} | |
Vector4 Vector4::operator -(float f) const | |
{ | |
return Vector4(x - f, y - f, z - f); | |
} | |
Vector4 Vector4::operator -(const Vector4 &v) const | |
{ | |
return Vector4(x - v.x, y - v.y, z - v.z); | |
} | |
Vector4 Vector4::operator *(float f) const | |
{ | |
return Vector4(x * f, y * f, z * f); | |
} | |
Vector4 Vector4::operator *(const Vector4 &v) const | |
{ | |
return Vector4(x * v.x, y * v.y, z * v.z); | |
} | |
Vector4 Vector4::operator /(float f) const | |
{ | |
return Vector4(x / f, y / f, z / f); | |
} | |
Vector4 Vector4::operator /(const Vector4 &v) const | |
{ | |
return Vector4(x / v.x, y / v.y, z / v.z); | |
} | |
void Vector4::operator +=(float f) | |
{ | |
x += f; | |
y += f; | |
z += f; | |
} | |
void Vector4::operator +=(const Vector4 &v) | |
{ | |
x += v.x; | |
y += v.y; | |
z += v.z; | |
} | |
void Vector4::operator -=(float f) | |
{ | |
x -= f; | |
y -= f; | |
z -= f; | |
} | |
void Vector4::operator -=(const Vector4 &v) | |
{ | |
x -= v.x; | |
y -= v.y; | |
z -= v.z; | |
} | |
void Vector4::operator *=(float f) | |
{ | |
x *= f; | |
y *= f; | |
z *= f; | |
} | |
void Vector4::operator *=(const Vector4 &v) | |
{ | |
x *= v.x; | |
y *= v.y; | |
z *= v.z; | |
} | |
void Vector4::operator /=(float f) | |
{ | |
x /= f; | |
y /= f; | |
z /= f; | |
} | |
void Vector4::operator /=(const Vector4 &v) | |
{ | |
x /= v.x; | |
y /= v.y; | |
z /= v.z; | |
} | |
bool Vector4::operator ==(float f) const | |
{ | |
return x == f && y == f && z == f; | |
} | |
bool Vector4::operator ==(const Vector4 &v) const | |
{ | |
return x == v.x && y == v.y && z == v.z; | |
} | |
bool Vector4::operator !=(float f) const | |
{ | |
return x != f || y != f || z != f; | |
} | |
bool Vector4::operator !=(const Vector4 &v) const | |
{ | |
return x != v.x || y != v.y || z != v.z; | |
} | |
bool Vector4::operator >=(const Vector4 &v) const | |
{ | |
return x >= v.x && y >= v.y && z >= v.z; | |
} | |
bool Vector4::operator <=(const Vector4 &v) const | |
{ | |
return x <= v.x && y <= v.y && z <= v.z; | |
} | |
bool Vector4::operator >(const Vector4 &v) const | |
{ | |
return x > v.x && y > v.y && z > v.z; | |
} | |
bool Vector4::operator <(const Vector4 &v) const | |
{ | |
return x < v.x && y < v.y && z < v.z; | |
} | |
float &Vector4::operator [](int index) | |
{ | |
return ((float *)this)[index]; | |
} | |
const float &Vector4::operator [](int index) const | |
{ | |
return ((float *)this)[index]; | |
} | |
Vector4::operator Vector2() const | |
{ | |
return vec2(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "Vector2.h" | |
class Vector4 | |
{ | |
public: | |
static const Vector4 Zero; | |
static const Vector4 One; | |
public: | |
float x; | |
float y; | |
float z; | |
float w; | |
public: | |
Vector4(); | |
Vector4(float f); | |
Vector4(float fx, float fy, float fz); | |
Vector4(float fx, float fy, float fz, float fw); | |
Vector4 cross(const Vector4 &v) const; | |
float dot(const Vector4 &v) const; | |
float length() const; | |
float lengthSquared() const; | |
float normalize(); | |
Vector4 normalized(); | |
Vector2 vec2() const; | |
Vector4 operator +(float f) const; | |
Vector4 operator +(const Vector4 &v) const; | |
Vector4 operator -() const; | |
Vector4 operator -(float f) const; | |
Vector4 operator -(const Vector4 &v) const; | |
Vector4 operator *(float f) const; | |
Vector4 operator *(const Vector4 &v) const; | |
Vector4 operator /(float f) const; | |
Vector4 operator /(const Vector4 &v) const; | |
void operator +=(float f); | |
void operator +=(const Vector4 &v); | |
void operator -=(float f); | |
void operator -=(const Vector4 &v); | |
void operator *=(float f); | |
void operator *=(const Vector4 &v); | |
void operator /=(float f); | |
void operator /=(const Vector4 &v); | |
bool operator ==(float f) const; | |
bool operator ==(const Vector4 &v) const; | |
bool operator !=(float f) const; | |
bool operator !=(const Vector4 &v) const; | |
bool operator >=(const Vector4 &v) const; | |
bool operator <=(const Vector4 &v) const; | |
bool operator >(const Vector4 &v) const; | |
bool operator <(const Vector4 &v) const; | |
float &operator [](int index); | |
const float &operator [](int index) const; | |
operator Vector2() const; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <Shlwapi.h> | |
#include <fstream> | |
#include "TerrainGenerator.h" | |
int main(int argc, char **argv) | |
{ | |
char path[MAX_PATH]; | |
GetModuleFileName(NULL, path, MAX_PATH); | |
PathStripPath(path); | |
if (argc != 3) | |
{ | |
printf("usage: %s output_file hex_terrain_code\n", path); | |
printf("example: %s terrain.txt 0x000000003a07b2320002589600003f3f000054c900007c97\n", path); | |
system("pause"); | |
return EXIT_SUCCESS; | |
} | |
TerrainGenerator *terrainGen; // too big for stack | |
try | |
{ | |
terrainGen = new TerrainGenerator(); | |
terrainGen->setTerrainCode(argv[2]); | |
terrainGen->generate(); | |
} | |
catch (...) // just for SEH, needs /EHa | |
{ | |
printf("exception while generating terrain. check your input mang :[\n"); | |
system("pause"); | |
return EXIT_SUCCESS; | |
} | |
std::ofstream outStream(argv[1], std::ios::trunc); | |
if (!outStream.is_open()) | |
{ | |
printf("failed to create output file\n"); | |
system("pause"); | |
return EXIT_SUCCESS; | |
} | |
outStream << "Num vertices (x, y):" << std::endl; | |
outStream << (terrainGen->m_numFaces[0] + 1) << " " << (terrainGen->m_numFaces[2] + 1) << std::endl; | |
outStream << "Vertices (x, y, pos x, pos y, pos z):" << std::endl; | |
for (int x = 0; x <= terrainGen->m_numFaces[0]; ++x) | |
{ | |
for (int y = 0; y <= terrainGen->m_numFaces[1]; ++y) | |
{ | |
TerrainVertex *vtx = &terrainGen->m_vertices[x][y]; | |
outStream << x << " " << y << " " << vtx->m_position.x << " " << vtx->m_position.y << " " << vtx->m_position.z << std::endl; | |
} | |
} | |
outStream.close(); | |
printf("terrain data stored to %s\n", argv[1]); | |
system("pause"); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment