first commit
This commit is contained in:
commit
8353960dae
14 changed files with 4729 additions and 0 deletions
2
.clangd
Normal file
2
.clangd
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
CompileFlags:
|
||||||
|
Add: -ferror-limit=0
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal 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
23
LICENSE
Normal 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
24
Makefile
Normal 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)
|
3932
include/HandmadeMath/HandmadeMath.h
Normal file
3932
include/HandmadeMath/HandmadeMath.h
Normal file
File diff suppressed because it is too large
Load diff
116
include/HandmadeMath/LICENSE
Normal file
116
include/HandmadeMath/LICENSE
Normal 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
34
include/gmc/gmc.h
Normal 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
41
include/gmc/map.h
Normal 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
326
include/slibs/slibs.h
Normal 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
142
src/gmc/gmc.c
Normal 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
13
src/gmc/main.c
Normal 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
48
src/gmc/map.c
Normal 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
2
src/gmc/slibs.c
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#define SL_IMPLEMENTATION
|
||||||
|
#include <slibs/slibs.h>
|
15
test.map
Normal file
15
test.map
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue