some meshgen and map rendering updates
[voxelands-alt.git] / src / map / map.c
blob912f64ec5b828f8ba9e92f402f8add0b6b7a5a8c
1 /************************************************************************
2 * map.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #include "map.h"
22 #include "list.h"
24 #include "content_block.h"
26 static struct {
27 mapoct_t map;
28 chunk_t *chunks;
29 mutex_t *mut;
30 chunk_t *last;
31 } map_data = {
33 65536,
34 {0,0,0},
35 NULL,
37 {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL},
38 {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
40 NULL,
41 NULL,
42 NULL
45 static void mapoct_delete(mapoct_t *m)
47 if (m->size == 65536)
48 return;
51 static int mapoct_index(mapoct_t *m, pos_t *p)
53 int i = 0;
55 if (p->x < m->pos.x) {
56 if (p->y < m->pos.y) {
57 if (p->z < m->pos.z) {
58 i = MAPOCT_MINUS_XYZ;
59 }else{
60 i = MAPOCT_MINUS_XY_PLUS_Z;
62 }else if (p->z < m->pos.z) {
63 i = MAPOCT_MINUS_XZ_PLUS_Y;
64 }else{
65 i = MAPOCT_MINUS_X_PLUS_YZ;
67 }else if (p->y < m->pos.y) {
68 if (p->z < m->pos.z) {
69 i = MAPOCT_MINUS_YZ_PLUS_X;
70 }else{
71 i = MAPOCT_MINUS_Y_PLUS_XZ;
73 }else if (p->z < m->pos.z) {
74 i = MAPOCT_MINUS_Z_PLUS_XY;
75 }else{
76 i = MAPOCT_PLUS_XYZ;
79 return i;
82 static mapoct_t *mapoct_walk(mapoct_t *m, pos_t *p, uint8_t create);
83 static mapoct_t *mapoct_walk(mapoct_t *m, pos_t *p, uint8_t create)
85 int i;
87 if (m->size == (CHUNKSIZE*2))
88 return m;
90 i = mapoct_index(m,p);
92 if (!m->children[i]) {
93 mapoct_t *mm;
94 int k;
95 if (!create)
96 return NULL;
98 mm = malloc(sizeof(mapoct_t));
99 if (!mm)
100 return NULL;
102 mm->parent = m;
103 mm->parent_index = i;
104 mm->size = m->size/2;
106 k = mm->size/2;
108 if (p->x < m->pos.x) {
109 mm->pos.x = m->pos.x-k;
110 }else{
111 mm->pos.x = m->pos.x+k;
113 if (p->y < m->pos.y) {
114 mm->pos.y = m->pos.y-k;
115 }else{
116 mm->pos.y = m->pos.y+k;
118 if (p->z < m->pos.z) {
119 mm->pos.z = m->pos.z-k;
120 }else{
121 mm->pos.z = m->pos.z+k;
124 for (k=0; k<8; k++) {
125 mm->children[k] = NULL;
126 mm->chunks[k] = NULL;
129 m->children[i] = mm;
132 if (m->children[i]->size == (CHUNKSIZE*2))
133 return m->children[i];
135 return mapoct_walk(m->children[i],p,create);
138 static chunk_t *mapoct_walk_chunk(mapoct_t *m, pos_t *p)
140 int i = 0;
142 m = mapoct_walk(m,p,0);
143 if (!m)
144 return NULL;
145 if (m->size != (CHUNKSIZE*2))
146 return NULL;
148 i = mapoct_index(m,p);
150 return m->chunks[i];
153 /* intialise the map data */
154 int map_init()
156 if (!map_data.mut)
157 map_data.mut = mutex_create();
159 return mapgen_init();
162 /* delete and free the current map */
163 void map_clear()
165 while (map_data.chunks) {
166 map_delete_chunk(map_data.chunks);
170 /* deinitialise the map */
171 void map_exit()
173 mapgen_exit();
174 map_clear();
175 map_data.last = NULL;
178 /* add a new chunk to the map */
179 void map_add_chunk(chunk_t *ch)
181 int i;
182 mapoct_t *m;
184 mutex_lock(map_data.mut);
186 m = mapoct_walk(&map_data.map,&ch->pos,1);
188 if (!m)
189 return;
191 i = mapoct_index(m,&ch->pos);
193 m->chunks[i] = ch;
194 ch->mapoct = m;
195 ch->mapoct_index = i;
197 map_data.chunks = list_append(&map_data.chunks,ch);
199 mutex_unlock(map_data.mut);
201 map_trigger(MAP_TRIGGER_LOADED,ch,&ch->pos);
204 /* delete a chunk from the map */
205 void map_delete_chunk(chunk_t *ch)
207 int i;
208 mapoct_t *m;
210 mutex_lock(map_data.mut);
212 map_data.chunks = list_remove(&map_data.chunks,ch);
214 m = ch->mapoct;
215 m->chunks[ch->mapoct_index] = NULL;
217 map_trigger(MAP_TRIGGER_UNLOAD,ch,&ch->pos);
219 free(ch);
221 for (i=0; i<8; i++) {
222 if (m->chunks[i]) {
223 mutex_unlock(map_data.mut);
224 return;
228 mapoct_delete(m);
230 mutex_unlock(map_data.mut);
233 /* get the map chunk containing a position */
234 chunk_t *map_get_chunk_containing(pos_t *p)
236 chunk_t *ch;
238 if (map_data.last) {
239 ch = map_data.last;
240 if (
241 p->x >= ch->pos.x && p->x < ch->pos.x+16
242 && p->y >= ch->pos.y && p->y < ch->pos.y+16
243 && p->z >= ch->pos.z && p->z < ch->pos.z+16
245 return ch;
248 mutex_lock(map_data.mut);
250 ch = mapoct_walk_chunk(&map_data.map,p);
252 mutex_unlock(map_data.mut);
254 if (ch) {
255 map_data.last = ch;
256 return ch;
259 /* TODO: load from disk, possibly asyncronously */
261 mapgen_request(p);
263 return NULL;
266 /* get the map block at a position */
267 block_t *map_get_block(pos_t *p)
269 chunk_t *ch;
270 int x;
271 int y;
272 int z;
274 ch = map_get_chunk_containing(p);
275 if (!ch)
276 return NULL;
278 x = p->x%CHUNKSIZE;
279 y = p->y%CHUNKSIZE;
280 z = p->z%CHUNKSIZE;
282 if (x<0)
283 x += CHUNKSIZE;
284 if (y<0)
285 y += CHUNKSIZE;
286 if (z<0)
287 z += CHUNKSIZE;
289 return &ch->blocks[x][y][z];
292 /* add/update a block */
293 void map_set_block(pos_t *p, block_t *b)
295 chunk_t *ch;
296 block_t *cb;
297 int x;
298 int y;
299 int z;
301 ch = map_get_chunk_containing(p);
302 if (!ch)
303 return;
305 x = p->x%CHUNKSIZE;
306 y = p->y%CHUNKSIZE;
307 z = p->z%CHUNKSIZE;
309 if (x<0)
310 x += CHUNKSIZE;
311 if (y<0)
312 y += CHUNKSIZE;
313 if (z<0)
314 z += CHUNKSIZE;
316 cb = &ch->blocks[x][y][z];
318 if (b) {
319 cb->content = b->content;
320 cb->param1 = b->param1;
321 cb->param2 = b->param2;
322 cb->param3 = b->param3;
323 cb->envticks = b->envticks;
324 /* NULL is air */
325 }else{
326 cb->content = CONTENT_AIR;
327 cb->param1 = 0;
328 cb->param2 = 0;
329 cb->param3 = 0;
330 cb->envticks = 0;
333 map_trigger(MAP_TRIGGER_UPDATE,ch,&ch->pos);