Initial Commit

Late as shit... as usual
This commit is contained in:
Thomas Muller 2021-03-14 21:13:29 -04:00
commit 439051e52c
Signed by: thomas
GPG key ID: AF006EB730564952
26 changed files with 6352 additions and 0 deletions

65
.gitignore vendored Normal file
View file

@ -0,0 +1,65 @@
# Created by https://www.toptal.com/developers/gitignore/api/cmake,c++
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,c++
### C++ ###
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
### CMake ###
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
CMakeUserPresets.json
### CMake Patch ###
# External projects
*-prefix/
# End of https://www.toptal.com/developers/gitignore/api/cmake,c++
build/

17
CMakeLists.txt Normal file
View file

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.10)
project(main)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
include_directories(src)
add_definitions(-g)
add_definitions(-fsanitize=address)
file(GLOB SOURCES "src/*.cpp" "src/**/*.cpp")
add_executable(${CMAKE_PROJECT_NAME} ${SOURCES})
target_link_libraries(${CMAKE_PROJECT_NAME} X11 GL pthread png stdc++fs)
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE -fsanitize=address)

93
src/app.cpp Normal file
View file

@ -0,0 +1,93 @@
#include "app.h"
#include "map/map.h"
#include "tiles/dirt.h"
#include "tiles/grass.h"
#include "util/vector2.h"
#include <iostream>
App::App() :
m_render(this) {
sAppName = "Automation";
}
bool App::OnUserCreate()
{
std::cout << "Create" << std::endl;
return true;
}
bool App::OnUserUpdate(float delta)
{
Vector2<int> screen = {ScreenWidth(), ScreenHeight()};
Vector2<int> mouse = {GetMouseX(), GetMouseY()};
// Save and load keys
if(GetKey(olc::Key::S).bReleased)
m_map.save();
if(GetKey(olc::Key::L).bReleased)
m_map.load();
// Basic block placing
if(GetMouse(0).bPressed) {
auto screen_pos = mouse - m_camera_pos;
auto tile_pos = screen_pos / (TILE_SIZE + 1);
if(screen_pos.x() < 0) tile_pos -= {1, 0};
if(screen_pos.y() < 0) tile_pos -= {0, 1};
m_map.set_tile(tile_pos, new Tile());
}
if(GetMouse(1).bPressed) {
auto screen_pos = mouse - m_camera_pos;
auto tile_pos = screen_pos / (TILE_SIZE + 1);
if(screen_pos.x() < 0) tile_pos -= {1, 0};
if(screen_pos.y() < 0) tile_pos -= {0, 1};
m_map.set_tile(tile_pos, new Dirt());
}
// Pan camera with middle mouse
if(GetMouse(2).bPressed) {
m_drag_start = {GetMouseX(), GetMouseY()};
}
if(GetMouse(2).bHeld) {
m_camera_pos += mouse - m_drag_start;
m_drag_start = mouse;
}
m_render.set_camera_pos(m_camera_pos);
// Clear screen
Clear({24, 24, 24});
// Render only what we can see
auto min = -m_camera_pos / (TILE_SIZE + 1);
auto max = (screen - m_camera_pos) / (TILE_SIZE + 1);
for(int y = min.y() - 1; y < max.y() + 1; y++) {
for(int x = min.x() - 1; x < max.x() + 1; x++) {
auto node = m_map.at(Vector2<int>(x, y));
node.render(m_render);
}
}
// Draw current coordinates in top left
char buf[128] = "";
sprintf(buf, "%d, %d", -m_camera_pos.x() / TILE_SIZE, -m_camera_pos.y() / TILE_SIZE);
DrawString(0, 0, buf, {255, 255, 255}, 1);
return true;
}
bool App::OnUserDestroy() {
std::cout << "Destroy" << std::endl;
return true;
}
int main()
{
App app;
if (app.Construct(800, 600, 1, 1))
app.Start();
return 0;
}

25
src/app.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#define OLC_PGE_APPLICATION
#include "olcPixelGameEngine.h"
#include "map/map.h"
#include "util/render.h"
class App : public olc::PixelGameEngine {
public:
App();
public:
bool OnUserCreate() override;
bool OnUserUpdate(float delta) override;
bool OnUserDestroy() override;
private:
Render m_render;
Map m_map;
Vector2<int> m_drag_start;
Vector2<int> m_camera_pos;
};

