summaryrefslogtreecommitdiff
path: root/src/common.hpp
blob: 06e9d9f1787143fa99077262e3292e8ed6a2b3e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <iostream>
#include <cstdint>
#include <cmath>
#include <cassert>
#include <map>
#include <list>
#include <unordered_set>
#include <SFML/Graphics.hpp>

namespace procgen {
	class prng_t {
		uint32_t state = 0;

	public:
		void seed(uint32_t seed);
		uint32_t next(void);
		float next_float(void);
		void unit_vec(float out[2]);

	};

	class perlin_noise_t {
		size_t size;
		float (*table)[2] = nullptr;

		float table_dot(size_t nx, size_t ny, float dx, float dy);

	public:
		~perlin_noise_t();

		void generate(prng_t *prng, size_t size);
		float get(float x, float y, float scale);
	};
}

namespace world {
	#define SECTOR_SIZE 8

	class tile_t {
	public:
		char type;
	};

	class sector_index_t {
	public:
		int64_t x, y;

		sector_index_t ();
		sector_index_t (int64_t x_, int64_t y_);
		sector_index_t (float x_, float y_);
		bool operator<(sector_index_t B) const;
	};

	class entity_t;

	class sector_t {
	public:
		sector_index_t index;
		sf::FloatRect bounds;
		std::unordered_set<entity_t*> ents;

		bool empty = true;
		tile_t tiles[SECTOR_SIZE * SECTOR_SIZE];
	};

	class world_t {
		procgen::prng_t prng;
		procgen::perlin_noise_t perlin;
		std::map<sector_index_t, sector_t> sectors;

		void generate_tile(ssize_t lx, ssize_t ly, tile_t *tile);
		void generate(sector_t *sector, sector_index_t index);

	public:
		world_t(void);
		sector_t *get_sector(sector_index_t index);
		tile_t *get_tile(ssize_t x, ssize_t y);

		// FIXME: iterators instead of returning std::lists
		std::list<sector_t*> get_sectors(sf::FloatRect rect);
		std::list<entity_t*> get_entities(sf::FloatRect rect);

		void render(sf::RenderWindow *window);

		void debug_point(sf::Vector2f point);
	};

	class entity_t {
		world_t *parent_world;
		std::vector<sector_t*> parents;

		void link_to_sector(sector_t *sector);

	protected:
		friend world_t;
		size_t cookie = 0;

	public:
		sf::FloatRect bounds;

		void link(world_t *world);
		void unlink();

		virtual void render(sf::RenderWindow *window) = 0;
	};
}

namespace game {
	class state_t {
	public:
		world::world_t world;

		void start(void);
		void tick(void);
		void render(sf::RenderWindow *window_);
	};

	class human_t : public world::entity_t {
	public:
		void render(sf::RenderWindow *window);
	};
}

namespace interface {
	class state_t {
		sf::RenderWindow *window;
		game::state_t *game;

		struct {
			sf::Vector2f center;
			int target_zoom = 3;
			float zoom = 3.0f;
			bool dragging = false;
			sf::Vector2f drag_ref;
		} camera;

	public:
		state_t(sf::RenderWindow *window_, game::state_t *game);
		void tick(void);
		void render(void);
	};
}

// Divide and round to minus infinity.
template <typename T>
T divide_rmi(T x, T y, T *rem)
{
	T rv;

	if (x >= 0) {
		*rem = x % y;
		return x / y;
	}

	rv = (x + 1) / y - 1;
	*rem = x - rv * y;
	return rv;
}

// Linear interpolation.
template <typename T>
T lerp(T a, T b, T x)
{
	return a * (1 - x) + b * x;
}

// Bilinear interpolation.
template <typename T>
T bilerp(T a, T b, T c, T d, T x, T y)
{
	T ab, cd;

	ab = lerp(a, b, x);
	cd = lerp(c, d, x);
	return lerp(ab, cd, y);
}