├── .editorconfig ├── .github └── workflows │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── docs └── coordsys.gif ├── libvxl.c └── libvxl.h /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = tab 3 | indent_size = 4 -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - '*' 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, macos-latest, windows-latest] 19 | runs-on: ${{ matrix.os }} 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v3 23 | - name: Build 24 | run: | 25 | cmake . -DCMAKE_BUILD_TYPE=Release 26 | cmake --build . 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(vxl C) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | 6 | if (NOT MSVC) 7 | add_compile_options(-Wall -Wextra -pedantic -std=c99 -Ofast) 8 | endif() 9 | 10 | add_library(vxl STATIC libvxl.c) 11 | 12 | target_include_directories(vxl PUBLIC .) 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2022 xtreme8000/ByteBit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -Wextra -pedantic -std=c99 -Ofast 2 | 3 | all: 4 | ${CC} -c libvxl.c -fPIC ${CFLAGS} -o libvxl.o 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## libvxl 2 | 3 | * read n' write Ace of Spades map files **easily** and **fast** 4 | * compressed internal format derived from .vxl 5 | * supports enhanced features for special cases: 6 | * floating block detection 7 | * get top layer block, useful for map overviews 8 | 9 | All functions use voxlap's coordinate system: 10 | 11 | ![coordsys](docs/coordsys.gif) 12 | 13 | ## Example 14 | 15 | ```C 16 | //create map from v pointer 17 | struct libvxl_map m; 18 | libvxl_create(&m,512,512,64,v); 19 | 20 | //get color at position (x,y,z) 21 | int col = libvxl_map_get(&m,x,y,z); 22 | 23 | //check if block is solid at (x,y,z) 24 | int solid = libvxl_map_issolid(&m,x,y,z); 25 | 26 | //free map after use 27 | libvxl_free(&m); 28 | ``` 29 | 30 | ## API functions 31 | 32 | ```C 33 | //Load a map from memory or create an empty one 34 | void libvxl_create(struct libvxl_map* map, int w, int h, int d, const void* data); 35 | //Write a map to disk, uses libvxl_write() internally 36 | void libvxl_writefile(struct libvxl_map* map, char* name); 37 | //Compress the map back to vxl format and save it in out, the total byte size will be written to size 38 | void libvxl_write(struct libvxl_map* map, void* out, int* size); 39 | //Tells if a block is solid at location [x,y,z] 40 | int libvxl_map_issolid(struct libvxl_map* map, int x, int y, int z); 41 | //Tells if a block is visible on the surface, meaning it is exposed to air 42 | int libvxl_map_onsurface(struct libvxl_map* map, int x, int y, int z); 43 | //Read block color 44 | int libvxl_map_get(struct libvxl_map* map, int x, int y, int z); 45 | //Read color of topmost block (as seen from above at Z=0) 46 | void libvxl_map_gettop(struct libvxl_map* map, int x, int y, int* result); 47 | //Set block at location [x,y,z] to a new color 48 | void libvxl_map_set(struct libvxl_map* map, int x, int y, int z, int color); 49 | //Set location [x,y,z] to air, will destroy any block at this position 50 | void libvxl_map_setair(struct libvxl_map* map, int x, int y, int z); 51 | //Free a map from memory 52 | void libvxl_free(struct libvxl_map* map); 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/coordsys.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xtreme8000/libvxl/2d482be6e738f0befdbb4f63d740c51eef9970a3/docs/coordsys.gif -------------------------------------------------------------------------------- /libvxl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "libvxl.h" 8 | 9 | #define LIBVXL_SPAN(base, off) ((struct libvxl_span*)((uint8_t*)(base) + (off))) 10 | 11 | static struct libvxl_chunk* chunk_fposition(struct libvxl_map* map, size_t x, 12 | size_t y) { 13 | libvxl_assert(map && x < map->width && y < map->height, 14 | "invalid input parameters"); 15 | 16 | size_t chunk_cnt = (map->width + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 17 | size_t chunk_x = x / LIBVXL_CHUNK_SIZE; 18 | size_t chunk_y = y / LIBVXL_CHUNK_SIZE; 19 | return map->chunks + chunk_x + chunk_y * chunk_cnt; 20 | } 21 | 22 | static bool libvxl_geometry_get(struct libvxl_map* map, size_t x, size_t y, 23 | size_t z) { 24 | libvxl_assert(map && x < map->width && y < map->height && z < map->depth, 25 | "invalid input parameters"); 26 | 27 | size_t offset = z + (x + y * map->width) * map->depth; 28 | return (map->geometry[offset / (sizeof(size_t) * 8)] 29 | & ((size_t)1 << (offset % (sizeof(size_t) * 8)))) 30 | > 0; 31 | } 32 | 33 | static void libvxl_geometry_set(struct libvxl_map* map, size_t x, size_t y, 34 | size_t z, size_t state) { 35 | libvxl_assert(map && x < map->width && y < map->height && z < map->depth, 36 | "invalid input parameters"); 37 | 38 | size_t offset = z + (x + y * map->width) * map->depth; 39 | 40 | size_t* val = map->geometry + offset / (sizeof(size_t) * 8); 41 | size_t bit = offset % (sizeof(size_t) * 8); 42 | 43 | *val = (*val & ~((size_t)1 << bit)) | (state << bit); 44 | } 45 | 46 | static int cmp(const void* a, const void* b) { 47 | struct libvxl_block* aa = (struct libvxl_block*)a; 48 | struct libvxl_block* bb = (struct libvxl_block*)b; 49 | 50 | return (int)(aa->position - bb->position); 51 | } 52 | 53 | static void libvxl_chunk_put(struct libvxl_chunk* chunk, uint32_t pos, 54 | uint32_t color) { 55 | libvxl_assert(chunk, "chunk pointer is null"); 56 | 57 | if(chunk->index == chunk->length) { // needs to grow 58 | chunk->length *= LIBVXL_CHUNK_GROWTH; 59 | chunk->blocks = libvxl_mem_realloc( 60 | chunk->blocks, chunk->length * sizeof(struct libvxl_block)); 61 | } 62 | 63 | memcpy(chunk->blocks + (chunk->index++), 64 | &(struct libvxl_block) { 65 | .position = pos, 66 | .color = color, 67 | }, 68 | sizeof(struct libvxl_block)); 69 | } 70 | 71 | static struct libvxl_block* 72 | libvxl_chunk_gequal_block(struct libvxl_chunk* chunk, uint32_t pos) { 73 | libvxl_assert(chunk, "chunk pointer is null"); 74 | 75 | size_t start = 0; 76 | size_t end = chunk->index; 77 | while(end > start) { 78 | size_t mid = (start + end) / 2; 79 | if(pos > chunk->blocks[mid].position) { 80 | start = mid + 1; 81 | } else if(pos < chunk->blocks[mid].position) { 82 | end = mid; 83 | } else { 84 | return chunk->blocks + mid; 85 | } 86 | } 87 | 88 | return chunk->blocks + start; 89 | } 90 | 91 | static void libvxl_chunk_insert(struct libvxl_chunk* chunk, uint32_t pos, 92 | uint32_t color) { 93 | libvxl_assert(chunk, "chunk pointer is null"); 94 | 95 | // TODO: use libvxl_chunk_gequal_block 96 | 97 | size_t start = 0; 98 | size_t end = chunk->index; 99 | while(end > start) { 100 | size_t mid = (start + end) / 2; 101 | if(pos > chunk->blocks[mid].position) { 102 | start = mid + 1; 103 | } else if(pos < chunk->blocks[mid].position) { 104 | end = mid; 105 | } else { // diff=0, replace color 106 | chunk->blocks[mid].color = color; 107 | return; 108 | } 109 | } 110 | 111 | if(chunk->index == chunk->length) { // needs to grow 112 | chunk->length *= LIBVXL_CHUNK_GROWTH; 113 | chunk->blocks = libvxl_mem_realloc( 114 | chunk->blocks, chunk->length * sizeof(struct libvxl_block)); 115 | } 116 | 117 | memmove(chunk->blocks + start + 1, chunk->blocks + start, 118 | (chunk->index - start) * sizeof(struct libvxl_block)); 119 | chunk->blocks[start].position = pos; 120 | chunk->blocks[start].color = color; 121 | chunk->index++; 122 | } 123 | 124 | static size_t libvxl_span_length(struct libvxl_span* s) { 125 | libvxl_assert(s, "span pointer is null"); 126 | 127 | return s->length > 0 ? s->length * 4 : 128 | (s->color_end + 2 - s->color_start) * 4; 129 | } 130 | 131 | void libvxl_free(struct libvxl_map* map) { 132 | if(!map) 133 | return; 134 | size_t sx = (map->width + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 135 | size_t sy = (map->height + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 136 | for(size_t k = 0; k < sx * sy; k++) 137 | libvxl_mem_free(map->chunks[k].blocks); 138 | libvxl_mem_free(map->chunks); 139 | libvxl_mem_free(map->geometry); 140 | } 141 | 142 | bool libvxl_size(size_t* size, size_t* depth, const void* data, size_t len) { 143 | if(!data || !size || !depth || len == 0) 144 | return false; 145 | size_t offset = 0; 146 | size_t columns = 0; 147 | *depth = 0; 148 | while(offset + sizeof(struct libvxl_span) - 1 < len) { 149 | struct libvxl_span* desc = LIBVXL_SPAN(data, offset); 150 | if(desc->color_end + 1 > (int)*depth) 151 | *depth = desc->color_end + 1; 152 | if(!desc->length) 153 | columns++; 154 | offset += libvxl_span_length(desc); 155 | } 156 | *depth = (size_t)(1U << (uint32_t)ceil(log2f(*depth))); 157 | *size = sqrt(columns); 158 | return true; 159 | } 160 | 161 | bool libvxl_create(struct libvxl_map* map, size_t w, size_t h, size_t d, 162 | const void* data, size_t len) { 163 | if(!map) 164 | return false; 165 | map->streamed = 0; 166 | map->width = w; 167 | map->height = h; 168 | map->depth = d; 169 | size_t sx = (w + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 170 | size_t sy = (h + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 171 | map->chunks = libvxl_mem_malloc(sx * sy * sizeof(struct libvxl_chunk)); 172 | for(size_t y = 0; y < sy; y++) { 173 | for(size_t x = 0; x < sx; x++) { 174 | map->chunks[x + y * sx].length = LIBVXL_CHUNK_SIZE 175 | * LIBVXL_CHUNK_SIZE * 2; // allows for two fully filled layers 176 | map->chunks[x + y * sx].index = 0; 177 | map->chunks[x + y * sx].blocks = libvxl_mem_malloc( 178 | map->chunks[x + y * sx].length * sizeof(struct libvxl_block)); 179 | } 180 | } 181 | 182 | size_t sg = (w * h * d + (sizeof(size_t) * 8 - 1)) / (sizeof(size_t) * 8) 183 | * sizeof(size_t); 184 | map->geometry = libvxl_mem_malloc(sg); 185 | if(data) { 186 | memset(map->geometry, 0xFF, sg); 187 | } else { 188 | memset(map->geometry, 0x00, sg); 189 | for(size_t y = 0; y < h; y++) 190 | for(size_t x = 0; x < w; x++) 191 | libvxl_map_set(map, x, y, d - 1, DEFAULT_COLOR(x, y, d - 1)); 192 | return true; 193 | } 194 | 195 | size_t offset = 0; 196 | for(size_t y = 0; y < map->height; y++) { 197 | for(size_t x = 0; x < map->width; x++) { 198 | struct libvxl_chunk* chunk = chunk_fposition(map, x, y); 199 | 200 | while(1) { 201 | if(offset + sizeof(struct libvxl_span) - 1 >= len) 202 | return false; 203 | struct libvxl_span* desc = LIBVXL_SPAN(data, offset); 204 | if(offset + libvxl_span_length(desc) - 1 >= len) 205 | return false; 206 | uint32_t* color_data = (uint32_t*)LIBVXL_SPAN( 207 | data, offset + sizeof(struct libvxl_span)); 208 | 209 | for(size_t z = desc->air_start; z < desc->color_start; z++) 210 | libvxl_geometry_set(map, x, y, z, 0); 211 | 212 | for(size_t z = desc->color_start; z <= desc->color_end; 213 | z++) // top color run 214 | libvxl_chunk_put(chunk, pos_key(x, y, z), 215 | color_data[z - desc->color_start]); 216 | 217 | size_t top_len = desc->color_end - desc->color_start + 1; 218 | size_t bottom_len = desc->length - 1 - top_len; 219 | 220 | if(desc->length > 0) { 221 | if(offset + libvxl_span_length(desc) 222 | + sizeof(struct libvxl_span) - 1 223 | >= len) 224 | return false; 225 | struct libvxl_span* desc_next 226 | = LIBVXL_SPAN(data, offset + libvxl_span_length(desc)); 227 | for(size_t z = desc_next->air_start - bottom_len; 228 | z < desc_next->air_start; z++) // bottom color run 229 | libvxl_chunk_put( 230 | chunk, pos_key(x, y, z), 231 | color_data[z - (desc_next->air_start - bottom_len) 232 | + top_len]); 233 | offset += libvxl_span_length(desc); 234 | } else { 235 | offset += libvxl_span_length(desc); 236 | break; 237 | } 238 | } 239 | } 240 | } 241 | 242 | for(size_t z = 0; z < map->depth; z++) { 243 | for(size_t x = 0; x < map->width; x++) { 244 | bool A = libvxl_geometry_get(map, x, 0, z); 245 | bool B = libvxl_geometry_get(map, x, map->height - 1, z); 246 | 247 | struct libvxl_chunk* c1 = chunk_fposition(map, x, 0); 248 | struct libvxl_block* b1 = bsearch( 249 | &(struct libvxl_block) { 250 | .position = pos_key(x, 0, z), 251 | }, 252 | c1->blocks, c1->index, sizeof(struct libvxl_block), cmp); 253 | 254 | struct libvxl_chunk* c2 = chunk_fposition(map, x, map->height - 1); 255 | struct libvxl_block* b2 = bsearch( 256 | &(struct libvxl_block) { 257 | .position = pos_key(x, map->height - 1, z), 258 | }, 259 | c2->blocks, c2->index, sizeof(struct libvxl_block), cmp); 260 | 261 | if(A && !B && !b1) 262 | libvxl_chunk_insert(c1, pos_key(x, 0, z), 263 | DEFAULT_COLOR(x, 0, z)); 264 | 265 | if(!A && B && !b2) 266 | libvxl_chunk_insert(c2, pos_key(x, map->height - 1, z), 267 | DEFAULT_COLOR(x, map->height - 1, z)); 268 | } 269 | 270 | for(size_t y = 0; y < map->height; y++) { 271 | bool A = libvxl_geometry_get(map, 0, y, z); 272 | bool B = libvxl_geometry_get(map, map->width - 1, y, z); 273 | 274 | struct libvxl_chunk* c1 = chunk_fposition(map, 0, y); 275 | struct libvxl_block* b1 = bsearch( 276 | &(struct libvxl_block) { 277 | .position = pos_key(0, y, z), 278 | }, 279 | c1->blocks, c1->index, sizeof(struct libvxl_block), cmp); 280 | 281 | struct libvxl_chunk* c2 = chunk_fposition(map, map->width - 1, y); 282 | struct libvxl_block* b2 = bsearch( 283 | &(struct libvxl_block) { 284 | .position = pos_key(map->width - 1, y, z), 285 | }, 286 | c2->blocks, c2->index, sizeof(struct libvxl_block), cmp); 287 | 288 | if(A && !B && !b1) 289 | libvxl_chunk_insert(c1, pos_key(0, y, z), 290 | DEFAULT_COLOR(0, y, z)); 291 | 292 | if(!A && B && !b2) 293 | libvxl_chunk_insert(c2, pos_key(map->width - 1, y, z), 294 | DEFAULT_COLOR(map->width - 1, y, z)); 295 | } 296 | } 297 | 298 | return true; 299 | } 300 | 301 | static size_t find_successive_surface(struct libvxl_chunk* chunk, 302 | size_t block_offset, int x, int y, 303 | size_t start, 304 | struct libvxl_block** current) { 305 | libvxl_assert(chunk && current, "chunk or block pointer is null"); 306 | 307 | *current = chunk->blocks + block_offset; 308 | struct libvxl_block* end_marker = chunk->blocks + chunk->index; 309 | 310 | if(*current < end_marker && (*current)->position == pos_key(x, y, start)) { 311 | while(1) { 312 | uint32_t next_z = key_getz((*current)->position) + 1; 313 | (*current)++; 314 | 315 | if(*current >= end_marker 316 | || (*current)->position != pos_key(x, y, next_z)) 317 | return next_z; 318 | } 319 | } else { 320 | return start; 321 | } 322 | } 323 | 324 | static void libvxl_column_encode(struct libvxl_map* map, size_t* chunk_offsets, 325 | int x, int y, void* out, size_t* offset) { 326 | libvxl_assert(map && chunk_offsets && out && offset, 327 | "invalid input parameters"); 328 | 329 | struct libvxl_chunk* chunk = chunk_fposition(map, x, y); 330 | 331 | bool first_run = true; 332 | size_t z 333 | = key_getz(chunk->blocks[chunk_offsets[chunk - map->chunks]].position); 334 | while(1) { 335 | size_t top_start = libvxl_geometry_get(map, x, y, z) ? 336 | z : 337 | key_getz( 338 | chunk->blocks[chunk_offsets[chunk - map->chunks]].position); 339 | 340 | struct libvxl_block* last_surface_block; 341 | size_t top_end 342 | = find_successive_surface(chunk, chunk_offsets[chunk - map->chunks], 343 | x, y, top_start, &last_surface_block); 344 | 345 | size_t bottom_start = map->depth; 346 | 347 | if(top_end == map->depth || !libvxl_geometry_get(map, x, y, top_end)) { 348 | bottom_start = top_end; 349 | } else if(last_surface_block < chunk->blocks + chunk->index 350 | && key_discardz(last_surface_block->position) 351 | == pos_key(x, y, 0)) { 352 | bottom_start = key_getz(last_surface_block->position); 353 | } 354 | 355 | struct libvxl_span* desc = LIBVXL_SPAN(out, *offset); 356 | desc->color_start = top_start; 357 | desc->color_end = top_end - 1; 358 | desc->air_start = first_run ? 0 : z; 359 | *offset += sizeof(struct libvxl_span); 360 | 361 | libvxl_assert(desc->air_start <= desc->color_start, 362 | "air_start is bigger than color_start"); 363 | libvxl_assert(desc->color_start <= desc->color_end + 1, 364 | "color_start is bigger than color_end + 1"); 365 | 366 | first_run = false; 367 | 368 | for(size_t k = top_start; k < top_end; k++) { 369 | *(uint32_t*)LIBVXL_SPAN(out, *offset) 370 | = (chunk->blocks[chunk_offsets[chunk - map->chunks]++].color 371 | & 0xFFFFFF) 372 | | 0x7F000000; 373 | *offset += sizeof(uint32_t); 374 | } 375 | 376 | if(bottom_start == map->depth) { 377 | /* this is the last span of this column, do not emit bottom colors, 378 | * set length to 0 */ 379 | desc->length = 0; 380 | break; 381 | } else { // bottom_start < map->depth 382 | struct libvxl_block* last_surface_block; 383 | size_t bottom_end = find_successive_surface( 384 | chunk, chunk_offsets[chunk - map->chunks], x, y, bottom_start, 385 | &last_surface_block); 386 | 387 | // there are more spans to follow, emit bottom colors 388 | if(bottom_end < map->depth) { 389 | desc->length 390 | = 1 + top_end - top_start + bottom_end - bottom_start; 391 | 392 | for(size_t k = bottom_start; k < bottom_end; k++) { 393 | *(uint32_t*)LIBVXL_SPAN(out, *offset) 394 | = (chunk->blocks[chunk_offsets[chunk - map->chunks]++] 395 | .color 396 | & 0xFFFFFF) 397 | | 0x7F000000; 398 | *offset += sizeof(uint32_t); 399 | } 400 | 401 | z = bottom_end; 402 | } else { // bottom_end == map->depth 403 | desc->length = 1 + top_end - top_start; 404 | z = bottom_start; 405 | } 406 | } 407 | } 408 | } 409 | 410 | void libvxl_stream(struct libvxl_stream* stream, struct libvxl_map* map, 411 | size_t chunk_size) { 412 | if(!stream || !map || chunk_size == 0) 413 | return; 414 | stream->map = map; 415 | map->streamed++; 416 | stream->chunk_size = chunk_size; 417 | stream->pos = pos_key(0, 0, 0); 418 | stream->buffer_offset = 0; 419 | stream->buffer = libvxl_mem_malloc(stream->chunk_size * 2); 420 | 421 | size_t sx = (map->width + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 422 | size_t sy = (map->height + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 423 | stream->chunk_offsets = libvxl_mem_malloc(sx * sy * sizeof(size_t)); 424 | memset(stream->chunk_offsets, 0, sx * sy * sizeof(size_t)); 425 | } 426 | 427 | void libvxl_stream_free(struct libvxl_stream* stream) { 428 | if(!stream) 429 | return; 430 | stream->map->streamed--; 431 | libvxl_mem_free(stream->buffer); 432 | libvxl_mem_free(stream->chunk_offsets); 433 | } 434 | 435 | #ifndef min 436 | #define min(a, b) ((a) < (b) ? (a) : (b)) 437 | #endif 438 | 439 | size_t libvxl_stream_read(struct libvxl_stream* stream, void* out) { 440 | if(!stream || !out || key_gety(stream->pos) >= stream->map->height) 441 | return 0; 442 | while(stream->buffer_offset < stream->chunk_size 443 | && key_gety(stream->pos) < stream->map->height) { 444 | libvxl_column_encode(stream->map, stream->chunk_offsets, 445 | key_getx(stream->pos), key_gety(stream->pos), 446 | stream->buffer, &stream->buffer_offset); 447 | if(key_getx(stream->pos) + 1 < stream->map->width) 448 | stream->pos 449 | = pos_key(key_getx(stream->pos) + 1, key_gety(stream->pos), 0); 450 | else 451 | stream->pos = pos_key(0, key_gety(stream->pos) + 1, 0); 452 | } 453 | size_t length = stream->buffer_offset; 454 | memcpy(out, stream->buffer, min(length, stream->chunk_size)); 455 | if(length < stream->chunk_size) { 456 | stream->buffer_offset = 0; 457 | } else { 458 | memmove(stream->buffer, (uint8_t*)stream->buffer + stream->chunk_size, 459 | length - stream->chunk_size); 460 | stream->buffer_offset -= stream->chunk_size; 461 | } 462 | return min(length, stream->chunk_size); 463 | } 464 | 465 | void libvxl_write(struct libvxl_map* map, void* out, size_t* size) { 466 | if(!map || !out) 467 | return; 468 | size_t sx = (map->width + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 469 | size_t sy = (map->height + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 470 | 471 | size_t* chunk_offsets = libvxl_mem_malloc(sx * sy * sizeof(size_t)); 472 | memset(chunk_offsets, 0, sx * sy * sizeof(size_t)); 473 | 474 | size_t offset = 0; 475 | for(uint32_t y = 0; y < map->height; y++) 476 | for(uint32_t x = 0; x < map->width; x++) 477 | libvxl_column_encode(map, chunk_offsets, x, y, out, &offset); 478 | 479 | if(size) 480 | *size = offset; 481 | 482 | libvxl_mem_free(chunk_offsets); 483 | } 484 | 485 | size_t libvxl_writefile(struct libvxl_map* map, char* name) { 486 | if(!map || !name) 487 | return 0; 488 | uint8_t buf[1024]; 489 | struct libvxl_stream s; 490 | libvxl_stream(&s, map, 1024); 491 | FILE* f = fopen(name, "wb"); 492 | size_t read, total = 0; 493 | while((read = libvxl_stream_read(&s, buf))) { 494 | fwrite(buf, 1, read, f); 495 | total += read; 496 | } 497 | fclose(f); 498 | libvxl_stream_free(&s); 499 | return total; 500 | } 501 | 502 | /*void libvxl_kv6_write(struct libvxl_map* map, char* name) { 503 | FILE* f = fopen(name, "wb"); 504 | 505 | struct libvxl_kv6 header; 506 | strcpy(header.magic, "Kvxl"); 507 | header.width = map->width; 508 | header.height = map->height; 509 | header.depth = map->depth; 510 | header.pivot[0] = map->width / 2.0F; 511 | header.pivot[1] = map->height / 2.0F; 512 | header.pivot[2] = map->depth / 2.0F; 513 | 514 | header.len = 0; 515 | 516 | int sx = (map->width + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 517 | int sy = (map->height + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE; 518 | for(int y = 0; y < sy; y++) 519 | for(int x = 0; x < sx; x++) 520 | header.len += map->chunks[x + y * sx].index; 521 | 522 | fwrite(&header, sizeof(header), 1, f); 523 | 524 | int xoffset[map->width]; 525 | short xyoffset[map->width * map->height]; 526 | memset(xoffset, 0, sizeof(xoffset)); 527 | memset(xyoffset, 0, sizeof(xyoffset)); 528 | 529 | size_t chunk_offsets[sx * sy]; 530 | memset(chunk_offsets, 0, sizeof(chunk_offsets)); 531 | 532 | for(size_t y = 0; y < map->height; y++) { 533 | for(size_t x = 0; x < map->width; x++) { 534 | struct libvxl_chunk* chunk = chunk_fposition(map, x, y); 535 | 536 | while(1) { 537 | struct libvxl_block* next 538 | = &chunk->blocks[chunk_offsets[chunk - map->chunks]]; 539 | if(key_getx(next->position) != x) 540 | break; 541 | 542 | chunk_offsets[chunk - map->chunks]++; 543 | 544 | struct libvxl_kv6_block blk; 545 | blk.color = next->color & 0xFFFFFF; 546 | blk.z = key_getz(next->position); 547 | blk.normal = 0; 548 | 549 | blk.visfaces = 0; 550 | if(libvxl_map_issolid(map, x + 1, y, blk.z)) 551 | blk.visfaces |= 0x01; 552 | if(libvxl_map_issolid(map, x - 1, y, blk.z)) 553 | blk.visfaces |= 0x02; 554 | if(libvxl_map_issolid(map, x, y + 1, blk.z)) 555 | blk.visfaces |= 0x04; 556 | if(libvxl_map_issolid(map, x, y - 1, blk.z)) 557 | blk.visfaces |= 0x08; 558 | if(libvxl_map_issolid(map, x, y, blk.z + 1)) 559 | blk.visfaces |= 0x10; 560 | if(libvxl_map_issolid(map, x, y, blk.z - 1)) 561 | blk.visfaces |= 0x20; 562 | 563 | fwrite(&blk, sizeof(blk), 1, f); 564 | 565 | xoffset[x]++; 566 | xyoffset[x + y * map->width]++; 567 | } 568 | } 569 | } 570 | 571 | fwrite(xoffset, sizeof(xoffset), 1, f); 572 | fwrite(xyoffset, sizeof(xyoffset), 1, f); 573 | 574 | fclose(f); 575 | }*/ 576 | 577 | bool libvxl_map_isinside(struct libvxl_map* map, int x, int y, int z) { 578 | return map && x >= 0 && y >= 0 && z >= 0 && x < (int)map->width 579 | && y < (int)map->height && z < (int)map->depth; 580 | } 581 | 582 | uint32_t libvxl_map_get(struct libvxl_map* map, int x, int y, int z) { 583 | if(!map || x < 0 || y < 0 || z < 0 || x >= (int)map->width 584 | || y >= (int)map->height || z >= (int)map->depth) 585 | return 0; 586 | if(!libvxl_geometry_get(map, x, y, z)) 587 | return 0; 588 | struct libvxl_chunk* chunk = chunk_fposition(map, x, y); 589 | struct libvxl_block* loc = bsearch( 590 | &(struct libvxl_block) { 591 | .position = pos_key(x, y, z), 592 | }, 593 | chunk->blocks, chunk->index, sizeof(struct libvxl_block), cmp); 594 | return loc ? loc->color : DEFAULT_COLOR(x, y, z); 595 | } 596 | 597 | bool libvxl_map_issolid(struct libvxl_map* map, int x, int y, int z) { 598 | if(z < 0) 599 | return false; 600 | if(!map || z >= (int)map->depth) 601 | return true; 602 | return libvxl_geometry_get(map, (size_t)x % (size_t)map->width, 603 | (size_t)y % (size_t)map->height, z); 604 | } 605 | 606 | bool libvxl_map_onsurface(struct libvxl_map* map, int x, int y, int z) { 607 | if(!map) 608 | return false; 609 | return !libvxl_map_issolid(map, x, y + 1, z) 610 | || !libvxl_map_issolid(map, x, y - 1, z) 611 | || !libvxl_map_issolid(map, x + 1, y, z) 612 | || !libvxl_map_issolid(map, x - 1, y, z) 613 | || !libvxl_map_issolid(map, x, y, z + 1) 614 | || !libvxl_map_issolid(map, x, y, z - 1); 615 | } 616 | 617 | void libvxl_map_gettop(struct libvxl_map* map, int x, int y, uint32_t* result) { 618 | if(!map || x < 0 || y < 0 || x >= (int)map->width || y >= (int)map->height) 619 | return; 620 | 621 | struct libvxl_chunk* c = chunk_fposition(map, x, y); 622 | struct libvxl_block* block = libvxl_chunk_gequal_block(c, pos_key(x, y, 0)); 623 | 624 | libvxl_assert(block < c->blocks + c->index, "block is out of bounds"); 625 | libvxl_assert(key_discardz(block->position) == pos_key(x, y, 0), 626 | "position is out of bounds"); 627 | libvxl_assert(key_getz(block->position) < map->depth, 628 | "position is out of bounds"); 629 | 630 | result[0] = block->color; 631 | result[1] = key_getz(block->position); 632 | } 633 | 634 | static void libvxl_map_set_internal(struct libvxl_map* map, int x, int y, int z, 635 | uint32_t color) { 636 | libvxl_assert(map, "map is null"); 637 | 638 | if(z < 0 || z >= (int)map->depth) 639 | return; 640 | 641 | x = (size_t)x % (size_t)map->width; 642 | y = (size_t)y % (size_t)map->height; 643 | 644 | if(libvxl_geometry_get(map, x, y, z) && !libvxl_map_onsurface(map, x, y, z)) 645 | return; 646 | 647 | libvxl_chunk_insert(chunk_fposition(map, x, y), pos_key(x, y, z), color); 648 | } 649 | 650 | static void libvxl_map_setair_internal(struct libvxl_map* map, int x, int y, 651 | int z) { 652 | libvxl_assert(map, "map is null"); 653 | 654 | if(z < 0 || z >= (int)map->depth) 655 | return; 656 | 657 | x = (size_t)x % (size_t)map->width; 658 | y = (size_t)y % (size_t)map->height; 659 | 660 | if(!libvxl_geometry_get(map, x, y, z)) 661 | return; 662 | 663 | struct libvxl_chunk* chunk = chunk_fposition(map, x, y); 664 | 665 | struct libvxl_block* loc = bsearch( 666 | &(struct libvxl_block) { 667 | .position = pos_key(x, y, z), 668 | }, 669 | chunk->blocks, chunk->index, sizeof(struct libvxl_block), cmp); 670 | 671 | if(loc) { 672 | memmove(loc, loc + 1, 673 | (chunk->blocks + (--chunk->index) - loc) 674 | * sizeof(struct libvxl_block)); 675 | 676 | if(chunk->index * LIBVXL_CHUNK_SHRINK <= chunk->length) { 677 | chunk->length /= LIBVXL_CHUNK_GROWTH; 678 | chunk->blocks = libvxl_mem_realloc( 679 | chunk->blocks, chunk->length * sizeof(struct libvxl_block)); 680 | } 681 | } 682 | } 683 | 684 | void libvxl_map_set(struct libvxl_map* map, int x, int y, int z, 685 | uint32_t color) { 686 | if(!map || x < 0 || y < 0 || z < 0 || x >= (int)map->width 687 | || y >= (int)map->height || z >= (int)map->depth) 688 | return; 689 | 690 | libvxl_geometry_set(map, x, y, z, 1); 691 | libvxl_map_set_internal(map, x, y, z, color); 692 | 693 | if(!libvxl_map_onsurface(map, x, y + 1, z)) 694 | libvxl_map_setair_internal(map, x, y + 1, z); 695 | if(!libvxl_map_onsurface(map, x, y - 1, z)) 696 | libvxl_map_setair_internal(map, x, y - 1, z); 697 | 698 | if(!libvxl_map_onsurface(map, x + 1, y, z)) 699 | libvxl_map_setair_internal(map, x + 1, y, z); 700 | if(!libvxl_map_onsurface(map, x - 1, y, z)) 701 | libvxl_map_setair_internal(map, x - 1, y, z); 702 | 703 | if(!libvxl_map_onsurface(map, x, y, z + 1)) 704 | libvxl_map_setair_internal(map, x, y, z + 1); 705 | if(!libvxl_map_onsurface(map, x, y, z - 1)) 706 | libvxl_map_setair_internal(map, x, y, z - 1); 707 | } 708 | 709 | void libvxl_map_setair(struct libvxl_map* map, int x, int y, int z) { 710 | if(!map || x < 0 || y < 0 || z < 0 || x >= (int)map->width 711 | || y >= (int)map->height || z >= (int)map->depth - 1) 712 | return; 713 | 714 | bool surface_prev[6] = { 715 | libvxl_map_issolid(map, x, y + 1, z) ? 716 | libvxl_map_onsurface(map, x, y + 1, z) : 717 | true, 718 | libvxl_map_issolid(map, x, y - 1, z) ? 719 | libvxl_map_onsurface(map, x, y - 1, z) : 720 | true, 721 | libvxl_map_issolid(map, x + 1, y, z) ? 722 | libvxl_map_onsurface(map, x + 1, y, z) : 723 | true, 724 | libvxl_map_issolid(map, x - 1, y, z) ? 725 | libvxl_map_onsurface(map, x - 1, y, z) : 726 | true, 727 | libvxl_map_issolid(map, x, y, z + 1) ? 728 | libvxl_map_onsurface(map, x, y, z + 1) : 729 | true, 730 | libvxl_map_issolid(map, x, y, z - 1) ? 731 | libvxl_map_onsurface(map, x, y, z - 1) : 732 | true, 733 | }; 734 | 735 | libvxl_map_setair_internal(map, x, y, z); 736 | libvxl_geometry_set(map, x, y, z, 0); 737 | 738 | if(!surface_prev[0] && libvxl_map_onsurface(map, x, y + 1, z)) 739 | libvxl_map_set_internal(map, x, y + 1, z, DEFAULT_COLOR(x, y + 1, z)); 740 | if(!surface_prev[1] && libvxl_map_onsurface(map, x, y - 1, z)) 741 | libvxl_map_set_internal(map, x, y - 1, z, DEFAULT_COLOR(x, y - 1, z)); 742 | 743 | if(!surface_prev[2] && libvxl_map_onsurface(map, x + 1, y, z)) 744 | libvxl_map_set_internal(map, x + 1, y, z, DEFAULT_COLOR(x + 1, y, z)); 745 | if(!surface_prev[3] && libvxl_map_onsurface(map, x - 1, y, z)) 746 | libvxl_map_set_internal(map, x - 1, y, z, DEFAULT_COLOR(x - 1, y, z)); 747 | 748 | if(!surface_prev[4] && libvxl_map_onsurface(map, x, y, z + 1)) 749 | libvxl_map_set_internal(map, x, y, z + 1, DEFAULT_COLOR(x, y, z + 1)); 750 | if(!surface_prev[5] && libvxl_map_onsurface(map, x, y, z - 1)) 751 | libvxl_map_set_internal(map, x, y, z - 1, DEFAULT_COLOR(x, y, z - 1)); 752 | } 753 | 754 | void libvxl_copy_chunk_destroy(struct libvxl_chunk_copy* copy) { 755 | if(!copy) 756 | return; 757 | 758 | libvxl_mem_free(copy->geometry); 759 | libvxl_mem_free(copy->blocks_sorted); 760 | } 761 | 762 | uint32_t libvxl_copy_chunk_get_color(struct libvxl_chunk_copy* copy, size_t x, 763 | size_t y, size_t z) { 764 | if(!copy) 765 | return 0; 766 | 767 | struct libvxl_block* loc = bsearch( 768 | &(struct libvxl_block) { 769 | .position = pos_key(x, y, z), 770 | }, 771 | copy->blocks_sorted, copy->blocks_sorted_count, 772 | sizeof(struct libvxl_block), cmp); 773 | return loc ? (loc->color & 0xFFFFFF) : 0; 774 | } 775 | 776 | bool libvxl_copy_chunk_is_solid(struct libvxl_chunk_copy* copy, size_t x, 777 | size_t y, size_t z) { 778 | if(!copy || x >= copy->width || y >= copy->height || z >= copy->depth) 779 | return true; 780 | 781 | size_t offset = z + (x + y * copy->width) * copy->depth; 782 | return copy->geometry[offset / (sizeof(size_t) * 8)] 783 | & ((size_t)1 << (offset % (sizeof(size_t) * 8))); 784 | } 785 | 786 | void libvxl_copy_chunk(struct libvxl_map* map, struct libvxl_chunk_copy* copy, 787 | size_t x, size_t y) { 788 | if(!map || !copy || x >= map->width || y >= map->height) 789 | return; 790 | 791 | size_t sg 792 | = (map->width * map->height * map->depth + (sizeof(size_t) * 8 - 1)) 793 | / (sizeof(size_t) * 8) * sizeof(size_t); 794 | copy->geometry = libvxl_mem_malloc(sg); 795 | memcpy(copy->geometry, map->geometry, sg); 796 | 797 | struct libvxl_chunk* c = chunk_fposition(map, x, y); 798 | copy->blocks_sorted 799 | = libvxl_mem_malloc(c->index * sizeof(struct libvxl_block)); 800 | copy->blocks_sorted_count = c->index; 801 | memcpy(copy->blocks_sorted, c->blocks, 802 | c->index * sizeof(struct libvxl_block)); 803 | 804 | copy->width = map->width; 805 | copy->height = map->height; 806 | copy->depth = map->depth; 807 | } 808 | -------------------------------------------------------------------------------- /libvxl.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBVXL_H 2 | #define LIBVXL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef libvxl_assert 9 | #include 10 | #define libvxl_assert(cond, msg) assert(cond) 11 | #endif 12 | 13 | //! @file libvxl.h 14 | //! Reads and writes vxl maps, using an likewise internal memory format 15 | 16 | //! @brief Internal chunk size 17 | //! @note Map is split into square chunks internally to speed up modifications 18 | //! @note Lower values can speed up map access, but can lead to higher memory fragmentation 19 | #define LIBVXL_CHUNK_SIZE 16 20 | //! @brief How many blocks the buffer will grow once it is full 21 | #define LIBVXL_CHUNK_GROWTH 2 22 | #define LIBVXL_CHUNK_SHRINK 4 23 | 24 | #ifndef libvxl_mem_malloc 25 | #define libvxl_mem_malloc(sz) malloc(sz) 26 | #define libvxl_mem_realloc(p, newsz) realloc(p, newsz) 27 | #define libvxl_mem_free(p) free(p) 28 | #endif 29 | 30 | //! @brief The default color to use when a block is solid, but has no color 31 | //! 32 | //! This is the case for e.g. underground blocks which are not visible from the surface 33 | #define DEFAULT_COLOR(x,y,z) 0x674028 34 | 35 | //! @brief Used to map coordinates to a key 36 | //! 37 | //! This format is used: 38 | //! @code{.c} 39 | //! 0xYYYXXXZZ 40 | //! @endcode 41 | //! This leaves 12 bits for X and Y and 8 bits for Z 42 | #define pos_key(x,y,z) ((uint32_t)(((y)<<20) | ((x)<<8) | (z))) 43 | #define key_discardz(key) ((uint32_t)((key)&0xFFFFFF00)) 44 | #define key_getx(key) (((key)>>8)&0xFFF) 45 | #define key_gety(key) (((key)>>20)&0xFFF) 46 | #define key_getz(key) ((key)&0xFF) 47 | 48 | #ifdef _MSC_VER 49 | #define __attribute(x) 50 | #endif 51 | 52 | struct __attribute((packed)) libvxl_span { 53 | uint8_t length; 54 | uint8_t color_start; 55 | uint8_t color_end; 56 | uint8_t air_start; 57 | }; 58 | 59 | struct libvxl_block { 60 | uint32_t position; 61 | uint32_t color; 62 | }; 63 | 64 | struct libvxl_chunk { 65 | struct libvxl_block* blocks; 66 | size_t length, index; 67 | }; 68 | 69 | struct libvxl_map { 70 | size_t width, height, depth; 71 | struct libvxl_chunk* chunks; 72 | size_t* geometry; 73 | size_t streamed; 74 | }; 75 | 76 | struct libvxl_stream { 77 | struct libvxl_map* map; 78 | size_t* chunk_offsets; 79 | size_t chunk_size; 80 | void* buffer; 81 | size_t buffer_offset; 82 | size_t pos; 83 | }; 84 | 85 | struct __attribute((packed)) libvxl_kv6 { 86 | char magic[4]; 87 | int width, height, depth; 88 | float pivot[3]; 89 | int len; 90 | }; 91 | 92 | struct __attribute((packed)) libvxl_kv6_block { 93 | int color; 94 | short z; 95 | unsigned char visfaces; 96 | unsigned char normal; 97 | }; 98 | 99 | struct libvxl_chunk_copy { 100 | size_t width, height, depth; 101 | size_t* geometry; 102 | struct libvxl_block* blocks_sorted; 103 | size_t blocks_sorted_count; 104 | }; 105 | 106 | void libvxl_copy_chunk_destroy(struct libvxl_chunk_copy* copy); 107 | 108 | uint32_t libvxl_copy_chunk_get_color(struct libvxl_chunk_copy* copy, size_t x, 109 | size_t y, size_t z); 110 | 111 | bool libvxl_copy_chunk_is_solid(struct libvxl_chunk_copy* copy, size_t x, 112 | size_t y, size_t z); 113 | 114 | void libvxl_copy_chunk(struct libvxl_map* map, struct libvxl_chunk_copy* copy, 115 | size_t x, size_t y); 116 | 117 | //! @brief Load a map from memory or create an empty one 118 | //! 119 | //! Example: 120 | //! @code{.c} 121 | //! struct libvxl_map m; 122 | //! libvxl_create(&m,512,512,64,ptr); 123 | //! @endcode 124 | //! @param map Pointer to a struct of type libvxl_map that stores information about the loaded map 125 | //! @param w Width of map (x-coord) 126 | //! @param h Height of map (y-coord) 127 | //! @param d Depth of map (z-coord) 128 | //! @param data Pointer to valid map data, left unmodified also not freed 129 | //! @param len map data size in bytes 130 | //! @note Pass **NULL** as map data to create a new empty map, just water level will be filled with DEFAULT_COLOR 131 | //! @returns 1 on success 132 | bool libvxl_create(struct libvxl_map* map, size_t w, size_t h, size_t d, const void* data, size_t len); 133 | 134 | //! @brief Write a map to disk, uses the libvxl_stream API internally 135 | //! @param map Map to be written 136 | //! @param name Filename of output file 137 | //! @returns total bytes written to disk 138 | size_t libvxl_writefile(struct libvxl_map* map, char* name); 139 | 140 | //! @brief Compress the map back to vxl format and save it in *out*, the total byte size will be written to *size* 141 | //! @param map Map to compress 142 | //! @param out pointer to memory where the vxl will be stored 143 | //! @param size pointer to an int, total byte size 144 | void libvxl_write(struct libvxl_map* map, void* out, size_t* size); 145 | 146 | //! @brief Tells if a block is solid at location [x,y,z] 147 | //! @param map Map to use 148 | //! @param x x-coordinate of block 149 | //! @param y y-coordinate of block 150 | //! @param z z-coordinate of block 151 | //! @returns solid=1, air=0 152 | //! @note Blocks out of map bounds are always non-solid 153 | bool libvxl_map_issolid(struct libvxl_map* map, int x, int y, int z); 154 | 155 | //! @brief Tells if a block is visible on the surface, meaning it is exposed to air 156 | //! @param map Map to use 157 | //! @param x x-coordinate of block 158 | //! @param y y-coordinate of block 159 | //! @param z z-coordinate of block 160 | //! @returns on surface=1 161 | bool libvxl_map_onsurface(struct libvxl_map* map, int x, int y, int z); 162 | 163 | //! @brief Read block color 164 | //! @param map Map to use 165 | //! @param x x-coordinate of block 166 | //! @param y y-coordinate of block 167 | //! @param z z-coordinate of block 168 | //! @returns color of block at location [x,y,z] in format *0xAARRGGBB*, on error *0* 169 | uint32_t libvxl_map_get(struct libvxl_map* map, int x, int y, int z); 170 | 171 | //! @brief Read color of topmost block (as seen from above at Z=0) 172 | //! 173 | //! See libvxl_map_get() for to be expected color format 174 | //! 175 | //! Example: 176 | //! @code{.c} 177 | //! int[2] result; 178 | //! libvxl_map_gettop(&m,256,256,&result); 179 | //! int color = result[0]; 180 | //! int height = result[1]; 181 | //! @endcode 182 | //! @param map Map to use 183 | //! @param x x-coordinate of block column 184 | //! @param y y-coordinate of block column 185 | //! @param result pointer to *int[2]*, is filled with color at *index 0* and height at *index 1* 186 | //! @note *result* is left unmodified if [x,y,z] is out of map bounds 187 | //! @returns *nothing, see result param* 188 | void libvxl_map_gettop(struct libvxl_map* map, int x, int y, uint32_t* result); 189 | 190 | //! @brief Set block at location [x,y,z] to a new color 191 | //! 192 | //! See libvxl_map_get() for expected color format, alpha component can be discarded 193 | //! 194 | //! @param map Map to use 195 | //! @param x x-coordinate of block 196 | //! @param y y-coordinate of block 197 | //! @param z z-coordinate of block 198 | //! @param color replacement color 199 | //! @note nothing is changed if [x,y,z] is out of map bounds 200 | void libvxl_map_set(struct libvxl_map* map, int x, int y, int z, uint32_t color); 201 | 202 | //! @brief Set location [x,y,z] to air, will destroy any block at this position 203 | //! @param map Map to use 204 | //! @param x x-coordinate of block 205 | //! @param y y-coordinate of block 206 | //! @param z z-coordinate of block 207 | void libvxl_map_setair(struct libvxl_map* map, int x, int y, int z); 208 | 209 | //! @brief Free a map from memory 210 | //! @param map Map to free 211 | void libvxl_free(struct libvxl_map* map); 212 | 213 | //! @brief Tries to guess the size of a map 214 | //! @note This won't always give accurate results for a map's height 215 | //! @note It is assumed the map is square. 216 | //! @param size Pointer to int where edge length of the square will be stored 217 | //! @param depth Pointer to int where map height will be stored 218 | //! @param data Pointer to valid map data, left unmodified also not freed 219 | //! @param len compressed map size in bytes 220 | bool libvxl_size(size_t* size, size_t* depth, const void* data, size_t len); 221 | 222 | //! @brief Start streaming a map 223 | //! @param stream Pointer to a struct of type libvxl_stream 224 | //! @param map Map to stream 225 | //! @param chunk_size size in bytes each call to libvxl_stream_read() will encode at most 226 | void libvxl_stream(struct libvxl_stream* stream, struct libvxl_map* map, size_t chunk_size); 227 | 228 | //! @brief Free a stream from memory 229 | //! @param map stream to free 230 | void libvxl_stream_free(struct libvxl_stream* stream); 231 | 232 | //! @brief Read bytes from the stream, this is at most stream->chunk_size bytes 233 | //! @note The actual byte count encoded is returned, this can be less but never more than chunk_size 234 | //! @note *0* is returned when the stream reached its end 235 | //! @param stream stream to use 236 | //! @param out pointer to buffer where encoded bytes are stored 237 | //! @returns total byte count that was encoded 238 | size_t libvxl_stream_read(struct libvxl_stream* stream, void* out); 239 | 240 | //! @brief Check if a position is inside a map's boundary 241 | //! @param map Map to use 242 | //! @param x x-coordinate of block 243 | //! @param y y-coordinate of block 244 | //! @param z z-coordinate of block 245 | bool libvxl_map_isinside(struct libvxl_map* map, int x, int y, int z); 246 | 247 | #endif 248 | --------------------------------------------------------------------------------