31
src/map/generator.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "map/generator.h"
#include "tiles/dirt.h"
#include "tiles/grass.h"
#include "tiles/stone.h"
Generator::Generator() {
// set_seed(420);
}
void Generator::generate(Vector2<int> pos, Region &region) {
for(int y = 0; y < REGION_SIZE; y++) {
for(int x = 0; x < REGION_SIZE; x++) {
auto world_pos = pos * REGION_SIZE + Vector2<int>(x, y);
double noise = m_noise.accumulatedOctaveNoise2D_0_1(
world_pos.x() / 64.0,
world_pos.y() / 64.0,
5
);
Tile *tile;
if(noise > 0.85) {
tile = new Stone();
} else if(noise > 0.3) {
tile = new Grass();
} else {
tile = new Dirt();
}
region.at({x, y}).set_tile(tile);
}
}
}

19
src/map/generator.h Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "map/region.h"
#include "perlin.h"
#include "util/vector2.h"
class Generator {
public:
Generator();
// void set_seed(int seed) { m_noise.reseed(seed); }
int seed() { return m_seed; }
void generate(Vector2<int> pos, Region &region);
private:
int m_seed;
siv::PerlinNoise m_noise;
};

62
src/map/map.cpp Normal file
View file

@ -0,0 +1,62 @@
#include "map/map.h"
#include <iostream>
#include "tiles/grass.h"
#define MOD(a, b) (((b) + ((a) % (b))) % (b))
Node &Map::at(Vector2<int> pos) {
Vector2<int> region_offset = pos / (REGION_SIZE + 0);
// Floor division
if(pos.x() < 0 && pos.x() % REGION_SIZE) region_offset -= {1, 0};
if(pos.y() < 0 && pos.y() % REGION_SIZE) region_offset -= {0, 1};
auto it = m_reigons.find(region_offset);
if(it == m_reigons.end()) {
m_reigons.insert(
std::pair<Vector2<int>, Region>(
region_offset,
load_or_create_region(region_offset)
)
);
}
Region &region = m_reigons.at(region_offset);
Vector2<int> tile_offset = Vector2<int>(MOD(pos.x(), REGION_SIZE), MOD(pos.y(), REGION_SIZE));
return region.at(tile_offset);
}
void Map::set_tile(Vector2<int> pos, Tile *tile) {
at(pos).set_tile(tile);
}
void Map::save() {
for(auto &elm : m_reigons) {
elm.second.save();
}
}
void Map::load() {
for(auto &elm : m_reigons) {
elm.second.load();
}
}
Region Map::load_or_create_region(Vector2<int> pos) {
Region region(pos);
if(!region.load()) {
std::cout << "Generating region @" << pos << std::endl;
// Call generator
m_grass.generate(pos, region);
// Save the newly generated region
region.save();
} else {
std::cout << "Loaded region @" << pos << std::endl;
}
return region;
}

24
src/map/map.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <map>
#include "map/generator.h"
#include "map/region.h"
#include "util/vector2.h"
class Map {
public:
Map() = default;
Node &at(Vector2<int> pos);
void set_tile(Vector2<int> pos, Tile *tile);
void save();
void load();
private:
Region load_or_create_region(Vector2<int> pos);
std::map<Vector2<int>, Region> m_reigons;
Generator m_grass;
};

68
src/map/node.cpp Normal file
View file

@ -0,0 +1,68 @@
#include "map/node.h"
#include "tiles/dirt.h"
#include "tiles/grass.h"
#include "tiles/stone.h"
Node::Node(const Node &other) {
if(other.m_tile) m_tile = other.m_tile->clone();
// if(other.m_entity) m_entity = other.m_entity->clone();
m_pos = other.m_pos;
m_size = other.m_size;
}
Node::~Node() {
if(m_tile) delete m_tile;
// if(m_entity) delete(m_entity);
}
void Node::render(Render r) {
if(m_tile)
m_tile->render(r, pos(), size());
}
std::ostream &operator<<(std::ostream &os, const Node &node) {
os.write(reinterpret_cast<const char *>(&node.m_size), sizeof(node.m_size));
if(node.m_tile) {
os << '\x01';
os << *node.m_tile;
} else {
os << '\x00';
}
return os;
}
std::istream &operator>>(std::istream &is, Node &node) {
is.read(reinterpret_cast<char *>(&node.m_size), sizeof(node.m_size));
uint8_t has_tile = 0;
is.read(reinterpret_cast<char *>(&has_tile), sizeof(has_tile));
if(has_tile) {
int id = 0;
// TODO: Move / figure this shit out
is.read(reinterpret_cast<char *>(&id), sizeof(id));
Tile *tile;
switch(id) {
case -1:
tile = new Tile();
break;
case 1:
tile = new Dirt();
break;
case 2:
tile = new Grass();
break;
case 3:
tile = new Stone();
default:
break;
}
if(tile) node.set_tile(tile);
is >> *node.m_tile;
}
return is;
}

