Skip to content

Instantly share code, notes, and snippets.

@Swyter
Last active April 26, 2021 19:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Swyter/1a06baf7fe5c057d19229b176dbe34ca to your computer and use it in GitHub Desktop.
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.
#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;
}
#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);
#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;
}
}
}
#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);
};
#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;
}
#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);
#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;
}
#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;
};
#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();
}
#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;
};
#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