/* Takes points (x, y) and returns a height (n) */ VALUE Perlin_Generator_run2d(const VALUE self, const VALUE x, const VALUE y) { GENERATOR(); if(generator->is_classic) { seed = generator->seed; // Store in global, for speed. return rb_float_new(perlin_octaves_2d(NUM2DBL(x), NUM2DBL(y), generator->persistence, generator->octave)); } else { return rb_float_new(octave_noise_3d(generator->octave, generator->persistence, 1.0, NUM2DBL(x), NUM2DBL(y), generator->seed)); } }
// 3D Scaled Multi-octave Simplex noise. // // Returned value will be between loBound and hiBound. double scaled_octave_noise_3d( const int octaves, const double persistence, const double scale, const double loBound, const double hiBound, const double x, const double y, const double z ) { return octave_noise_3d(octaves, persistence, scale, x, y, z) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; }
// 3D Scaled Multi-octave Simplex noise. // // Returned value will be between loBound and hiBound. float scaled_octave_noise_3d( const float octaves, const float persistence, const float scale, const float loBound, const float hiBound, const float x, const float y, const float z ) { return octave_noise_3d(octaves, persistence, scale, x, y, z) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; }
// 3D Marble Noise: x-axis. float marble_noise_3d( const float octaves, const float persistence, const float scale, const float x, const float y, const float z ) { return cosf( x * scale + octave_noise_3d(octaves, persistence, scale / 3, x, y, z) ); }
/* Returns a chunk of coordinates starting from x, y and of size steps_x, steps_y with interval. */ VALUE Perlin_Generator_chunk2d(const VALUE self, const VALUE x, const VALUE y, const VALUE steps_x, const VALUE steps_y, const VALUE interval) { GENERATOR(); VALUE arr, row; int i, j; const float x_min = NUM2DBL(x), y_min = NUM2DBL(y); float _x, _y; const int _steps_x = NUM2INT(steps_x), _steps_y = NUM2INT(steps_y); const float _interval = NUM2DBL(interval); if(_steps_x < 1 || _steps_y < 1) { rb_raise(rb_eArgError, "steps must be >= 1"); } if(generator->is_classic) seed = generator->seed; // Store in global, for speed. if(rb_block_given_p()) { // Iterate through x, then y [0, 0], [1, 0], [2, 0]... _x = x_min; for (i = 0; i < _steps_x; i++) { _y = y_min; for (j = 0; j < _steps_y; j++) { if(generator->is_classic) { rb_yield_values(3, rb_float_new(perlin_octaves_2d(_x, _y, generator->persistence, generator->octave)), rb_float_new(_x), rb_float_new(_y)); } else { rb_yield_values(3, rb_float_new(octave_noise_3d(generator->octave, generator->persistence, 1.0, _x, _y, generator->seed)), rb_float_new(_x), rb_float_new(_y)); } _y += _interval; } _x += _interval; } return Qnil; } else { // 2D array can be indexed with arr[x][y] arr = rb_ary_new(); _x = x_min; for (i = 0; i < _steps_x; i++) { row = rb_ary_new(); _y = y_min; for (j = 0; j < _steps_y; j++) { if(generator->is_classic) { rb_ary_push(row, rb_float_new(perlin_octaves_2d(_x, _y, generator->persistence, generator->octave))); } else { rb_ary_push(row, rb_float_new(octave_noise_3d(generator->octave, generator->persistence, 1.0, _x, _y, generator->seed))); } _y += _interval; } rb_ary_push(arr, row); _x += _interval; } return arr; } }
float Landscape::getAltitude(int x, int z) { float height = octave_noise_3d(3, 0.5, 0.005, GAME::SEED, x, z); return height; }
void Chunk::Setup() { ChunkStorageLoader* pChunkStorage = m_pChunkManager->GetChunkStorage(m_gridX, m_gridY, m_gridZ, false); for (int x = 0; x < CHUNK_SIZE; x++) { for (int z = 0; z < CHUNK_SIZE; z++) { float xPosition = m_position.x + x; float zPosition = m_position.z + z; float noise = octave_noise_2d(m_pVoxSettings->m_landscapeOctaves, m_pVoxSettings->m_landscapePersistence, m_pVoxSettings->m_landscapeScale, xPosition, zPosition); float noiseNormalized = ((noise + 1.0f) * 0.5f); float mountainNoise = octave_noise_2d(m_pVoxSettings->m_mountainOctaves, m_pVoxSettings->m_mountainPersistence, m_pVoxSettings->m_mountainScale, xPosition, zPosition); float mountainNoiseNormalise = (mountainNoise + 1.0f) * 0.5f; float mountainMultiplier = m_pVoxSettings->m_mountainMultiplier * mountainNoiseNormalise; float noiseHeight = noiseNormalized * CHUNK_SIZE; noiseHeight *= mountainMultiplier; if (m_gridY < 0) { noiseHeight = CHUNK_SIZE; } for (int y = 0; y < CHUNK_SIZE; y++) { float yPosition = m_position.y + y; if (pChunkStorage != NULL && pChunkStorage->m_blockSet[x][y][z] == true) { SetColour(x, y, z, pChunkStorage->m_colour[x][y][z]); } else { if (y + (m_gridY*CHUNK_SIZE) < noiseHeight) { float colorNoise = octave_noise_3d(4.0f, 0.3f, 0.005f, xPosition, yPosition, zPosition); float colorNoiseNormalized = ((colorNoise + 1.0f) * 0.5f); float red1 = 0.65f; float green1 = 0.80f; float blue1 = 0.00f; float red2 = 0.00f; float green2 = 0.46f; float blue2 = 0.16f; if (noise < -0.5f) { red1 = 0.10f; green1 = 0.25f; blue1 = 1.00f; red2 = 0.10f; green2 = 0.25f; blue2 = 1.00f; } else if (noise < -0.25f) { red1 = 0.94f; green1 = 0.74f; blue1 = 0.34f; red2 = 0.50f; green2 = 0.29f; blue2 = 0.20f; } else if (noise < 0.5f) { red1 = 0.65f; green1 = 0.80f; blue1 = 0.00f; red2 = 0.00f; green2 = 0.46f; blue2 = 0.16f; } else if (noise < 1.0f) { red1 = 0.85f; green1 = 0.85f; blue1 = 0.85f; red2 = 0.77f; green2 = 0.65f; blue2 = 0.80f; } float alpha = 1.0f; float r = red1 + ((red2 - red1) * colorNoiseNormalized); float g = green1 + ((green2 - green1) * colorNoiseNormalized); float b = blue1 + ((blue2 - blue1) * colorNoiseNormalized); SetColour(x, y, z, r, g, b, alpha); } } } // Tree generation if (m_gridY >= 0) // Only above ground { // Trees if ((GetRandomNumber(0, 1000) >= 1000)) { if (noiseNormalized >= 0.5f) { vec3 treePos = vec3(xPosition, noiseHeight, zPosition); m_pChunkManager->ImportQubicleBinary("media/gamedata/terrain/plains/smalltree.qb", treePos, QubicleImportDirection_Normal); } } // Scenery if ((GetRandomNumber(0, 1000) >= 995)) { if (noiseNormalized >= 0.5f) { vec3 pos = vec3(xPosition, noiseHeight, zPosition); //m_pSceneryManager->AddSceneryObject("flower", "media/gamedata/terrain/plains/flower1.qb", pos, vec3(0.0f, 0.0f, 0.0f), QubicleImportDirection_Normal, QubicleImportDirection_Normal, 0.08f, GetRandomNumber(0, 360, 2)); } } } } } // Remove the chunk storage loader since we no longer need it if (pChunkStorage != NULL) { m_pChunkManager->RemoveChunkStorageLoader(pChunkStorage); } m_setup = true; SetNeedsRebuild(true, true); }