54
src/map/node.h Normal file
View file

@ -0,0 +1,54 @@
#pragma once
#include <iostream>
#include "tiles/tile.h"
#include "util/render.h"
#include "util/vector2.h"
class Node {
public:
Node() : Node({0, 0}, {1, 1}) {}
Node(Vector2<int> pos, Vector2<int> size) :
m_pos(pos),
m_size(size) {}
Node(const Node &other);
Node &operator=(const Node &other) = default;
~Node();
// Get a reference to the tile associated with this node
Tile *tile() { return m_tile; }
void set_tile(Tile *tile) {
if(m_tile)
delete m_tile;
m_tile = tile;
}
// Get a reference to the tile entity associated with this node
// Entity &entity() { return *m_entity; }
// Get/Set the position in world coordinates
Vector2<int> pos() { return m_pos; }
void set_pos(Vector2<int> pos) { m_pos = pos; }
// Get/Set the size of this block in tiles
Vector2<int> size() { return m_size; }
void set_size(Vector2<int> size) { m_size = size; }
void render(Render r);
friend std::ostream &operator<<(std::ostream &os, const Node &node);
friend std::istream &operator>>(std::istream &is, Node &node);
private:
Tile *m_tile = 0;
// Entity *m_entity;
Vector2<int> m_pos;
Vector2<int> m_size;
};

66
src/map/region.cpp Normal file
View file

@ -0,0 +1,66 @@
#include "map/region.h"
#include <cstdio>
#include <fstream>
using std::ios;
using std::ofstream;
using std::ifstream;
Region::Region(Vector2<int> pos) :
m_pos(pos) {
// Initialize node positions
for(int y = 0; y < REGION_SIZE; y++)
for(int x = 0; x < REGION_SIZE; x++)
m_nodes[y][x] = Node(pos * REGION_SIZE + Vector2<int>(x, y), {1, 1});
}
Node &Region::at(Vector2<int> pos) {
if(pos.x() < 0 || pos.y() < 0 || pos.x() >= REGION_SIZE || pos.y() >= REGION_SIZE) {
printf("[ERR] Region::at(%i, %i): Invalid tile location!", pos.x(), pos.y());
return *(Node *)0; // TODO: Crash
}
return m_nodes[pos.y()][pos.x()];
}
bool Region::save() {
char path[25];
sprintf(path, "region/%d_%d.dat", m_pos.x(), m_pos.y());
ofstream file;
file.open(path, ios::out | ios::binary);
if(!file.good()) return false;
file.write(reinterpret_cast<const char *>(&m_pos), sizeof(m_pos));
for(int y = 0; y < REGION_SIZE; y++)
for(int x = 0; x < REGION_SIZE; x++)
file << m_nodes[y][x];
file.close();
return true;
}
bool Region::load() {
char path[25];
sprintf(path, "region/%d_%d.dat", m_pos.x(), m_pos.y());
ifstream file;
file.open(path, ios::in | ios::binary);
if(!file.good()) return false;
file.read(reinterpret_cast<char *>(&m_pos), sizeof(m_pos));
for(int y = 0; y < REGION_SIZE; y++)
for(int x = 0; x < REGION_SIZE; x++) {
// Load node data
file >> m_nodes[y][x];
// Set node position
m_nodes[y][x].set_pos(m_pos * REGION_SIZE + Vector2<int>(x, y));
}
file.close();
return true;
}

