first commit

This commit is contained in:
sam 2024-09-12 18:21:08 +12:00
commit 8353960dae
14 changed files with 4729 additions and 0 deletions

2
.clangd Normal file
View file

@ -0,0 +1,2 @@
CompileFlags:
Add: -ferror-limit=0

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
.DS_Store
.cache/
.session.vim
*.exe
*.pdb
*.ilk
gmc-bin
out.gmc
compile_commands.json
**/*.o
.vscode/

23
LICENSE Normal file
View file

@ -0,0 +1,23 @@
zlib/libpng license
Copyright (c) 2024 Sam Watson
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

24
Makefile Normal file
View file

@ -0,0 +1,24 @@
GMAPC=gmc-bin
CFLAGS=-I. -Iinclude -Wall -Wextra -Werror -Wno-header-guard -Wno-comment -Wno-unused-parameter -Wno-unused-function -Ofast
GMC_C_FILES=$(shell find -L src/gmc -type f -name '*.c')
GMC_C_OBJ=$(GMC_C_FILES:.c=.o)
ifeq ($(OS), Windows_NT)
BINARY := $(BINARY).exe
endif
.PHONY: clean bear
$(GMAPC): $(GMC_C_OBJ)
$(CC) $(GMC_C_OBJ) $(LDFLAGS) -o $@
%.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)
bear: clean
bear -- $(MAKE) $(BINARY)
clean:
rm -rf $(GMC_C_OBJ) $(GMAPC)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

34
include/gmc/gmc.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef __G_GMC_H__
#define __G_GMC_H__
#include <stdint.h>
#include <gmc/map.h>
typedef struct gmc_property {
uint32_t key;
uint32_t value;
} gmc_property;
typedef struct gmc_entity {
uint32_t property_count;
gmc_property* properties;
} gmc_entity;
typedef struct gmc_file {
uint64_t magic;
uint32_t string_buf_len;
char* string_buf;
uint32_t entity_count;
gmc_entity* entities;
} gmc_file;
gmc_file gmc_read(const char* filename);
gmc_file gmc_from_map(map_map map);
void gmc_write(gmc_file file, const char* filename);
void gmc_print(gmc_file file);
const extern uint64_t gmc_magic;
#endif

41
include/gmc/map.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef __GMC_MAP_H__
#define __GMC_MAP_H__
#include <HandmadeMath/HandmadeMath.h>
#include <slibs/slibs.h>
#define PLANE_FMT "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) %s %f %f %f %f %f"
#define SPREAD_VEC2(v) v.X, v.Y
#define SPREAD_VEC3(v) SPREAD_VEC2(v), v.Z
#define SPREAD_PLANE(p) SPREAD_VEC3(p.p1), SPREAD_VEC3(p.p2), SPREAD_VEC3(p.p3), \
p.texture, SPREAD_VEC2(p.tex_offset), p.tex_rotation, SPREAD_VEC2(p.tex_scale)
typedef struct map_plane {
HMM_Vec3 p1, p2, p3;
char texture[128];
HMM_Vec2 tex_offset;
float tex_rotation;
HMM_Vec2 tex_scale;
} map_plane;
typedef struct map_brush {
sl_vec(map_plane) planes;
} map_brush;
typedef struct map_property {
char key[128];
char value[128];
} map_property;
typedef struct map_entity {
sl_vec(map_property) properties;
sl_vec(map_brush) brushes;
} map_entity;
typedef struct map_map {
sl_vec(map_entity) entities;
} map_map;
map_map map_parse(const char* filename);
#endif

326
include/slibs/slibs.h Normal file
View file

@ -0,0 +1,326 @@
#ifndef SLIBS_H
#define SLIBS_H
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Miscellaneous
#define sl_auto(name, x) typeof(x) name = x
#define sl_new(type, ...) \
({ \
type *ptr = malloc(sizeof(type)); \
*ptr = (type){__VA_ARGS__}; \
ptr; \
})
#define sl_init(type, ...) \
(type) { __VA_ARGS__ }
#define sl_array_len(arr) sizeof(arr) / sizeof(arr[0])
#define sl_fmt_spec(arg) \
_Generic((arg), \
int8_t: "%d", \
int16_t: "%d", \
int32_t: "%d", \
int64_t: "%lld", \
uint8_t: "%u", \
uint16_t: "%u", \
uint32_t: "%lu", \
uint64_t: "%llu", \
double: "%lf", \
float: "%f", \
char: "%c", \
char *: "%s", \
void *: "%p", \
default: "Unknown")
#define sl_stringify(x) #x
// Vector
#define sl_vec(type) \
struct { \
type *data; \
size_t size; \
size_t capacity; \
}
#define sl_vec_grow(vec) \
{ \
(vec).capacity = (vec).capacity * 2 + 1; \
void *ptr = realloc((vec).data, (vec).capacity * sizeof(*(vec).data)); \
if (ptr) \
(vec).data = ptr; \
}
#define sl_vec_push(vec, element) \
{ \
if ((vec).size >= (vec).capacity) \
sl_vec_grow(vec); \
(vec).data[(vec).size++] = (element); \
}
#define sl_vec_from_arr(vec, arr) \
{ \
for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { \
sl_vec_push(vec, arr[i]); \
} \
}
#define sl_vec_unshift(vec, element) \
{ \
if ((vec).size >= (vec).capacity) \
sl_vec_grow(vec); \
memmove((vec).data + 1, (vec).data, (vec).size * sizeof(*(vec).data)); \
(vec).data[0] = (element); \
(vec).size++; \
}
#define sl_vec_shift(vec) \
{ \
memmove((vec).data, (vec).data + 1, (vec).size * sizeof(*(vec).data)); \
(vec).size--; \
}
#define sl_vec_forward(vec) \
{ (vec).data++; }
#define sl_vec_backward(vec) \
{ (vec).data--; }
#define sl_vec_pop(vec) \
{ \
if ((vec).size > 0) { \
(vec).size--; \
} \
}
#define sl_vec_at(vec, index) ((vec).data[index])
#define sl_vec_size(vec) ((vec).size)
#define sl_vec_capacity(vec) ((vec).capacity)
#define sl_vec_free(vec) free((vec).data)
#define sl_vec_begin(vec) (vec).data
#define sl_vec_end(vec) ((vec).data + (vec).size)
#define sl_vec_it(name, vec) \
sl_auto((name), sl_vec_begin(vec)); \
(name) != sl_vec_end(vec); \
++(name)
// TODO: Linked List
// #define sl_list(name, type) \
// struct name \
// { \
// type *data; \
// struct name *next; \
// }
// #define sl_list_append(list, value) \
// { \
// sl_auto(curr, list);\
// } \
// Hashmap
#define SL_MAX_HASH_ENTRIES 512
int sl_hash(const char *str);
#define sl_map(name, valuetype) \
typedef valuetype sl_##name##_type; \
\
typedef struct sl_##name##_entry { \
const char *key; \
sl_##name##_type value; \
} sl_##name##_entry; \
\
typedef sl_vec(sl_##name##_entry) sl_##name##_entry_vec; \
\
typedef struct sl_##name##_map { \
sl_##name##_entry_vec *entries[SL_MAX_HASH_ENTRIES]; \
} sl_##name##_map; \
\
sl_##name##_map name = {0};
#define sl_map_set(map, key_, val) \
{ \
int hash = sl_hash(key_); \
sl_##map##_entry_vec *entry = map.entries[hash]; \
if (!entry) { \
entry = calloc(1, sizeof(sl_##map##_entry_vec)); \
map.entries[hash] = entry; \
} \
int found = 0; \
for (sl_vec_it(el, *entry)) { \
if (strcmp(el->key, key_) == 0) { \
el->value = val; \
found = 1; \
break; \
} \
} \
if (!found) { \
sl_##map##_entry new_entry = {key_, val}; \
sl_vec_push(*entry, new_entry) \
} \
}
#define sl_map_get(map, key_) \
({ \
sl_##map##_entry_vec *entry = map.entries[sl_hash(key_)]; \
sl_##map##_type *value_ = NULL; \
\
if (entry) { \
for (sl_vec_it(el, *entry)) { \
if (strcmp(el->key, key_) == 0) { \
value_ = &el->value; \
break; \
} \
} \
} \
\
value_; \
})
#ifdef SL_IMPLEMENTATION
int sl_hash(const char *str) {
uint32_t seed = 0;
size_t len = strlen(str);
for (size_t i = 0; i < len && i < sizeof(uint32_t); i++) {
seed <<= 8;
seed |= str[i];
}
srand(seed);
return rand() % SL_MAX_HASH_ENTRIES;
}
#endif
// String
typedef sl_vec(char) sl_string;
#define sl_string(c_str) \
({ \
sl_string str = {0}; \
for (size_t i = 0; i < strlen((c_str)); i++) \
sl_vec_push(str, (c_str)[i]); \
str; \
})
#define sl_tostring(val) \
({ \
sl_auto(len, snprintf(NULL, 0, sl_fmt_spec(val), val) + 1); \
sl_auto(buf, (char *)malloc(len)); \
snprintf(buf, len, sl_fmt_spec(val), val); \
sl_auto(str, sl_string(buf)); \
free(buf); \
str; \
})
#define sl_str_free(str) sl_vec_free(str)
char *sl_c_str(sl_string str);
#ifdef SL_IMPLEMENTATION
char *sl_c_str(sl_string str) {
sl_vec_push(str, '\0');
return str.data;
}
#endif
void sl_append_c_str(sl_string *sl_str, const char *c_str);
#ifdef SL_IMPLEMENTATION
void sl_append_c_str(sl_string *sl_str, const char *c_str) {
for (size_t i = 0; i < strlen(c_str); i++) {
sl_vec_push(*sl_str, c_str[i]);
}
}
#endif
// Pointers
#define sl_ptr(type) \
struct { \
type *ptr; \
int ref_count; \
}
#define sl_ptr_make(raw_ptr) {raw_ptr, 1}
#define sl_ptr_release(smart_ptr) \
({ \
smart_ptr.ref_count--; \
if (smart_ptr.ref_count <= 0) { \
free(smart_ptr.ptr); \
} \
})
#define sl_ptr_get(smart_ptr, raw_ptr_name, scope) \
({ \
assert(smart_ptr.ref_count > 0 && "Smart pointer already released!"); \
sl_auto(raw_ptr_name, smart_ptr.ptr); \
smart_ptr.ref_count++; \
scope; \
sl_ptr_release(smart_ptr); \
});
#define sl_ptr_scope(smart_ptr, scope) \
({ \
scope; \
sl_ptr_release(smart_ptr); \
});
FILE *sl_open_file(const char *filename, const char *mode);
sl_string *sl_read_file(const char *filename);
void sl_write_file(const char *filename, const sl_string buffer);
#ifdef SL_IMPLEMENTATION
FILE *sl_open_file(const char *filename, const char *mode) {
FILE *file = fopen(filename, mode);
return file;
}
sl_string *sl_read_file(const char *filename) {
FILE *file = sl_open_file(filename, "r");
if (!file)
return NULL;
fseek(file, 0, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0, SEEK_SET);
sl_string *buffer = sl_new(sl_string, 0);
for (size_t i = 0; i < file_size; i++) {
sl_vec_push(*buffer, fgetc(file));
}
fclose(file);
return buffer;
}
void sl_write_file(const char *filename, sl_string buffer) {
FILE *file = sl_open_file(filename, "w");
if (!file)
return;
fputs(sl_c_str(buffer), file);
fclose(file);
}
#endif
#endif // SLIBS_H

142
src/gmc/gmc.c Normal file
View file

@ -0,0 +1,142 @@
#include <gmc/gmc.h>
#include <stdio.h>
#include <slibs/slibs.h>
#include <zlib.h>
#define GMC_WM(file, variable, count) fwrite(&variable, sizeof(variable), count, file)
#define GMC_RM(file, variable, count) fread(&variable, sizeof(variable), count, file)
#define GMC_W(file, variable) GMC_WM(file, variable, 1)
#define GMC_R(file, variable) GMC_RM(file, variable, 1)
gmc_file gmc_read(const char* filename) {
FILE* input = fopen(filename, "rb");
gmc_file file = { 0 };
GMC_R(input, file.magic);
GMC_R(input, file.string_buf_len);
file.string_buf = calloc(file.string_buf_len, sizeof(char));
GMC_RM(input, *file.string_buf, file.string_buf_len);
GMC_R(input, file.entity_count);
file.entities = calloc(file.entity_count, sizeof(gmc_entity));
for(uint32_t i = 0; i < file.entity_count; i++) {
gmc_entity* entity = &file.entities[i];
GMC_R(input, entity->property_count);
entity->properties = calloc(entity->property_count, sizeof(gmc_property));
GMC_RM(input, *entity->properties, entity->property_count);
}
return file;
}
gmc_file gmc_from_map(map_map map) {
sl_string strings = { 0 };
sl_map(string_indicies, int);
sl_vec(gmc_entity) gmc_ents = { 0 };
for(sl_vec_it(entity, map.entities)) {
sl_vec(gmc_property) gmc_props = { 0 };
for(sl_vec_it(property, entity->properties)) {
gmc_property gmc_prop = { 0 };
if(sl_map_get(string_indicies, property->key) == NULL) {
gmc_prop.key = strings.size;
sl_append_c_str(&strings, property->key);
sl_vec_push(strings, '\0');
sl_map_set(string_indicies, property->key, gmc_prop.key);
} else {
gmc_prop.key = *sl_map_get(string_indicies, property->key);
}
if(sl_map_get(string_indicies, property->value) == NULL) {
gmc_prop.value = strings.size;
sl_append_c_str(&strings, property->value);
sl_vec_push(strings, '\0');
sl_map_set(string_indicies, property->value, gmc_prop.value);
} else {
gmc_prop.value = *sl_map_get(string_indicies, property->value);
}
sl_vec_push(gmc_props, gmc_prop);
}
gmc_entity gmc_ent = {
.property_count = gmc_props.size,
.properties = gmc_props.data
};
sl_vec_push(gmc_ents, gmc_ent);
}
gmc_file file = {
.magic = gmc_magic,
.string_buf_len = strings.size,
.string_buf = strings.data,
.entity_count = gmc_ents.size,
.entities = gmc_ents.data
};
return file;
}
void gmc_write(gmc_file file, const char* filename) {
FILE* output = fopen(filename, "wb");
GMC_W(output, file.magic);
GMC_W(output, file.string_buf_len);
fwrite(file.string_buf, sizeof(char), file.string_buf_len, output);
GMC_W(output, file.entity_count);
for(uint32_t i = 0; i < file.entity_count; i++) {
gmc_entity entity = file.entities[i];
GMC_W(output, entity.property_count);
for(uint32_t j = 0; j < entity.property_count; j++) {
gmc_property property = entity.properties[j];
GMC_W(output, property.key);
GMC_W(output, property.value);
}
}
fclose(output);
}
void gmc_print(gmc_file file) {
printf("--GMC File--\n");
printf("Magic: %llu\n\n", file.magic);
printf("String buffer length: %d\n", file.string_buf_len);
printf("String buffer:\n0: ");
for(uint32_t i = 0; i < file.string_buf_len; i++) {
char ch = file.string_buf[i];
if(ch == '\0') {
printf("\n%d: ", i + 1);
} else {
printf("%c", ch);
}
}
printf("\n\nEntity count: %d\n", file.entity_count);
for(uint32_t i = 0; i < file.entity_count; i++) {
gmc_entity entity = file.entities[i];
printf("Entity %d:\n", i);
printf("\tProperty count: %d\n", entity.property_count);
printf("\tProperties:\n");
for(uint32_t j = 0; j < entity.property_count; j++) {
gmc_property property = entity.properties[j];
printf("\t\t%d (%s): %d (%s)\n", property.key, &file.string_buf[property.key],
property.value, &file.string_buf[property.value]);
}
}
}
const uint64_t gmc_magic =
((uint64_t)('G') << 0 | (uint64_t)('M') << 8 | (uint64_t)('C') << 16 |
(uint64_t)('F') << 24 | (uint64_t)('M') << 32 | (uint64_t)('T') << 40 |
(uint64_t)('0') << 48 | (uint64_t)('1') << 56);

13
src/gmc/main.c Normal file
View file

@ -0,0 +1,13 @@
#include <gmc/gmc.h>
#include <gmc/map.h>
#include <stdint.h>
#include <slibs/slibs.h>
int main(int argc, char* argv[]) {
assert(argc > 1);
map_map map = map_parse(argv[1]);
gmc_file file = gmc_from_map(map);
gmc_write(file, "out.gmc");
file = gmc_read("out.gmc");
gmc_print(file);
}

48
src/gmc/map.c Normal file
View file

@ -0,0 +1,48 @@
#include <gmc/map.h>
#include <assert.h>
map_map map_parse(const char* filename) {
map_map m = { 0 };
map_entity* current_ent = NULL;
map_brush* current_brush = NULL;
FILE* map_file = fopen(filename, "r");
assert(map_file && "Failed to open map file");
char line[256];
while(fgets(line, sizeof(line), map_file)) {
char c = line[0];
if(c == '{' && current_ent != NULL) {
current_brush = &(map_brush){ 0 };
} else if(c == '{') {
current_ent = &(map_entity){ 0 };
} else if(c == '"') {
map_property prop = { 0 };
sscanf(line, "\"%127[^\"]\" \"%127[^\"]\"", prop.key, prop.value);
sl_vec_push(current_ent->properties, prop);
} else if(c == '(') {
map_plane p = { 0 };
sscanf(line, PLANE_FMT,
&p.p1.X, &p.p1.Y, &p.p1.Z,
&p.p2.X, &p.p2.Y, &p.p2.Z,
&p.p3.X, &p.p3.Y, &p.p3.Z,
p.texture,
&p.tex_offset.X, &p.tex_offset.Y,
&p.tex_rotation,
&p.tex_scale.X, &p.tex_scale.Y);
sl_vec_push(current_brush->planes, p);
} else if(c == '}' && current_brush != NULL) {
sl_vec_push(current_ent->brushes, *current_brush);
current_brush = NULL;
} else if(c == '}') {
sl_vec_push(m.entities, *current_ent);
current_ent = NULL;
}
}
fclose(map_file);
return m;
}

2
src/gmc/slibs.c Normal file
View file

@ -0,0 +1,2 @@
#define SL_IMPLEMENTATION
#include <slibs/slibs.h>

15
test.map Normal file
View file

@ -0,0 +1,15 @@
// Game: Generic
// Format: Standard
// entity 0
{
"classname" "worldspawn"
// brush 0
{
( -64 -64 -16 ) ( -64 -63 -16 ) ( -64 -64 -15 ) __TB_empty 0 0 0 1 1
( -64 -64 -16 ) ( -64 -64 -15 ) ( -63 -64 -16 ) __TB_empty 0 0 0 1 1
( -64 -64 -16 ) ( -63 -64 -16 ) ( -64 -63 -16 ) __TB_empty 0 0 0 1 1
( 64 64 16 ) ( 64 65 16 ) ( 65 64 16 ) __TB_empty -22.5 0 0 1 1
( 64 64 16 ) ( 65 64 16 ) ( 64 64 17 ) __TB_empty 0 0 0 1 1
( 64 64 16 ) ( 64 64 17 ) ( 64 65 16 ) __TB_empty 0 0 0 1 1
}
}