24
src/map/region.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "map/node.h"
#define REGION_SIZE 16
class Region {
public:
Region() : Region({0, 0}) {};
Region(Vector2<int> pos);
Vector2<int> pos() { return m_pos; };
Color m_color = Color::from_hsv(rand() % 254, 255, 255);
Node &at(Vector2<int> pos);
bool save();
bool load();
private:
Vector2<int> m_pos;
Node m_nodes[REGION_SIZE][REGION_SIZE];
};

5105
src/olcPixelGameEngine.h Normal file

File diff suppressed because it is too large Load diff

407
src/perlin.h Normal file
View file

@ -0,0 +1,407 @@
//----------------------------------------------------------------------------------------
//
// siv::PerlinNoise
// Perlin noise library for modern C++
//
// Copyright (C) 2013-2020 Ryo Suzuki <reputeless@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//----------------------------------------------------------------------------------------
# pragma once
# include <cstdint>
# include <algorithm>
# include <array>
# ifdef __cpp_concepts
# if __has_include(<concepts>)
# include <concepts>
# endif
# endif
# include <iterator>
# include <numeric>
# include <random>
# include <type_traits>
namespace siv
{
# ifdef __cpp_lib_concepts
template <std::floating_point Float>
# else
template <class Float>
# endif
class BasicPerlinNoise
{
public:
using value_type = Float;
private:
std::uint8_t p[512];
[[nodiscard]]
static constexpr value_type Fade(value_type t) noexcept
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
[[nodiscard]]
static constexpr value_type Lerp(value_type t, value_type a, value_type b) noexcept
{
return a + t * (b - a);
}
[[nodiscard]]
static constexpr value_type Grad(std::uint8_t hash, value_type x, value_type y, value_type z) noexcept
{
const std::uint8_t h = hash & 15;
const value_type u = h < 8 ? x : y;
const value_type v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
[[nodiscard]]
static constexpr value_type Weight(std::int32_t octaves) noexcept
{
value_type amp = 1;
value_type value = 0;
for (std::int32_t i = 0; i < octaves; ++i)
{
value += amp;
amp /= 2;
}
return value;
}
public:
# if __has_cpp_attribute(nodiscard) >= 201907L
[[nodiscard]]
# endif
explicit BasicPerlinNoise(std::uint32_t seed = std::default_random_engine::default_seed)
{
reseed(seed);
}
# ifdef __cpp_lib_concepts
template <std::uniform_random_bit_generator URNG>
# else
template <class URNG, std::enable_if_t<!std::is_arithmetic_v<URNG>>* = nullptr>
# endif
# if __has_cpp_attribute(nodiscard) >= 201907L
[[nodiscard]]
# endif
explicit BasicPerlinNoise(URNG&& urng)
{
reseed(std::forward<URNG>(urng));
}
void reseed(std::uint32_t seed)
{
for (size_t i = 0; i < 256; ++i)
{
p[i] = static_cast<std::uint8_t>(i);
}
std::shuffle(std::begin(p), std::begin(p) + 256, std::default_random_engine(seed));
for (size_t i = 0; i < 256; ++i)
{
p[256 + i] = p[i];
}
}
# ifdef __cpp_lib_concepts
template <std::uniform_random_bit_generator URNG>
# else
template <class URNG, std::enable_if_t<!std::is_arithmetic_v<URNG>>* = nullptr>
# endif
void reseed(URNG&& urng)
{
for (size_t i = 0; i < 256; ++i)
{
p[i] = static_cast<std::uint8_t>(i);
}
std::shuffle(std::begin(p), std::begin(p) + 256, std::forward<URNG>(urng));
for (size_t i = 0; i < 256; ++i)
{
p[256 + i] = p[i];
}
}
///////////////////////////////////////
//
// Noise [-1, 1]
//
[[nodiscard]]
value_type noise1D(value_type x) const noexcept
{
return noise3D(x, 0, 0);
}
[[nodiscard]]
value_type noise2D(value_type x, value_type y) const noexcept
{
return noise3D(x, y, 0);
}
[[nodiscard]]
value_type noise3D(value_type x, value_type y, value_type z) const noexcept
{
const std::int32_t X = static_cast<std::int32_t>(std::floor(x)) & 255;
const std::int32_t Y = static_cast<std::int32_t>(std::floor(y)) & 255;
const std::int32_t Z = static_cast<std::int32_t>(std::floor(z)) & 255;
x -= std::floor(x);
y -= std::floor(y);
z -= std::floor(z);
const value_type u = Fade(x);
const value_type v = Fade(y);
const value_type w = Fade(z);
const std::int32_t A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
const std::int32_t B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
return Lerp(w, Lerp(v, Lerp(u, Grad(p[AA], x, y, z),
Grad(p[BA], x - 1, y, z)),
Lerp(u, Grad(p[AB], x, y - 1, z),
Grad(p[BB], x - 1, y - 1, z))),
Lerp(v, Lerp(u, Grad(p[AA + 1], x, y, z - 1),
Grad(p[BA + 1], x - 1, y, z - 1)),
Lerp(u, Grad(p[AB + 1], x, y - 1, z - 1),
Grad(p[BB + 1], x - 1, y - 1, z - 1))));
}
///////////////////////////////////////
//
// Noise [0, 1]
//
[[nodiscard]]
value_type noise1D_0_1(value_type x) const noexcept
{
return noise1D(x)
* value_type(0.5) + value_type(0.5);
}
[[nodiscard]]
value_type noise2D_0_1(value_type x, value_type y) const noexcept
{
return noise2D(x, y)
* value_type(0.5) + value_type(0.5);
}
[[nodiscard]]
value_type noise3D_0_1(value_type x, value_type y, value_type z) const noexcept
{
return noise3D(x, y, z)
* value_type(0.5) + value_type(0.5);
}
///////////////////////////////////////
//
// Accumulated octave noise
// * Return value can be outside the range [-1, 1]
//
[[nodiscard]]
value_type accumulatedOctaveNoise1D(value_type x, std::int32_t octaves) const noexcept
{
value_type result = 0;
value_type amp = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += noise1D(x) * amp;
x *= 2;
amp /= 2;
}
return result; // unnormalized
}
[[nodiscard]]
value_type accumulatedOctaveNoise2D(value_type x, value_type y, std::int32_t octaves) const noexcept
{
value_type result = 0;
value_type amp = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += noise2D(x, y) * amp;
x *= 2;
y *= 2;
amp /= 2;
}
return result; // unnormalized
}
[[nodiscard]]
value_type accumulatedOctaveNoise3D(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept
{
value_type result = 0;
value_type amp = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += noise3D(x, y, z) * amp;
x *= 2;
y *= 2;
z *= 2;
amp /= 2;
}
return result; // unnormalized
}
///////////////////////////////////////
//
// Normalized octave noise [-1, 1]
//
[[nodiscard]]
value_type normalizedOctaveNoise1D(value_type x, std::int32_t octaves) const noexcept
{
return accumulatedOctaveNoise1D(x, octaves)
/ Weight(octaves);
}
[[nodiscard]]
value_type normalizedOctaveNoise2D(value_type x, value_type y, std::int32_t octaves) const noexcept
{
return accumulatedOctaveNoise2D(x, y, octaves)
/ Weight(octaves);
}
[[nodiscard]]
value_type normalizedOctaveNoise3D(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept
{
return accumulatedOctaveNoise3D(x, y, z, octaves)
/ Weight(octaves);
}
///////////////////////////////////////
//
// Accumulated octave noise clamped within the range [0, 1]
//
[[nodiscard]]
value_type accumulatedOctaveNoise1D_0_1(value_type x, std::int32_t octaves) const noexcept
{
return std::clamp<value_type>(accumulatedOctaveNoise1D(x, octaves)
* value_type(0.5) + value_type(0.5), 0, 1);
}
[[nodiscard]]
value_type accumulatedOctaveNoise2D_0_1(value_type x, value_type y, std::int32_t octaves) const noexcept
{
return std::clamp<value_type>(accumulatedOctaveNoise2D(x, y, octaves)
* value_type(0.5) + value_type(0.5), 0, 1);
}
[[nodiscard]]
value_type accumulatedOctaveNoise3D_0_1(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept
{
return std::clamp<value_type>(accumulatedOctaveNoise3D(x, y, z, octaves)
* value_type(0.5) + value_type(0.5), 0, 1);
}
///////////////////////////////////////
//
// Normalized octave noise [0, 1]
//
[[nodiscard]]
value_type normalizedOctaveNoise1D_0_1(value_type x, std::int32_t octaves) const noexcept
{
return normalizedOctaveNoise1D(x, octaves)
* value_type(0.5) + value_type(0.5);
}
[[nodiscard]]
value_type normalizedOctaveNoise2D_0_1(value_type x, value_type y, std::int32_t octaves) const noexcept
{
return normalizedOctaveNoise2D(x, y, octaves)
* value_type(0.5) + value_type(0.5);
}
[[nodiscard]]
value_type normalizedOctaveNoise3D_0_1(value_type x, value_type y, value_type z, std::int32_t octaves) const noexcept
{
return normalizedOctaveNoise3D(x, y, z, octaves)
* value_type(0.5) + value_type(0.5);
}
///////////////////////////////////////
//
// Serialization
//
void serialize(std::array<std::uint8_t, 256>& s) const noexcept
{
for (std::size_t i = 0; i < 256; ++i)
{
s[i] = p[i];
}
}
void deserialize(const std::array<std::uint8_t, 256>& s) noexcept
{
for (std::size_t i = 0; i < 256; ++i)
{
p[256 + i] = p[i] = s[i];
}
}
///////////////////////////////////////
//
// Legacy interface
//
[[deprecated("use noise1D() instead")]]
double noise(double x) const;
[[deprecated("use noise2D() instead")]]
double noise(double x, double y) const;
[[deprecated("use noise3D() instead")]]
double noise(double x, double y, double z) const;
[[deprecated("use noise1D_0_1() instead")]]
double noise0_1(double x) const;
[[deprecated("use noise2D_0_1() instead")]]
double noise0_1(double x, double y) const;
[[deprecated("use noise3D_0_1() instead")]]
double noise0_1(double x, double y, double z) const;
[[deprecated("use accumulatedOctaveNoise1D() instead")]]
double octaveNoise(double x, std::int32_t octaves) const;
[[deprecated("use accumulatedOctaveNoise2D() instead")]]
double octaveNoise(double x, double y, std::int32_t octaves) const;
[[deprecated("use accumulatedOctaveNoise3D() instead")]]
double octaveNoise(double x, double y, double z, std::int32_t octaves) const;
[[deprecated("use accumulatedOctaveNoise1D_0_1() instead")]]
double octaveNoise0_1(double x, std::int32_t octaves) const;
[[deprecated("use accumulatedOctaveNoise2D_0_1() instead")]]
double octaveNoise0_1(double x, double y, std::int32_t octaves) const;
[[deprecated("use accumulatedOctaveNoise3D_0_1() instead")]]
double octaveNoise0_1(double x, double y, double z, std::int32_t octaves) const;
};
using PerlinNoise = BasicPerlinNoise<double>;
}

10
src/tiles/dirt.cpp Normal file
View file

@ -0,0 +1,10 @@
#include "tiles/dirt.h"
void Dirt::render(Render r, Vector2<int>pos, Vector2<int>size) {
r.fill_rectangle_sz(
pos * (TILE_SIZE + 1),
size * TILE_SIZE,
{100, 50, 10}
);
}

18
src/tiles/dirt.h Normal file
View file

@ -0,0 +1,18 @@
#include "tiles/tile.h"
class Dirt : public Tile {
public:
Dirt() : Tile(1) {}
Dirt(const Dirt &other) = default;
Dirt &operator=(const Dirt &other) = delete;
virtual ~Dirt() = default;
virtual Dirt *clone() { return new Dirt(*this); }
void render(Render r, Vector2<int>pos, Vector2<int>size) override;
private:
};

10
src/tiles/grass.cpp Normal file
View file

@ -0,0 +1,10 @@
#include "tiles/grass.h"
void Grass::render(Render r, Vector2<int>pos, Vector2<int>size) {
r.fill_rectangle_sz(
pos * (TILE_SIZE + 1),
size * TILE_SIZE,
{7, 176, 52}
);
}

18
src/tiles/grass.h Normal file
View file

@ -0,0 +1,18 @@
#include "tiles/tile.h"
class Grass : public Tile {
public:
Grass() : Tile(2) {}
Grass(const Grass &other) = default;
Grass &operator=(const Grass &other) = delete;
virtual ~Grass() = default;
virtual Grass *clone() { return new Grass(*this); }
void render(Render r, Vector2<int>pos, Vector2<int>size) override;
private:
};

10
src/tiles/stone.cpp Normal file
View file

@ -0,0 +1,10 @@
#include "tiles/stone.h"
void Stone::render(Render r, Vector2<int>pos, Vector2<int>size) {
r.fill_rectangle_sz(
pos * (TILE_SIZE + 1),
size * TILE_SIZE,
{42, 42, 42}
);
}

18
src/tiles/stone.h Normal file
View file

@ -0,0 +1,18 @@
#include "tiles/tile.h"
class Stone : public Tile {
public:
Stone() : Tile(3) {}
Stone(const Stone &other) = default;
Stone &operator=(const Stone &other) = delete;
virtual ~Stone() = default;
virtual Stone *clone() { return new Stone(*this); }
void render(Render r, Vector2<int>pos, Vector2<int>size) override;
private:
};

23
src/tiles/tile.cpp Normal file
View file

@ -0,0 +1,23 @@
#include "tiles/tile.h"
void Tile::render(Render r, Vector2<int>pos, Vector2<int>size) {
r.rectangle_sz(
pos * (TILE_SIZE + 1),
size * TILE_SIZE,
m_color
);
}
std::ostream &operator<<(std::ostream &os, const Tile &tile) {
os.write(reinterpret_cast<const char *>(&tile.m_id), sizeof(tile.m_id));
os.write(reinterpret_cast<const char *>(&tile.m_color), sizeof(tile.m_color));
return os;
}
std::istream &operator>>(std::istream &is, Tile &tile) {
is.read(reinterpret_cast<char *>(&tile.m_color), sizeof(tile.m_color));
return is;
}

34
src/tiles/tile.h Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include <iostream>
#include "util/render.h"
#include "util/vector2.h"
#define TILE_SIZE 16
class Tile {
public:
Tile() : Tile(-1) {}
Tile(int id) : m_id(id) {}
Tile(const Tile &other) = default;
Tile &operator=(const Tile &other) = delete;
virtual ~Tile() = default;
virtual Tile *clone() { return new Tile(*this); }
// Get the tile's ID
int id() { return m_id; }
// void set_id(int id) { m_id = id; }
virtual void render(Render r, Vector2<int>pos, Vector2<int>size);
friend std::ostream &operator<<(std::ostream &os, const Tile &tile);
friend std::istream &operator>>(std::istream &is, Tile &tile);
private:
int m_id;
Color m_color = Color::from_hsv(rand() % 255, 255, 255);
};

48
src/util/color.h Normal file
View file

@ -0,0 +1,48 @@
#pragma once
class Color {
public:
Color() = default;
Color(int r, int g, int b) : m_r(r), m_g(g), m_b(b) {}
int r() { return m_r; }
int g() { return m_g; }
int b() { return m_b; }
void set_r(int r) { m_r = r; }
void set_g(int g) { m_g = g; }
void set_b(int b) { m_b = b; }
static Color from_hsv(int h, int s, int v) {
if(s == 0) {
return {v, v, v};
}
int region = h / 43;
int remainder = (h - region * 43) * 6;
int p = (v * (255 - s)) >> 8;
int q = (v * (255 - ((s * remainder) >> 8))) >> 8;
int t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
switch(region) {
case 0:
return {v, t, p};
case 1:
return {q, v, p};
case 2:
return {p, v, t};
case 3:
return {p, q, v};
case 4:
return {t, p, v};
default:
return {v, p ,q};
}
}
private:
int m_r;
int m_g;
int m_b;
};

22
src/util/render.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "util/render.h"
void Render::rectangle(Vector2<int> start, Vector2<int> end, Color color) {
auto origin = start + m_camera_pos;
m_pge->DrawRect(origin.x(), origin.y(), end.x() - start.x(), end.y() - start.y(), olc::Pixel(color.r(), color.g(), color.b()));
}
void Render::rectangle_sz(Vector2<int> start, Vector2<int> size, Color color) {
auto origin = start + m_camera_pos;
m_pge->DrawRect(origin.x(), origin.y(), size.x(), size.y(), olc::Pixel(color.r(), color.g(), color.b()));
}
void Render::fill_rectangle(Vector2<int> start, Vector2<int> end, Color color) {
auto origin = start + m_camera_pos;
m_pge->FillRect(origin.x(), origin.y(), end.x() - start.x() + 1, end.y() - start.y() + 1, olc::Pixel(color.r(), color.g(), color.b()));
}
void Render::fill_rectangle_sz(Vector2<int> start, Vector2<int> size, Color color) {
auto origin = start + m_camera_pos;
m_pge->FillRect(origin.x(), origin.y(), size.x() + 1, size.y() + 1, olc::Pixel(color.r(), color.g(), color.b()));
}

24
src/util/render.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "olcPixelGameEngine.h"
#include "util/color.h"
#include "util/vector2.h"
class Render {
public:
Render(olc::PixelGameEngine *pge) : m_pge(pge) {}
void rectangle(Vector2<int> start, Vector2<int> end, Color color = {0, 0, 0});
void rectangle_sz(Vector2<int> start, Vector2<int> size, Color color = {0, 0, 0});
void fill_rectangle(Vector2<int> start, Vector2<int> end, Color color = {0, 0, 0});
void fill_rectangle_sz(Vector2<int> start, Vector2<int> size, Color color = {0, 0, 0});
void set_camera_pos(Vector2<int> camera_pos) { m_camera_pos = camera_pos; }
Vector2<int> camera_pos() { return m_camera_pos; }
private:
olc::PixelGameEngine *m_pge;
Vector2<int> m_camera_pos;
};

57
src/util/vector2.h Normal file
View file

@ -0,0 +1,57 @@
#pragma once
#include <ostream>
template <typename T>
class Vector2 {
public:
Vector2() = default;
Vector2(T x, T y) : m_x(x), m_y(y) {}
T x() { return m_x; }
T y() { return m_y; }
void set_x(T x) { m_x = x; }
void set_y(T y) { m_y = y; }
void set(T x, T y) { m_x = x; m_y = y; }
Vector2<T> operator-() const { return Vector2<T>(-m_x, -m_y); }
Vector2<T> &operator=(const Vector2<T> &other) { m_x = other.m_x; m_y = other.m_y; return *this; }
Vector2<T> operator+(const Vector2<T> &other) const { return Vector2(m_x + other.m_x, m_y + other.m_y); }
Vector2<T> &operator+=(const Vector2<T> &other) { m_x += other.m_x; m_y += other.m_y; return *this; }
Vector2<T> operator-(const Vector2<T> &other) const { return Vector2(m_x - other.m_x, m_y - other.m_y); }
Vector2<T> &operator-=(const Vector2<T> &other) { m_x -= other.m_x; m_y -= other.m_y; return *this; }
Vector2<T> operator*(const Vector2<T> &other) const { return Vector2(m_x * other.m_x, m_y * other.m_y); }
Vector2<T> &operator*=(const Vector2<T> &other) { m_x *= other.m_x; m_y *= other.m_y; return *this; }
Vector2<T> operator*(const T &s) const { return Vector2(m_x * s, m_y * s); }
Vector2<T> &operator*=(const T &s) { m_x *= s; m_y *= s; return *this; }
Vector2<T> operator/(const Vector2<T> &other) const { return Vector2(m_x / other.m_x, m_y / other.m_y); }
Vector2<T> &operator/=(const Vector2<T> &other) { m_x /= other.m_x; m_y /= other.m_y; return *this; }
Vector2<T> operator/(const T &s) const { return Vector2(m_x / s, m_y / s); }
Vector2<T> &operator/=(const T &s) { m_x /= s; m_y /= s; return *this; }
bool operator==(const Vector2<T> &other) const { return m_x == other.m_x && m_y == other.m_y; }
bool operator!=(const Vector2<T> &other) const { return m_x != other.m_x || m_y != other.m_y; }
bool operator<(const Vector2<T> &other) const { return m_x < other.m_x || (m_x == other.m_x && m_y < other.m_y); }
bool operator>(const Vector2<T> &other) const { return m_x > other.m_x || (m_x == other.m_x && m_y > other.m_y); }
bool operator<=(const Vector2<T> &other) const { return m_x <= other.m_x || (m_x == other.m_x && m_y <= other.m_y); }
bool operator>=(const Vector2<T> &other) const { return m_x >= other.m_x || (m_x == other.m_x && m_y >= other.m_y); }
friend std::ostream &operator<<(std::ostream &os, const Vector2<T> &vec) {
os << "Vector2(" << vec.m_x << ", " << vec.m_y << ")";
return os;
}
private:
T m_x = 0;
T m_y = 0;
};