aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar gingerBill 2016-04-24 20:45:16 +0100
committerGravatar gingerBill 2016-04-24 20:45:16 +0100
commit3811da351ab5067cd86a0948816532fc039276e0 (patch)
tree3076ce6700f7a9e68a1a1fc25ce5fb3a30d46e6b
parentREADME.md Update (diff)
gb_gl.h and new naming conventions
-rw-r--r--gb.h529
-rw-r--r--gb_gl.h1412
2 files changed, 1656 insertions, 285 deletions
diff --git a/gb.h b/gb.h
index 9e75b6b..28d8aa5 100644
--- a/gb.h
+++ b/gb.h
@@ -1,4 +1,4 @@
-/* gb.h - v0.02a - Ginger Bill's C Helper Library - public domain
+/* gb.h - v0.03 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff
@@ -26,6 +26,7 @@ Conventions used:
Version History:
+ 0.03 - Completely change procedure naming convention
0.02a - Bug fixes
0.02 - Change naming convention and gbArray(Type)
0.01 - Initial Version
@@ -170,6 +171,7 @@ extern "C" {
#if defined(GB_SYSTEM_WINDOWS)
#define NOMINMAX 1
#define WIN32_LEAN_AND_MEAN 1
+ #define WIN32_MEAN_AND_LEAN 1
#define VC_EXTRALEAN 1
#include <windows.h>
#else
@@ -448,7 +450,7 @@ namespace gb {
#define GB_DEFER_1(x, y) x##y
#define GB_DEFER_2(x, y) GB_DEFER_1(x, y)
#define GB_DEFER_3(x) GB_DEFER_2(x, __COUNTER__)
- #define defer(code) auto GB_DEFER_3(_defer_) = priv_defer_func([&](){code;})
+ #define defer(code) auto GB_DEFER_3(_defer_) = gb::priv_defer_func([&](){code;})
#endif
} // namespace gb
}
@@ -629,21 +631,21 @@ GB_DEF void *gb_memset(void *data, u8 byte_value, isize size);
typedef struct gbAtomic32 { i32 volatile value; } gbAtomic32;
typedef struct gbAtomic64 { i64 volatile value; } gbAtomic64;
-GB_DEF i32 gb_atomic32_load(gbAtomic32 const volatile *a);
-GB_DEF void gb_atomic32_store(gbAtomic32 volatile *a, i32 value);
-GB_DEF i32 gb_atomic32_compare_exchange_strong(gbAtomic32 volatile *a, i32 expected, i32 desired);
-GB_DEF i32 gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired);
-GB_DEF i32 gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand);
-GB_DEF i32 gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand);
-GB_DEF i32 gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand);
+GB_DEF i32 gb_load_atomic32(gbAtomic32 const volatile *a);
+GB_DEF void gb_store_atomic32(gbAtomic32 volatile *a, i32 value);
+GB_DEF i32 gb_compare_exchange_strong_atomic32(gbAtomic32 volatile *a, i32 expected, i32 desired);
+GB_DEF i32 gb_exchanged_atomic32(gbAtomic32 volatile *a, i32 desired);
+GB_DEF i32 gb_fetch_add_atomic32(gbAtomic32 volatile *a, i32 operand);
+GB_DEF i32 gb_fetch_and_atomic32(gbAtomic32 volatile *a, i32 operand);
+GB_DEF i32 gb_fetch_or_atomic32(gbAtomic32 volatile *a, i32 operand);
-GB_DEF i64 gb_atomic64_load(gbAtomic64 const volatile *a);
-GB_DEF void gb_atomic64_store(gbAtomic64 volatile *a, i64 value);
-GB_DEF i64 gb_atomic64_compare_exchange_strong(gbAtomic64 volatile *a, i64 expected, i64 desired);
-GB_DEF i64 gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired);
-GB_DEF i64 gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand);
-GB_DEF i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand);
-GB_DEF i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand);
+GB_DEF i64 gb_load_atomic64(gbAtomic64 const volatile *a);
+GB_DEF void gb_store_atomic64(gbAtomic64 volatile *a, i64 value);
+GB_DEF i64 gb_compare_exchange_strong_atomic64(gbAtomic64 volatile *a, i64 expected, i64 desired);
+GB_DEF i64 gb_exchanged_atomic64(gbAtomic64 volatile *a, i64 desired);
+GB_DEF i64 gb_fetch_add_atomic64(gbAtomic64 volatile *a, i64 operand);
+GB_DEF i64 gb_fetch_and_atomic64(gbAtomic64 volatile *a, i64 operand);
+GB_DEF i64 gb_fetch_or_atomic64(gbAtomic64 volatile *a, i64 operand);
typedef struct gbMutex {
@@ -654,11 +656,11 @@ typedef struct gbMutex {
#endif
} gbMutex;
-GB_DEF void gb_mutex_init(gbMutex *m);
-GB_DEF void gb_mutex_destroy(gbMutex *m);
-GB_DEF void gb_mutex_lock(gbMutex *m);
-GB_DEF b32 gb_mutex_try_lock(gbMutex *m);
-GB_DEF void gb_mutex_unlock(gbMutex *m);
+GB_DEF void gb_init_mutex(gbMutex *m);
+GB_DEF void gb_destroy_mutex(gbMutex *m);
+GB_DEF void gb_lock_mutex(gbMutex *m);
+GB_DEF b32 gb_try_lock_mutex(gbMutex *m);
+GB_DEF void gb_unlock_mutex(gbMutex *m);
// NOTE(bill): If you wanted a Scoped Mutex in C++, why not use the defer() construct?
// No need for a silly wrapper class
@@ -685,10 +687,10 @@ typedef struct gbSemaphore {
#endif
} gbSemaphore;
-GB_DEF void gb_semaphore_init(gbSemaphore *s);
-GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
-GB_DEF void gb_semaphore_post(gbSemaphore *s, i32 count);
-GB_DEF void gb_semaphore_wait(gbSemaphore *s);
+GB_DEF void gb_init_semaphore(gbSemaphore *s);
+GB_DEF void gb_destroy_semaphore(gbSemaphore *s);
+GB_DEF void gb_post_semaphore(gbSemaphore *s, i32 count);
+GB_DEF void gb_wait_semaphore(gbSemaphore *s);
@@ -711,13 +713,13 @@ typedef struct gbThread {
b32 is_running;
} gbThread;
-GB_DEF void gb_thread_init(gbThread *t);
-GB_DEF void gb_thread_destory(gbThread *t);
-GB_DEF void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data);
-GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
-GB_DEF void gb_thread_join(gbThread *t);
-GB_DEF b32 gb_thread_is_running(gbThread const *t);
-GB_DEF u32 gb_thread_current_id(void);
+GB_DEF void gb_init_thread(gbThread *t);
+GB_DEF void gb_destory_thread(gbThread *t);
+GB_DEF void gb_start_thread(gbThread *t, gbThreadProc *proc, void *data);
+GB_DEF void gb_start_thread_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
+GB_DEF void gb_join_thread(gbThread *t);
+GB_DEF b32 gb_is_thread_running(gbThread const *t);
+GB_DEF u32 gb_current_thread_id(void);
////////////////////////////////////////////////////////////////
//
@@ -825,14 +827,14 @@ typedef struct gbArena {
u32 temp_count;
} gbArena;
-GB_DEF void gb_arena_init_from_memory(gbArena *arena, void *start, isize size);
-GB_DEF void gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size);
-GB_DEF void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, isize size);
-GB_DEF void gb_arena_free(gbArena *arena);
+GB_DEF void gb_init_arena_from_memory(gbArena *arena, void *start, isize size);
+GB_DEF void gb_init_arena_from_allocator(gbArena *arena, gbAllocator backing, isize size);
+GB_DEF void gb_init_subarena(gbArena *arena, gbArena *parent_arena, isize size);
+GB_DEF void gb_free_arena(gbArena *arena);
GB_DEF isize gb_arena_alignment_of(gbArena *arena, isize alignment);
GB_DEF isize gb_arena_size_remaining(gbArena *arena, isize alignment);
-GB_DEF void gb_arena_check(gbArena *arena);
+GB_DEF void gb_check_arena(gbArena *arena);
GB_DEF gbAllocator gb_arena_allocator(gbArena *arena);
@@ -845,8 +847,8 @@ typedef struct gbTempArenaMemory {
isize original_count;
} gbTempArenaMemory;
-GB_DEF gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena);
-GB_DEF void gb_temp_arena_memory_end(gbTempArenaMemory tmp_mem);
+GB_DEF gbTempArenaMemory gb_begin_temp_arena_memory(gbArena *arena);
+GB_DEF void gb_end_temp_arena_memory(gbTempArenaMemory tmp_mem);
@@ -867,9 +869,9 @@ typedef struct gbPool {
isize total_size;
} gbPool;
-GB_DEF void gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size);
-GB_DEF void gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align);
-GB_DEF void gb_pool_free(gbPool *pool);
+GB_DEF void gb_init_pool(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size);
+GB_DEF void gb_init_pool_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align);
+GB_DEF void gb_free_pool(gbPool *pool);
GB_DEF gbAllocator gb_pool_allocator(gbPool *pool);
@@ -889,11 +891,11 @@ GB_DEF GB_ALLOCATOR_PROC(gb_pool_allocator_proc);
GB_DEF char gb_char_to_lower(char c);
GB_DEF char gb_char_to_upper(char c);
-GB_DEF b32 gb_char_is_space(char c);
-GB_DEF b32 gb_char_is_digit(char c);
-GB_DEF b32 gb_char_is_hex_digit(char c);
-GB_DEF b32 gb_char_is_alpha(char c);
-GB_DEF b32 gb_char_is_alphanumeric(char c);
+GB_DEF b32 gb_is_char_space(char c);
+GB_DEF b32 gb_is_char_digit(char c);
+GB_DEF b32 gb_is_char_hex_digit(char c);
+GB_DEF b32 gb_is_char_alpha(char c);
+GB_DEF b32 gb_is_char_alphanumeric(char c);
//
@@ -906,8 +908,8 @@ GB_DEF i32 gb_strcmp(char const *s1, char const *s2);
GB_DEF char * gb_strncpy(char *dest, char const *source, isize len);
GB_DEF i32 gb_strncmp(char const *s1, char const *s2, isize len);
-GB_DEF char const *gb_char_first_occurence(char const *s1, char c);
-GB_DEF char const *gb_char_last_occurence(char const *s1, char c);
+GB_DEF char const *gb_first_occurence_of_char(char const *s1, char c);
+GB_DEF char const *gb_last_occurence_of_char(char const *s1, char c);
GB_DEF void gb_cstr_concat(char *dest, isize dest_len,
char const *src_a, isize src_a_len,
@@ -946,31 +948,31 @@ typedef struct gbStringHeader {
#define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1)
-GB_DEF gbString gb_string_make(gbAllocator a, char const *str);
-GB_DEF gbString gb_string_make_length(gbAllocator a, void const *str, isize num_bytes);
-GB_DEF void gb_string_free(gbString str);
+GB_DEF gbString gb_make_string(gbAllocator a, char const *str);
+GB_DEF gbString gb_make_string_length(gbAllocator a, void const *str, isize num_bytes);
+GB_DEF void gb_free_string(gbString str);
-GB_DEF gbString gb_string_duplicate(gbAllocator a, gbString const str);
+GB_DEF gbString gb_duplicate_string(gbAllocator a, gbString const str);
GB_DEF isize gb_string_length(gbString const str);
GB_DEF isize gb_string_capacity(gbString const str);
GB_DEF isize gb_string_available_space(gbString const str);
-GB_DEF void gb_string_clear(gbString str);
+GB_DEF void gb_clear_string(gbString str);
-GB_DEF gbString gb_string_append_string(gbString str, gbString const other);
-GB_DEF gbString gb_string_append_string_length(gbString str, void const *other, isize num_bytes);
-GB_DEF gbString gb_string_append_cstring(gbString str, char const *other);
+GB_DEF gbString gb_append_string(gbString str, gbString const other);
+GB_DEF gbString gb_append_string_length(gbString str, void const *other, isize num_bytes);
+GB_DEF gbString gb_append_cstring(gbString str, char const *other);
-GB_DEF gbString gb_string_set(gbString str, char const *cstr);
+GB_DEF gbString gb_set_string(gbString str, char const *cstr);
-GB_DEF gbString gb_string_make_space_for(gbString str, isize add_len);
+GB_DEF gbString gb_make_space_for_string(gbString str, isize add_len);
GB_DEF isize gb_string_allocation_size(gbString const str);
-GB_DEF b32 gb_strings_are_equal(gbString const lhs, gbString const rhs);
+GB_DEF b32 gb_are_strings_equal(gbString const lhs, gbString const rhs);
-GB_DEF gbString gb_string_trim(gbString str, char const *cut_set);
-GB_DEF gbString gb_string_trim_space(gbString str); /* Whitespace ` \t\r\n\v\f` */
+GB_DEF gbString gb_trim_string(gbString str, char const *cut_set);
+GB_DEF gbString gb_trim_space_string(gbString str); /* Whitespace ` \t\r\n\v\f` */
@@ -988,26 +990,26 @@ GB_DEF gbString gb_string_trim_space(gbString str); /* Whitespace ` \t\r\n\v\f`
typedef gbBuffer(u8) gbByteBuffer;
-#define gb_buffer_init(x, allocator, cap) do { \
+#define gb_init_buffer(x, allocator, cap) do { \
void **data = cast(void **)&((x)->data); \
gb_zero_struct(x); \
(x)->capacity = (cap); \
*data = gb_alloc((allocator), (cap)*gb_size_of((x)->data[0])); \
} while (0)
-#define gb_buffer_free(x, allocator) do { gb_free(allocator, (x)->data); } while (0)
+#define gb_free_buffer(x, allocator) do { gb_free(allocator, (x)->data); } while (0)
-#define gb_buffer_append(x, item) do { (x)->data[(x)->count++] = item; } while (0)
+#define gb_append_buffer(x, item) do { (x)->data[(x)->count++] = item; } while (0)
-#define gb_buffer_appendv(x, items, item_count) do { \
+#define gb_appendv_buffer(x, items, item_count) do { \
GB_ASSERT(gb_size_of((items)[0]) == gb_size_of((x)->data[0])); \
GB_ASSERT((x)->count+item_count <= (x)->capacity); \
gb_memcopy((x)->data[a->count], (items), gb_size_of((x)->data[0])*(item_count)); \
(x)->count += (item_count); \
} while (0)
-#define gb_buffer_pop(x) do { GB_ASSERT((x)->count > 0); (x)->count--; } while (0)
-#define gb_buffer_clear(x) do { (x)->count = 0; } while (0)
+#define gb_pop_buffer(x) do { GB_ASSERT((x)->count > 0); (x)->count--; } while (0)
+#define gb_clear_buffer(x) do { (x)->count = 0; } while (0)
@@ -1031,74 +1033,74 @@ typedef gbBuffer(u8) gbByteBuffer;
typedef gbArray(void) gbVoidArray; // NOTE(bill): Useful for generic stuff
// Available Procedures for gbArray(Type)
-// gb_array_init
-// gb_array_free
-// gb_array_set_capacity
-// gb_array_grow
-// gb_array_append
-// gb_array_appendv
-// gb_array_pop
-// gb_array_clear
-// gb_array_resize
-// gb_array_reserve
+// gb_init_array
+// gb_free_array
+// gb_set_array_capacity
+// gb_grow_array
+// gb_append_array
+// gb_appendv_array
+// gb_pop_array
+// gb_clear_array
+// gb_resize_array
+// gb_reserve_array
//
-#define gb_array_init(x, allocator_) do { gb_zero_struct(x); (x)->allocator = allocator_; } while (0)
+#define gb_init_array(x, allocator_) do { gb_zero_struct(x); (x)->allocator = allocator_; } while (0)
-#define gb_array_free(x) do { \
+#define gb_free_array(x) do { \
if ((x)->allocator.proc) { \
gbAllocator a = (x)->allocator; \
gb_free(a, (x)->data); \
- gb_array_init((x), a); \
+ gb_init_array((x), a); \
} \
} while (0)
-#define gb_array_set_capacity(array, capacity) gb__array_set_capacity((array), (capacity), gb_size_of((array)->data[0]))
+#define gb_set_array_capacity(array, capacity) gb__set_array_capacity((array), (capacity), gb_size_of((array)->data[0]))
// NOTE(bill): Do not use the thing below directly, use the macro
-GB_DEF void gb__array_set_capacity(void *array, isize capacity, isize element_size);
+GB_DEF void gb__set_array_capacity(void *array, isize capacity, isize element_size);
#ifndef GB_ARRAY_GROW_FORMULA
#define GB_ARRAY_GROW_FORMULA(x) (2*(x) + 8)
#endif
// TODO(bill): Decide on a decent growing formula for gbArray
-#define gb_array_grow(x, min_capacity) do { \
+#define gb_grow_array(x, min_capacity) do { \
isize capacity = GB_ARRAY_GROW_FORMULA((x)->capacity); \
if (capacity < (min_capacity)) \
capacity = (min_capacity); \
- gb_array_set_capacity(x, capacity); \
+ gb_set_array_capacity(x, capacity); \
} while (0)
-#define gb_array_append(x, item) do { \
+#define gb_append_array(x, item) do { \
if ((x)->capacity < (x)->count+1) \
- gb_array_grow(x, 0); \
+ gb_grow_array(x, 0); \
(x)->data[(x)->count++] = (item); \
} while (0)
-#define gb_array_appendv(x, items, item_count) do { \
+#define gb_appendv_array(x, items, item_count) do { \
GB_ASSERT(gb_size_of((items)[0]) == gb_size_of((x)->data[0])); \
if ((x)->capacity < (x)->count+(item_count)) \
- gb_array_grow(x, (x)->count+(item_count)); \
+ gb_grow_array(x, (x)->count+(item_count)); \
gb_memcopy((x)->data[(x)->count], (items), gb_size_of((x)->data[0])*(item_count)); \
(x)->count += (item_count); \
} while (0)
-#define gb_array_pop(x) do { GB_ASSERT((x)->count > 0); (x)->count--; } while (0)
-#define gb_array_clear(x) do { (x)->count = 0; } while (0)
+#define gb_pop_array(x) do { GB_ASSERT((x)->count > 0); (x)->count--; } while (0)
+#define gb_clear_array(x) do { (x)->count = 0; } while (0)
-#define gb_array_resize(x, count) do { \
+#define gb_resize_array(x, count) do { \
if ((x)->capacity < (count)) \
- gb_array_grow(x, count); \
+ gb_grow_array(x, count); \
(x)->count = (count); \
} while (0)
-#define gb_array_reserve(x, new_capacity) do { \
+#define gb_reserve_array(x, new_capacity) do { \
if ((x)->capacity < (new_capacity)) \
- gb_array_set_capacity(x, new_capacity); \
+ gb_set_array_capacity(x, new_capacity); \
} while (0)
@@ -1113,82 +1115,6 @@ GB_DEF void gb__array_set_capacity(void *array, isize capacity, isize element_si
////////////////////////////////////////////////////////////////
//
-//
-// Hash_Table (POD Types)
-//
-//
-
-#if 0
-// TODO(bill): Hash Table and make it decent!!!
-
-// NOTE(bill): All keys are u64
-#ifndef GB_HASH_TABLE_TYPE
-#define GB_HASH_TABLE_TYPE
-
-typedef struct gbHashTableEntry {
- u64 key;
- isize value;
- isize next;
-} gbHashTableEntry;
-
-#define GB_HASH_TABLE_HEADER \
- gbArray(isize) hashes; \
- gbArray(gbHashTableEntry) entries \
-
-typedef struct gbHashTableHeader {
- GB_HASH_TABLE_HEADER;
-} gbHashTableHeader;
-
-#define gbHashTable(Type) struct { \
- GB_HASH_TABLE_HEADER; \
- gbArray(Type) data; \
-}
-
-typedef gbHashTable(void) gbHashTableVoid; // Generic Type
-
-#define gb_hash_table_init(h, allocator) do { \
- gb_array_init((h)->hashes, allocator); \
- gb_array_init((h)->entries, allocator); \
- gb_array_init((h)->data, allocator); \
-} while (0)
-
-#define gb_hash_table_free(h) do { \
- gb_free(&(h)->hashes); \
- gb_free(&(h)->entries); \
- gb_free(&(h)->data); \
-} while (0)
-
-#define gb_hash_table_header(h) (cast(gbHashTableHeader *)(h))
-
-
-// TODO(bill): Should the use have to pass the Hash Table and their array?
-
-
-
-
-/* TODO(bill): Hash_Table Procs
- gb_hash_table_init(h, allocator)
- gb_hash_table_free(h)
-
- gb_hash_table_has(h, key) // Return false/true
- gb_hash_table_get(h, key) // Return entries index
- gb_hash_table_set(h, key, value)
- gb_hash_table_remove(h, key)
- gb_hash_table_reserve(h, capacity)
- gb_hash_table_clear(h)
-
-*/
-
-
-
-#endif
-
-#endif /* GB_HASH_TABLE_TYPE */
-
-
-
-////////////////////////////////////////////////////////////////
-//
// File Handling
//
//
@@ -1214,19 +1140,19 @@ typedef struct gbFileContents {
} gbFileContents;
-GB_DEF b32 gb_file_create(gbFile *file, char const *filepath, ...); // TODO(bill): Give file permissions
-GB_DEF b32 gb_file_open(gbFile *file, char const *filepath, ...);
-GB_DEF b32 gb_file_close(gbFile *file);
+GB_DEF b32 gb_create_file(gbFile *file, char const *filepath, ...); // TODO(bill): Give file permissions
+GB_DEF b32 gb_open_file(gbFile *file, char const *filepath, ...);
+GB_DEF b32 gb_close_file(gbFile *file);
GB_DEF b32 gb_file_read_at(gbFile *file, void *buffer, isize size, i64 offset);
GB_DEF b32 gb_file_write_at(gbFile *file, void const *buffer, isize size, i64 offset);
GB_DEF i64 gb_file_size(gbFile *file);
-GB_DEF b32 gb_file_has_changed(gbFile *file);
+GB_DEF b32 gb_has_file_changed(gbFile *file);
GB_DEF gbFileTime gb_file_last_write_time(char const *filepath, ...);
-GB_DEF b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists);
-GB_DEF b32 gb_file_move(char const *existing_filename, char const *new_filename);
+GB_DEF b32 gb_copy_file(char const *existing_filename, char const *new_filename, b32 fail_if_exists);
+GB_DEF b32 gb_move_file(char const *existing_filename, char const *new_filename);
GB_DEF gbFileContents gb_read_entire_file_contents(gbAllocator a, b32 zero_terminate, char const *filepath, ...);
@@ -1240,9 +1166,9 @@ GB_DEF gbFileContents gb_read_entire_file_contents(gbAllocator a, b32 zero_termi
#endif
#endif
-GB_DEF b32 gb_path_is_absolute(char const *path);
-GB_DEF b32 gb_path_is_relative(char const *path);
-GB_DEF b32 gb_path_is_root(char const *path);
+GB_DEF b32 gb_is_path_absolute(char const *path);
+GB_DEF b32 gb_is_path_relative(char const *path);
+GB_DEF b32 gb_is_path_root(char const *path);
GB_DEF char const *gb_path_base_name(char const *path);
GB_DEF char const *gb_path_extension(char const *path);
@@ -1259,8 +1185,8 @@ GB_DEF void gb_exit(u32 code);
typedef void *gbDllHandle;
typedef void (*gbDllProc)(void);
-GB_DEF gbDllHandle gb_dll_load(char const *filepath, ...);
-GB_DEF void gb_dll_unload(gbDllHandle dll);
+GB_DEF gbDllHandle gb_load_dll(char const *filepath, ...);
+GB_DEF void gb_unload_dll(gbDllHandle dll);
GB_DEF gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name);
@@ -1327,6 +1253,39 @@ gb_global gbColour const GB_COLOUR_BLUE = {0xffff0000};
gb_global gbColour const GB_COLOUR_VIOLET = {0xffff007f};
gb_global gbColour const GB_COLOUR_MAGENTA = {0xffff00ff};
+////////////////////////////////////////////////////////////////
+//
+// Window Management
+//
+//
+
+#if 0
+
+#ifndef GB_MAX_WINDOW_TITLE_LENGTH
+#define GB_MAX_WINDOW_TITLE_LENGTH 256
+#endif
+
+
+typedef struct gbPlatformData {
+ void *native_display_type;
+ void *native_window_handle;
+ void *context;
+ void *back_buffer;
+ void *back_buffer_depth_stencil;
+} gbPlatformData;
+
+
+typedef struct gbWindow {
+ gbPlatformData platform_data;
+ i32 x, y;
+ i32 width, height;
+ char title[GB_MAX_WINDOW_TITLE_LENGTH];
+ b32 fullscreen;
+ b32 active;
+} gbWindow;
+
+#endif
+
#if defined(__cplusplus)
@@ -1563,49 +1522,49 @@ gb_alloc_cstring(gbAllocator a, char const *str)
#if defined(_MSC_VER)
gb_inline i32
-gb_atomic32_load(gbAtomic32 const volatile *a)
+gb_load_atomic32(gbAtomic32 const volatile *a)
{
return a->value;
}
gb_inline void
-gb_atomic32_store(gbAtomic32 volatile *a, i32 value)
+gb_store_atomic32(gbAtomic32 volatile *a, i32 value)
{
a->value = value;
}
gb_inline i32
-gb_atomic32_compare_exchange_strong(gbAtomic32 volatile *a, i32 expected, i32 desired)
+gb_compare_exchange_strong_atomic32(gbAtomic32 volatile *a, i32 expected, i32 desired)
{
return _InterlockedCompareExchange(cast(long volatile *)a, desired, expected);
}
gb_inline i32
-gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired)
+gb_exchanged_atomic32(gbAtomic32 volatile *a, i32 desired)
{
return _InterlockedExchange(cast(long volatile *)a, desired);
}
gb_inline i32
-gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand)
+gb_fetch_add_atomic32(gbAtomic32 volatile *a, i32 operand)
{
return _InterlockedExchangeAdd(cast(long volatile *)a, operand);
}
gb_inline i32
-gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand)
+gb_fetch_and_atomic32(gbAtomic32 volatile *a, i32 operand)
{
return _InterlockedAnd(cast(long volatile *)a, operand);
}
gb_inline i32
-gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand)
+gb_fetch_or_atomic32(gbAtomic32 volatile *a, i32 operand)
{
return _InterlockedOr(cast(long volatile *)a, operand);
}
gb_inline i64
-gb_atomic64_load(gbAtomic64 const volatile *a)
+gb_load_atomic64(gbAtomic64 const volatile *a)
{
#if defined(GB_ARCH_64_BIT)
return a->value;
@@ -1625,7 +1584,7 @@ gb_atomic64_load(gbAtomic64 const volatile *a)
}
gb_inline void
-gb_atomic64_store(gbAtomic64 volatile *a, i64 value)
+gb_store_atomic64(gbAtomic64 volatile *a, i64 value)
{
#if defined(GB_ARCH_64_BIT)
a->value = value;
@@ -1643,13 +1602,13 @@ gb_atomic64_store(gbAtomic64 volatile *a, i64 value)
}
gb_inline i64
-gb_atomic64_compare_exchange_strong(gbAtomic64 volatile *a, i64 expected, i64 desired)
+gb_compare_exchange_strong_atomic64(gbAtomic64 volatile *a, i64 expected, i64 desired)
{
return _InterlockedCompareExchange64(cast(i64 volatile *)a, desired, expected);
}
gb_inline i64
-gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired)
+gb_exchanged_atomic64(gbAtomic64 volatile *a, i64 desired)
{
#if defined(GB_ARCH_64_BIT)
return _InterlockedExchange64(cast(i64 volatile *)a, desired);
@@ -1665,7 +1624,7 @@ gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired)
}
gb_inline i64
-gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand)
+gb_fetch_add_atomic64(gbAtomic64 volatile *a, i64 operand)
{
#if defined(GB_ARCH_64_BIT)
return _InterlockedExchangeAdd64(cast(i64 volatile *)a, operand);
@@ -1681,7 +1640,7 @@ gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand)
}
gb_inline i64
-gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand)
+gb_fetch_and_atomic64(gbAtomic64 volatile *a, i64 operand)
{
#if defined(GB_ARCH_64_BIT)
return _InterlockedAnd64(cast(i64 volatile *)a, operand);
@@ -1697,7 +1656,7 @@ gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand)
}
gb_inline i64
-gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand)
+gb_fetch_or_atomic64(gbAtomic64 volatile *a, i64 operand)
{
#if defined(GB_ARCH_64_BIT)
return _InterlockedAnd64(cast(i64 volatile *)a, operand);
@@ -1720,38 +1679,38 @@ gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand)
-gb_inline void gb_mutex_init(gbMutex *m) { m->win32_handle = CreateMutex(0, false, 0); }
-gb_inline void gb_mutex_destroy(gbMutex *m) { CloseHandle(m->win32_handle); }
-gb_inline void gb_mutex_lock(gbMutex *m) { WaitForSingleObject(m->win32_handle, INFINITE); }
-gb_inline b32 gb_mutex_try_lock(gbMutex *m) { return WaitForSingleObject(m->win32_handle, 0) == WAIT_OBJECT_0; }
-gb_inline void gb_mutex_unlock(gbMutex *m) { ReleaseMutex(m->win32_handle); }
+gb_inline void gb_init_mutex(gbMutex *m) { m->win32_handle = CreateMutex(0, false, 0); }
+gb_inline void gb_destroy_mutex(gbMutex *m) { CloseHandle(m->win32_handle); }
+gb_inline void gb_lock_mutex(gbMutex *m) { WaitForSingleObject(m->win32_handle, INFINITE); }
+gb_inline b32 gb_try_lock_mutex(gbMutex *m) { return WaitForSingleObject(m->win32_handle, 0) == WAIT_OBJECT_0; }
+gb_inline void gb_unlock_mutex(gbMutex *m) { ReleaseMutex(m->win32_handle); }
gb_inline void
-gb_semaphore_init(gbSemaphore *s)
+gb_init_semaphore(gbSemaphore *s)
{
s->win32_handle = CreateSemaphore(NULL, 0, I32_MAX, NULL);
GB_ASSERT_MSG(s->win32_handle != NULL, "CreateSemaphore: GetLastError = %d", GetLastError());
}
gb_inline void
-gb_semaphore_destroy(gbSemaphore *s)
+gb_destroy_semaphore(gbSemaphore *s)
{
BOOL err = CloseHandle(s->win32_handle);
GB_ASSERT_MSG(err != 0, "CloseHandle: GetLastError = %d", GetLastError());
}
gb_inline void
-gb_semaphore_post(gbSemaphore *s, i32 count)
+gb_post_semaphore(gbSemaphore *s, i32 count)
{
BOOL err = ReleaseSemaphore(s->win32_handle, count, NULL);
GB_ASSERT_MSG(err != 0, "ReleaseSemaphore: GetLastError = %d", GetLastError());
}
gb_inline void
-gb_semaphore_wait(gbSemaphore *s)
+gb_wait_semaphore(gbSemaphore *s)
{
DWORD result = WaitForSingleObject(s->win32_handle, INFINITE);
GB_ASSERT_MSG(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError = %d", GetLastError());
@@ -1759,38 +1718,38 @@ gb_semaphore_wait(gbSemaphore *s)
void
-gb_thread_init(gbThread *t)
+gb_init_thread(gbThread *t)
{
gb_zero_struct(t);
t->win32_handle = INVALID_HANDLE_VALUE;
- gb_semaphore_init(&t->semaphore);
+ gb_init_semaphore(&t->semaphore);
}
void
-gb_thread_destory(gbThread *t)
+gb_destory_thread(gbThread *t)
{
- if (t->is_running) gb_thread_join(t);
- gb_semaphore_destroy(&t->semaphore);
+ if (t->is_running) gb_join_thread(t);
+ gb_destroy_semaphore(&t->semaphore);
}
gb_internal void
-gb__thread_run(gbThread *t)
+gb__run_thread(gbThread *t)
{
- gb_semaphore_post(&t->semaphore, 1);
+ gb_post_semaphore(&t->semaphore, 1);
t->proc(t->data);
}
#if defined(GB_SYSTEM_WINDOWS)
- gb_internal DWORD WINAPI gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return 0; }
+ gb_internal DWORD WINAPI gb__thread_proc(void *arg) { gb__run_thread(cast(gbThread *)arg); return 0; }
#else
- gb_internal void *gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return NULL; }
+ gb_internal void *gb__thread_proc(void *arg) { gb__run_thread(cast(gbThread *)arg); return NULL; }
#endif
-gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data) { gb_thread_start_with_stack(t, proc, data, 0); }
+gb_inline void gb_start_thread(gbThread *t, gbThreadProc *proc, void *data) { gb_start_thread_with_stack(t, proc, data, 0); }
gb_inline void
-gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size)
+gb_start_thread_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size)
{
GB_ASSERT(!t->is_running);
GB_ASSERT(proc != NULL);
@@ -1802,11 +1761,11 @@ gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize st
GB_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError = %d", GetLastError());
t->is_running = true;
- gb_semaphore_wait(&t->semaphore);
+ gb_wait_semaphore(&t->semaphore);
}
gb_inline void
-gb_thread_join(gbThread *t)
+gb_join_thread(gbThread *t)
{
if (!t->is_running) return;
@@ -1816,10 +1775,10 @@ gb_thread_join(gbThread *t)
t->is_running = false;
}
-gb_inline b32 gb_thread_is_running(gbThread const *t) { return t->is_running != 0; }
+gb_inline b32 gb_is_thread_running(gbThread const *t) { return t->is_running != 0; }
gb_inline u32
-gb_thread_current_id(void)
+gb_current_thread_id(void)
{
u32 thread_id;
#if defined(GB_SYSTEM_WINDOWS)
@@ -1901,7 +1860,7 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc)
gb_inline void
-gb_arena_init_from_memory(gbArena *arena, void *start, isize size)
+gb_init_arena_from_memory(gbArena *arena, void *start, isize size)
{
arena->backing.proc = NULL;
arena->backing.data = NULL;
@@ -1912,7 +1871,7 @@ gb_arena_init_from_memory(gbArena *arena, void *start, isize size)
}
gb_inline void
-gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size)
+gb_init_arena_from_allocator(gbArena *arena, gbAllocator backing, isize size)
{
arena->backing = backing;
arena->physical_start = gb_alloc(backing, size); // NOTE(bill): Uses default alignment
@@ -1921,11 +1880,11 @@ gb_arena_init_from_allocator(gbArena *arena, gbAllocator backing, isize size)
arena->temp_count = 0;
}
-gb_inline void gb_arena_init_subarena(gbArena *arena, gbArena *parent_arena, isize size) { gb_arena_init_from_allocator(arena, gb_arena_allocator(parent_arena), size); }
+gb_inline void gb_init_subarena(gbArena *arena, gbArena *parent_arena, isize size) { gb_init_arena_from_allocator(arena, gb_arena_allocator(parent_arena), size); }
gb_inline void
-gb_arena_free(gbArena *arena)
+gb_free_arena(gbArena *arena)
{
if (arena->backing.proc) {
gb_free(arena->backing, arena->physical_start);
@@ -1956,7 +1915,7 @@ gb_arena_size_remaining(gbArena *arena, isize alignment)
return result;
}
-gb_inline void gb_arena_check(gbArena *arena) { GB_ASSERT(arena->temp_count == 0); }
+gb_inline void gb_check_arena(gbArena *arena) { GB_ASSERT(arena->temp_count == 0); }
@@ -2029,7 +1988,7 @@ GB_ALLOCATOR_PROC(gb_arena_allocator_proc)
gb_inline gbTempArenaMemory
-gb_temp_arena_memory_begin(gbArena *arena)
+gb_begin_temp_arena_memory(gbArena *arena)
{
gbTempArenaMemory tmp;
tmp.arena = arena;
@@ -2039,7 +1998,7 @@ gb_temp_arena_memory_begin(gbArena *arena)
}
gb_inline void
-gb_temp_arena_memory_end(gbTempArenaMemory tmp)
+gb_end_temp_arena_memory(gbTempArenaMemory tmp)
{
GB_ASSERT(tmp.arena->total_allocated >= tmp.original_count);
GB_ASSERT(tmp.arena->temp_count > 0);
@@ -2051,13 +2010,13 @@ gb_temp_arena_memory_end(gbTempArenaMemory tmp)
gb_inline void
-gb_pool_init(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size)
+gb_init_pool(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size)
{
- gb_pool_init_align(pool, backing, num_blocks, block_size, GB_DEFAULT_MEMORY_ALIGNMENT);
+ gb_init_pool_align(pool, backing, num_blocks, block_size, GB_DEFAULT_MEMORY_ALIGNMENT);
}
void
-gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align)
+gb_init_pool_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize block_size, isize block_align)
{
isize actual_block_size, pool_size, block_index;
void *data, *curr;
@@ -2090,7 +2049,7 @@ gb_pool_init_align(gbPool *pool, gbAllocator backing, isize num_blocks, isize bl
}
gb_inline void
-gb_pool_free(gbPool *pool)
+gb_free_pool(gbPool *pool)
{
if (pool->backing.proc) {
gb_free(pool->backing, pool->physical_start);
@@ -2174,7 +2133,7 @@ gb_char_to_upper(char c)
}
gb_inline b32
-gb_char_is_space(char c)
+gb_is_char_space(char c)
{
if (c == ' ' ||
c == '\t' ||
@@ -2187,7 +2146,7 @@ gb_char_is_space(char c)
}
gb_inline b32
-gb_char_is_digit(char c)
+gb_is_char_digit(char c)
{
if (c >= '0' && c <= '9')
return true;
@@ -2195,9 +2154,9 @@ gb_char_is_digit(char c)
}
gb_inline b32
-gb_char_is_hex_digit(char c)
+gb_is_char_hex_digit(char c)
{
- if (gb_char_is_digit(c) ||
+ if (gb_is_char_digit(c) ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'))
return true;
@@ -2205,7 +2164,7 @@ gb_char_is_hex_digit(char c)
}
gb_inline b32
-gb_char_is_alpha(char c)
+gb_is_char_alpha(char c)
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z'))
@@ -2214,9 +2173,9 @@ gb_char_is_alpha(char c)
}
gb_inline b32
-gb_char_is_alphanumeric(char c)
+gb_is_char_alphanumeric(char c)
{
- return gb_char_is_alpha(c) || gb_char_is_digit(c);
+ return gb_is_char_alpha(c) || gb_is_char_digit(c);
}
@@ -2297,7 +2256,7 @@ gb_strncmp(char const *s1, char const *s2, isize len)
gb_inline char const *
-gb_char_first_occurence(char const *s, char c)
+gb_first_occurence_of_char(char const *s, char c)
{
char ch = c;
for (; *s != ch; s++) {
@@ -2309,7 +2268,7 @@ gb_char_first_occurence(char const *s, char c)
gb_inline char const *
-gb_char_last_occurence(char const *s, char c)
+gb_last_occurence_of_char(char const *s, char c)
{
char const *result = NULL;
do {
@@ -2344,19 +2303,19 @@ gb_cstr_concat(char *dest, isize dest_len,
-gb_inline void gb__string_set_length(gbString str, isize len) { GB_STRING_HEADER(str)->length = len; }
-gb_inline void gb__string_set_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; }
+gb_inline void gb__set_string_length(gbString str, isize len) { GB_STRING_HEADER(str)->length = len; }
+gb_inline void gb__set_string_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; }
gb_inline gbString
-gb_string_make(gbAllocator a, char const *str)
+gb_make_string(gbAllocator a, char const *str)
{
isize len = str ? gb_strlen(str) : 0;
- return gb_string_make_length(a, str, len);
+ return gb_make_string_length(a, str, len);
}
gbString
-gb_string_make_length(gbAllocator a, void const *init_str, isize num_bytes)
+gb_make_string_length(gbAllocator a, void const *init_str, isize num_bytes)
{
isize header_size = gb_size_of(gbStringHeader);
void *ptr = gb_alloc(a, header_size + num_bytes + 1);
@@ -2380,7 +2339,7 @@ gb_string_make_length(gbAllocator a, void const *init_str, isize num_bytes)
}
gb_inline void
-gb_string_free(gbString str)
+gb_free_string(gbString str)
{
if (str) {
gbStringHeader *header = GB_STRING_HEADER(str);
@@ -2389,7 +2348,7 @@ gb_string_free(gbString str)
}
-gb_inline gbString gb_string_duplicate(gbAllocator a, gbString const str) { return gb_string_make_length(a, str, gb_string_length(str)); }
+gb_inline gbString gb_string_duplicate(gbAllocator a, gbString const str) { return gb_make_string_length(a, str, gb_string_length(str)); }
gb_inline isize gb_string_length(gbString const str) { return GB_STRING_HEADER(str)->length; }
gb_inline isize gb_string_capacity(gbString const str) { return GB_STRING_HEADER(str)->capacity; }
@@ -2404,46 +2363,46 @@ gb_string_available_space(gbString const str)
}
-gb_inline void gb_string_clear(gbString str) { gb__string_set_length(str, 0); str[0] = '\0'; }
+gb_inline void gb_clear_string(gbString str) { gb__set_string_length(str, 0); str[0] = '\0'; }
-gb_inline gbString gb_string_append_string(gbString str, gbString const other) { return gb_string_append_string_length(str, other, gb_string_length(other)); }
+gb_inline gbString gb_append_string(gbString str, gbString const other) { return gb_append_string_length(str, other, gb_string_length(other)); }
gbString
-gb_string_append_string_length(gbString str, void const *other, isize other_len)
+gb_append_string_length(gbString str, void const *other, isize other_len)
{
isize curr_len = gb_string_length(str);
- str = gb_string_make_space_for(str, other_len);
+ str = gb_make_space_for_string(str, other_len);
if (str == NULL)
return NULL;
gb_memcopy(str + curr_len, other, other_len);
str[curr_len + other_len] = '\0';
- gb__string_set_length(str, curr_len + other_len);
+ gb__set_string_length(str, curr_len + other_len);
return str;
}
gb_inline gbString
-gb_string_append_cstring(gbString str, char const *other)
+gb_append_cstring(gbString str, char const *other)
{
- return gb_string_append_string_length(str, other, cast(isize)strlen(other));
+ return gb_append_string_length(str, other, cast(isize)strlen(other));
}
gbString
-gb_string_set(gbString str, char const *cstr)
+gb_set_string(gbString str, char const *cstr)
{
isize len = gb_strlen(cstr);
if (gb_string_capacity(str) < len) {
- str = gb_string_make_space_for(str, len - gb_string_length(str));
+ str = gb_make_space_for_string(str, len - gb_string_length(str));
if (str == NULL)
return NULL;
}
gb_memcopy(str, cstr, len);
str[len] = '\0';
- gb__string_set_length(str, len);
+ gb__set_string_length(str, len);
return str;
}
@@ -2451,7 +2410,7 @@ gb_string_set(gbString str, char const *cstr)
gbString
-gb_string_make_space_for(gbString str, isize add_len)
+gb_make_space_for_string(gbString str, isize add_len)
{
isize available = gb_string_available_space(str);
@@ -2468,7 +2427,7 @@ gb_string_make_space_for(gbString str, isize add_len)
if (new_ptr == NULL) return NULL;
str = cast(char *)(GB_STRING_HEADER(new_ptr) + 1);
- gb__string_set_capacity(str, new_len);
+ gb__set_string_capacity(str, new_len);
return str;
}
@@ -2483,7 +2442,7 @@ gb_string_allocation_size(gbString const str)
gb_inline b32
-gb_strings_are_equal(gbString const lhs, gbString const rhs)
+gb_are_strings_equal(gbString const lhs, gbString const rhs)
{
isize lhs_len, rhs_len, i;
lhs_len = gb_string_length(lhs);
@@ -2501,7 +2460,7 @@ gb_strings_are_equal(gbString const lhs, gbString const rhs)
gbString
-gb_string_trim(gbString str, char const *cut_set)
+gb_trim_string(gbString str, char const *cut_set)
{
char *start, *end, *start_pos, *end_pos;
isize len;
@@ -2509,9 +2468,9 @@ gb_string_trim(gbString str, char const *cut_set)
start_pos = start = str;
end_pos = end = str + gb_string_length(str) - 1;
- while (start_pos <= end && gb_char_first_occurence(cut_set, *start_pos))
+ while (start_pos <= end && gb_first_occurence_of_char(cut_set, *start_pos))
start_pos++;
- while (end_pos > start_pos && gb_char_first_occurence(cut_set, *end_pos))
+ while (end_pos > start_pos && gb_first_occurence_of_char(cut_set, *end_pos))
end_pos--;
len = cast(isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
@@ -2520,12 +2479,12 @@ gb_string_trim(gbString str, char const *cut_set)
gb_memmove(str, start_pos, len);
str[len] = '\0';
- gb__string_set_length(str, len);
+ gb__set_string_length(str, len);
return str;
}
-gb_inline gbString gb_string_trim_space(gbString str) { return gb_string_trim(str, " \t\r\n\v\f"); }
+gb_inline gbString gb_trim_space_string(gbString str) { return gb_trim_string(str, " \t\r\n\v\f"); }
@@ -2649,7 +2608,7 @@ gb_utf16_to_utf8(char *buffer, char16 *str, isize len)
gb_no_inline void
-gb__array_set_capacity(void *array_, isize capacity, isize element_size)
+gb__set_array_capacity(void *array_, isize capacity, isize element_size)
{
// NOTE(bill): I know this is unsafe so don't call this function directly
gbVoidArray *a = cast(gbVoidArray *)array_;
@@ -2665,7 +2624,7 @@ gb__array_set_capacity(void *array_, isize capacity, isize element_size)
isize new_capacity = GB_ARRAY_GROW_FORMULA(a->capacity);
if (new_capacity < capacity)
new_capacity = capacity;
- gb__array_set_capacity(a, new_capacity, element_size);
+ gb__set_array_capacity(a, new_capacity, element_size);
}
a->count = capacity;
}
@@ -2691,7 +2650,7 @@ gb__array_set_capacity(void *array_, isize capacity, isize element_size)
//
b32
-gb_file_create(gbFile *file, char const *filepath, ...)
+gb_create_file(gbFile *file, char const *filepath, ...)
{
va_list va;
char *path;
@@ -2716,7 +2675,7 @@ gb_file_create(gbFile *file, char const *filepath, ...)
b32
-gb_file_open(gbFile *file, char const *filepath, ...)
+gb_open_file(gbFile *file, char const *filepath, ...)
{
va_list va;
char *path;
@@ -2739,7 +2698,7 @@ gb_file_open(gbFile *file, char const *filepath, ...)
}
gb_inline b32
-gb_file_close(gbFile *file)
+gb_close_file(gbFile *file)
{
b32 result = true;
if (file && file->handle)
@@ -2798,7 +2757,7 @@ gb_file_size(gbFile *file)
}
b32
-gb_file_has_changed(gbFile *file)
+gb_has_file_changed(gbFile *file)
{
b32 result = false;
gbFileTime last_write_time = gb_file_last_write_time(file->path);
@@ -2833,13 +2792,13 @@ gb_file_last_write_time(char const *filepath, ...)
}
gb_inline b32
-gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists)
+gb_copy_file(char const *existing_filename, char const *new_filename, b32 fail_if_exists)
{
return CopyFile(existing_filename, new_filename, fail_if_exists);
}
gb_inline b32
-gb_file_move(char const *existing_filename, char const *new_filename)
+gb_move_file(char const *existing_filename, char const *new_filename)
{
return MoveFile(existing_filename, new_filename);
}
@@ -2865,7 +2824,7 @@ gb_read_entire_file_contents(gbAllocator a, b32 zero_terminate, char const *file
path = gb_sprintf_va(filepath, va);
va_end(va);
- if (gb_file_open(&file, path)) {
+ if (gb_open_file(&file, path)) {
i64 file_size = gb_file_size(&file);
if (file_size > 0) {
result.data = gb_alloc(a, zero_terminate ? file_size+1 : file_size);
@@ -2876,7 +2835,7 @@ gb_read_entire_file_contents(gbAllocator a, b32 zero_terminate, char const *file
str[file_size] = '\0';
}
}
- gb_file_close(&file);
+ gb_close_file(&file);
}
return result;
@@ -2887,13 +2846,13 @@ gb_read_entire_file_contents(gbAllocator a, b32 zero_terminate, char const *file
gb_inline b32
-gb_path_is_absolute(char const *path)
+gb_is_path_absolute(char const *path)
{
b32 result = false;
GB_ASSERT_NOT_NULL(path);
#if defined(GB_SYSTEM_WINDOWS)
result == (gb_strlen(path) > 2) &&
- gb_char_is_alpha(path[0]) &&
+ gb_is_char_alpha(path[0]) &&
(path[1] == ':' && path[2] == GB_PATH_SEPARATOR);
#else
result = (gb_strlen(path) > 0 && path[0] == GB_PATH_SEPARATOR);
@@ -2901,17 +2860,17 @@ gb_path_is_absolute(char const *path)
return result;
}
-gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolute(path); }
+gb_inline b32 gb_is_path_relative(char const *path) { return !gb_is_path_absolute(path); }
gb_inline b32
-gb_path_is_root(char const *path)
+gb_is_path_root(char const *path)
{
b32 result = false;
GB_ASSERT_NOT_NULL(path);
#if defined(GB_SYSTEM_WINDOWS)
- result = gb_path_is_absolute(path) && gb_strlen(path) == 3;
+ result = gb_is_path_absolute(path) && gb_strlen(path) == 3;
#else
- result = gb_path_is_absolute(path) && gb_strlen(path) == 1;
+ result = gb_is_path_absolute(path) && gb_strlen(path) == 1;
#endif
return result;
}
@@ -2921,7 +2880,7 @@ gb_path_base_name(char const *path)
{
char const *ls;
GB_ASSERT_NOT_NULL(path);
- ls = gb_char_last_occurence(path, '/');
+ ls = gb_last_occurence_of_char(path, '/');
return (ls == NULL) ? path : ls+1;
}
@@ -2930,7 +2889,7 @@ gb_path_extension(char const *path)
{
char const *ld;
GB_ASSERT_NOT_NULL(path);
- ld = gb_char_last_occurence(path, '.');
+ ld = gb_last_occurence_of_char(path, '.');
return (ld == NULL) ? NULL : ld+1;
}
@@ -2950,7 +2909,7 @@ gb_inline void gb_exit(u32 code) { ExitProcess(code); }
#if defined(GB_SYSTEM_WINDOWS)
gbDllHandle
-gb_dll_load(char const *filepath, ...)
+gb_load_dll(char const *filepath, ...)
{
gb_local_persist char buffer[512];
va_list va;
@@ -2959,7 +2918,7 @@ gb_dll_load(char const *filepath, ...)
va_end(va);
return cast(gbDllHandle)LoadLibraryA(buffer);
}
-gb_inline void gb_dll_unload(gbDllHandle dll) { FreeLibrary(cast(HMODULE)dll); }
+gb_inline void gb_unload_dll(gbDllHandle dll) { FreeLibrary(cast(HMODULE)dll); }
gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)GetProcAddress(cast(HMODULE)dll, proc_name); }
#else
diff --git a/gb_gl.h b/gb_gl.h
new file mode 100644
index 0000000..7cb9b3a
--- /dev/null
+++ b/gb_gl.h
@@ -0,0 +1,1412 @@
+/* gb.h - v0.01 - OpenGL Helper Library - public domain
+ - no warranty implied; use at your own risk
+
+ This is a single header file with a bunch of useful stuff
+ for working with OpenGL
+
+===========================================================================
+ YOU MUST
+
+ #define GBGL_IMPLEMENTATION
+
+ in EXACTLY _one_ C or C++ file that includes this header, BEFORE the
+ include like this:
+
+ #define GBGL_IMPLEMENTATION
+ #include "gb_gl.h"
+
+ All other files should just #include "gb_gl.h" without #define
+
+ NOTE
+
+ This library REQUIRES "stb_image.h" for loading images from file
+ - You may need change the path
+ This library REQUIRES "gb.h" at this moment in time.
+ This library REQUIRES "gb_math.h" at this moment in time.
+
+===========================================================================
+
+Conventions used:
+ gbglTypesAreLikeThis (None core types)
+ gbgl_functions_and_variables_like_this
+ Prefer // Comments
+ Never use _t suffix for types (I think they are stupid...)
+
+
+Version History:
+ 0.01 - Initial Version
+
+LICENSE
+ This software is dual-licensed to the public domain and under the following
+ license: you are granted a perpetual, irrevocable license to copy, modify,
+ publish, and distribute this file as you see fit.
+
+WARNING
+ - This library is _highly_ experimental and features may not work as expected.
+ - This also means that many functions are not documented.
+
+CREDITS
+ Written by Ginger Bill
+
+*/
+
+#ifndef GBGL_INCLUDE_GB_GL_H
+#define GBGL_INCLUDE_GB_GL_H
+
+#ifndef GB_IMPLEMENTATION
+#include "gb.h"
+#endif
+
+#ifndef GB_MATH_IMPLEMENTATION
+#include "gb_math.h"
+#endif
+
+
+#ifndef STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+#endif
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#ifndef GBGL_DEF
+#define GBGL_DEF extern
+#endif
+
+
+#ifndef gbgl_malloc
+#define gbgl_malloc(sz) malloc(sz)
+#endif
+
+#ifndef gbgl_free
+#define gbgl_free(ptr) free(ptr)
+#endif
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Generic Stuff
+//
+//
+
+
+#ifndef GBGL_VERT_PTR_AA_GENERIC
+#define GBGL_VERT_PTR_AA_GENERIC
+// NOTE(bill) The "default" is just the f32 version
+#define gbgl_vert_ptr_aa(index, element_count, Type, var_name) \
+ gbgl_vert_ptr_aa_f32(index, element_count, Type, var_name)
+
+#define gbgl_vert_ptr_aa_f32(index, element_count, Type, var_name) do { \
+ glVertexAttribPointer(index, \
+ element_count, \
+ GL_FLOAT, \
+ false, \
+ gb_size_of(Type), \
+ (void const *)(gb_offset_of(Type, var_name))); \
+ glEnableVertexAttribArray(index); \
+} while (0)
+
+#define gbgl_vert_ptr_aa_u8(index, element_count, Type, var_name) do { \
+ glVertexAttribPointer(index, \
+ element_count, \
+ GL_UNSIGNED_BYTE, \
+ false, \
+ gb_size_of(Type), \
+ (void const *)(gb_offset_of(Type, var_name))); \
+ glEnableVertexAttribArray(index); \
+} while (0)
+
+#define gbgl_vert_ptr_aa_u8n(index, element_count, Type, var_name) do { \
+ glVertexAttribPointer(index, \
+ element_count, \
+ GL_UNSIGNED_BYTE, \
+ true, \
+ gb_size_of(Type), \
+ (void const *)(gb_offset_of(Type, var_name))); \
+ glEnableVertexAttribArray(index); \
+} while (0)
+
+#define gbgl_vert_ptr_aa_u32(index, element_count, Type, var_name) do { \
+ glVertexAttribIPointer(index, \
+ element_count, \
+ GL_UNSIGNED_INT, \
+ gb_size_of(Type), \
+ (void const *)(gb_offset_of(Type, var_name))); \
+ glEnableVertexAttribArray(index); \
+} while (0)
+
+#define gbgl_vert_ptr_aa_u16(index, element_count, Type, var_name) do { \
+ glVertexAttribIPointer(index, \
+ element_count, \
+ GL_UNSIGNED_SHORT, \
+ gb_size_of(Type), \
+ (void const *)(gb_offset_of(Type, var_name))); \
+ glEnableVertexAttribArray(index); \
+} while (0)
+
+#define gbgl_vert_ptr_aa_u16n(index, element_count, Type, var_name) do { \
+ glVertexAttribPointer(index, \
+ element_count, \
+ GL_UNSIGNED_SHORT, \
+ true, \
+ gb_size_of(Type), \
+ (void const *)(gb_offset_of(Type, var_name))); \
+ glEnableVertexAttribArray(index); \
+} while (0)
+
+#endif
+
+
+GBGL_DEF u32 gbgl_generate_sampler(u32 min_filter, u32 max_filter, u32 s_wrap, u32 t_wrap);
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Data Buffers
+//
+//
+
+
+typedef enum gbglBufferDataType {
+ GBGL_BDT_U8 = GL_UNSIGNED_BYTE,
+ GBGL_BDT_I8 = GL_BYTE,
+
+ GBGL_BDT_U16 = GL_UNSIGNED_SHORT,
+ GBGL_BDT_I16 = GL_SHORT,
+ GBGL_BDT_F16 = GL_HALF_FLOAT,
+
+ GBGL_BDT_U32 = GL_UNSIGNED_INT,
+ GBGL_BDT_I32 = GL_INT,
+ GBGL_BDT_F32 = GL_FLOAT,
+
+ GBGL_BDT_F8, // NOTE(bill): This is not a "real" OpenGL type but it is needed for internal format enums
+} gbglBufferDataType;
+
+
+// NOTE(bill) index+1 = channels count
+#if defined(GBGL_USE_SRGB_TEXTURE_FORMAT)
+i32 const GBGL_TEXTURE_FORMAT[4] = { GL_RED, GL_RG, GL_SRGB8, GL_SRGB8_ALPHA8 };
+#else
+i32 const GBGL_TEXTURE_FORMAT[4] = { GL_RED, GL_RG, GL_RGB, GL_RGBA };
+#endif
+
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_8[4] = { GL_R8, GL_RG8, GL_RGB8, GL_RGBA8 };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_16[4] = { GL_R16, GL_RG16, GL_RGB16, GL_RGBA16 };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_32[4] = { GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F };
+
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_U8[4] = { GL_R8UI, GL_RG8UI, GL_RGB8UI, GL_RGB8UI };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_I8[4] = { GL_R8I, GL_RG8I, GL_RGB8I, GL_RGB8I };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_F8[4] = { GL_R8, GL_RG8, GL_RGB8, GL_RGB8 };
+
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_U16[4] = { GL_R16UI, GL_RG16UI, GL_RGB16UI, GL_RGB16UI };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_I16[4] = { GL_R16I, GL_RG16I, GL_RGB16I, GL_RGB16I };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_F16[4] = { GL_R16F, GL_RG16F, GL_RGB16F, GL_RGB16F };
+
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_U32[4] = { GL_R32UI, GL_RG32UI, GL_RGB32UI, GL_RGBA32UI };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_I32[4] = { GL_R32I, GL_RG32I, GL_RGB32I, GL_RGBA32I };
+i32 const GBGL_INTERNAL_TEXTURE_FORMAT_F32[4] = { GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F };
+
+gb_inline i32
+gbgl__get_texture_format(gbglBufferDataType data_type, i32 channel_count)
+{
+ GB_ASSERT(channel_count >= 1 && channel_count <= 4);
+ switch (data_type) {
+ case GBGL_BDT_U8: return GBGL_INTERNAL_TEXTURE_FORMAT_U8[channel_count-1];
+ case GBGL_BDT_I8: return GBGL_INTERNAL_TEXTURE_FORMAT_I8[channel_count-1];
+ case GBGL_BDT_F8: return GBGL_INTERNAL_TEXTURE_FORMAT_F8[channel_count-1];
+ case GBGL_BDT_U16: return GBGL_INTERNAL_TEXTURE_FORMAT_U16[channel_count-1];
+ case GBGL_BDT_I16: return GBGL_INTERNAL_TEXTURE_FORMAT_I16[channel_count-1];
+ case GBGL_BDT_F16: return GBGL_INTERNAL_TEXTURE_FORMAT_F16[channel_count-1];
+ case GBGL_BDT_U32: return GBGL_INTERNAL_TEXTURE_FORMAT_U32[channel_count-1];
+ case GBGL_BDT_I32: return GBGL_INTERNAL_TEXTURE_FORMAT_I32[channel_count-1];
+ case GBGL_BDT_F32: return GBGL_INTERNAL_TEXTURE_FORMAT_F32[channel_count-1];
+ }
+ return GBGL_INTERNAL_TEXTURE_FORMAT_F32[4-1];
+}
+
+typedef struct gbglTBO {
+ u32 buffer_obj_handle;
+ u32 buffer_handle;
+} gbglTBO;
+
+// NOTE(bill): usage_hint == (GL_STATIC_DRAW, GL_STREAM_DRAW, GL_DYNAMIC_DRAW)
+GBGL_DEF u32 gbgl_make_vbo(void const *data, isize size, i32 usage_hint);
+GBGL_DEF u32 gbgl_make_ebo(void const *data, isize size, i32 usage_hint);
+GBGL_DEF gbglTBO gbgl_make_tbo(gbglBufferDataType data_type, i32 channel_count, void const *data, isize size, i32 usage_hint);
+
+GBGL_DEF void gbgl_vbo_copy(u32 vbo_handle, void *const data, isize size, isize offset);
+GBGL_DEF void gbgl_ebo_copy(u32 ebo_handle, void *const data, isize size, isize offset);
+GBGL_DEF void gbgl_tbo_copy(gbglTBO tbo, void *const data, isize size, isize offset);
+
+
+
+GBGL_DEF void gbgl_bind_vbo(u32 vbo_handle);
+GBGL_DEF void gbgl_bind_ebo(u32 ebo_handle);
+GBGL_DEF void gbgl_bind_tbo(gbglTBO tbo, i32 sampler_handle, i32 tex_unit);
+
+// NOTE(bill): access = GL_WRITE_ONLY, etc.
+GBGL_DEF void *gbgl_map_vbo(u32 vbo_handle, i32 access);
+GBGL_DEF void *gbgl_map_ebo(u32 ebo_handle, i32 access);
+GBGL_DEF void gbgl_unmap_vbo(void);
+GBGL_DEF void gbgl_unmap_ebo(void);
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Shader
+//
+//
+
+typedef enum gbglShaderType {
+ GBGL_SHADER_TYPE_VERTEX,
+ GBGL_SHADER_TYPE_FRAGMENT,
+ GBGL_SHADER_TYPE_GEOMETRY,
+
+ GBGL_SHADER_TYPE_COUNT,
+} gbglShaderType;
+
+i32 const GBGL_SHADER_TYPE[GBGL_SHADER_TYPE_COUNT] = {
+ GL_VERTEX_SHADER, /* GBGL_SHADER_TYPE_VERTEX */
+ GL_FRAGMENT_SHADER, /* GBGL_SHADER_TYPE_FRAGMENT */
+ GL_GEOMETRY_SHADER, /* GBGL_SHADER_TYPE_GEOMETRY */
+};
+
+typedef enum gbglShaderError {
+ GBGL_SHADER_ERROR_NONE,
+ GBGL_SHADER_ERROR_SHADER_COMPILE,
+ GBGL_SHADER_ERROR_LINKING,
+ GBGL_SHADER_ERROR_UNABLE_TO_READ_FILE,
+
+ GBGL_SHADER_ERROR_COUNT,
+} gbglShaderError;
+
+#ifndef GBGL_MAX_UNIFORM_COUNT
+#define GBGL_MAX_UNIFORM_COUNT 32
+#endif
+
+typedef struct gbglShader {
+ u32 shaders[GBGL_SHADER_TYPE_COUNT];
+ u32 program;
+
+ i32 uniform_locs[GBGL_MAX_UNIFORM_COUNT];
+ char *uniform_names[GBGL_MAX_UNIFORM_COUNT];
+ i32 uniform_count;
+
+ u32 type_flags;
+
+ gbFile files[GBGL_SHADER_TYPE_COUNT];
+
+ char base_name[64];
+} gbglShader;
+
+
+
+#ifndef GBGL_SHADER_FILE_EXTENSIONS_DEFINED
+#define GBGL_SHADER_FILE_EXTENSIONS_DEFINED
+gb_global char const *GBGL_SHADER_FILE_EXTENSIONS[GBGL_SHADER_TYPE_COUNT] = {".vs", ".fs", ".gs"};
+#endif
+
+
+GBGL_DEF gbglShaderError gbgl_load_shader_from_file (gbglShader *s, u32 type_bits, char const *filename, ...);
+GBGL_DEF gbglShaderError gbgl_load_shader_vf_from_source (gbglShader *s, char const *vert_source, char const *frag_source);
+GBGL_DEF gbglShaderError gbgl_load_shader_vfg_from_source(gbglShader *s, char const *vert_source, char const *frag_source, char const *geom_source);
+
+GBGL_DEF void gbgl_destroy_shader(gbglShader *shader);
+GBGL_DEF b32 gbgl_has_shader_changed(gbglShader *shader);
+GBGL_DEF b32 gbgl_reload_shader(gbglShader *shader); // TODO(bill): Return an error code?
+GBGL_DEF void gbgl_use_shader(gbglShader *shader);
+GBGL_DEF b32 gbgl_is_shader_in_use(gbglShader *shader);
+
+GBGL_DEF i32 gbgl_get_uniform(gbglShader *shader, char const *name);
+
+#ifndef GBGL_UNIFORM_SET
+#define GBGL_UNIFORM_SET
+
+#define gbgl_set_uniform_int(loc, i) glUniform1i(loc, i)
+#define gbgl_set_uniform_float(loc, f) glUniform1f(loc, f)
+#define gbgl_set_uniform_vec2(loc, v) glUniform2fv(loc, 1, &v.x)
+#define gbgl_set_uniform_vec3(loc, v) glUniform3fv(loc, 1, &v.x)
+#define gbgl_set_uniform_vec4(loc, v) glUniform4fv(loc, 1, &v.x)
+#define gbgl_set_uniform_mat4(loc, mat) glUniformMatrix4fv(loc, 1, false, mat)
+#define gbgl_set_uniform_mat4_count(loc, mat, count) glUniformMatrix4fv(loc, count, false, mat)
+
+#endif
+
+////////////////////////////////////////////////////////////////
+//
+// Texture
+//
+//
+
+typedef enum gbglTextureType {
+ GBGL_TEXTURE_TYPE_2D,
+ GBGL_TEXTURE_TYPE_CUBE_MAP,
+
+ GBGL_TEXTURE_TYPE_COUNT,
+} gbglTextureType;
+
+gb_global i32 const GBGL_TEXTURE_TYPE[GBGL_TEXTURE_TYPE_COUNT] = {
+ GL_TEXTURE_2D, /* GBGL_TEXTURE_TYPE_2D */
+ GL_TEXTURE_CUBE_MAP, /* GBGL_TEXTURE_TYPE_CUBE_MAP */
+};
+
+
+typedef struct gbglTexture {
+ i32 width, height;
+ i32 channel_count;
+ gbglBufferDataType data_type;
+ gbglTextureType type;
+ u32 handle;
+} gbglTexture;
+
+GBGL_DEF b32 gbgl_load_texture2d_from_file(gbglTexture *texture, b32 flip_vertically, char const *filename, ...);
+GBGL_DEF b32 gbgl_load_texture2d_from_memory(gbglTexture *texture, void const *data, i32 width, i32 height, i32 channel_count);
+GBGL_DEF b32 gbgl_init_texture2d_coloured(gbglTexture *texture, gbColour colour);
+GBGL_DEF void gbgl_destroy_texture(gbglTexture *texture);
+
+GBGL_DEF void gbgl_bind_texture2d(gbglTexture const *texture, u32 position, u32 sampler);
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Render Buffer
+//
+//
+
+// TODO(bill): Record depth and stencil and numerous colour attachments
+
+typedef struct gbglRenderBuffer {
+ i32 width, height;
+ i32 channel_count;
+ u32 handle;
+
+ gbglTexture colour_texture;
+} gbglRenderBuffer;
+
+#define GBGL_MAX_RENDER_COLOUR_BUFFERS 16
+gb_global u32 const GBGL_COLOUR_BUFFER_ATTACHMENTS[GBGL_MAX_RENDER_COLOUR_BUFFERS] = {
+ GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_COLOR_ATTACHMENT2,
+ GL_COLOR_ATTACHMENT3,
+ GL_COLOR_ATTACHMENT4,
+ GL_COLOR_ATTACHMENT5,
+ GL_COLOR_ATTACHMENT6,
+ GL_COLOR_ATTACHMENT7,
+ GL_COLOR_ATTACHMENT8,
+ GL_COLOR_ATTACHMENT9,
+ GL_COLOR_ATTACHMENT10,
+ GL_COLOR_ATTACHMENT11,
+ GL_COLOR_ATTACHMENT12,
+ GL_COLOR_ATTACHMENT13,
+ GL_COLOR_ATTACHMENT14,
+ GL_COLOR_ATTACHMENT15,
+};
+
+
+GBGL_DEF b32 gbgl_init_render_buffer(gbglRenderBuffer *rb, i32 width, i32 height, i32 channel_count);
+GBGL_DEF void gbgl_destroy_render_buffer(gbglRenderBuffer *rb);
+GBGL_DEF void gbgl_render_to_buffer(gbglRenderBuffer const *rb);
+GBGL_DEF void gbgl_render_to_screen(i32 width, i32 height);
+
+////////////////////////////////////////////////////////////////
+//
+// Basic State
+//
+//
+
+
+typedef struct gbglBasicVertex {
+ f32 x, y;
+ f32 u, v;
+} gbglBasicVertex;
+
+
+#ifndef GBGL_BS_MAX_VERTEX_COUNT
+#define GBGL_BS_MAX_VERTEX_COUNT 32
+#endif
+
+
+#ifndef GBGL_BS_MAX_INDEX_COUNT
+#define GBGL_BS_MAX_INDEX_COUNT 6
+#endif
+
+typedef struct gbglBasicState {
+ gbglBasicVertex vertices[GBGL_BS_MAX_VERTEX_COUNT];
+ u16 indices[GBGL_BS_MAX_INDEX_COUNT];
+
+ u32 vao, vbo, ebo;
+ u32 nearest_sampler;
+ u32 linear_sampler;
+ gbglShader ortho_tex_shader;
+ gbglShader ortho_col_shader;
+
+ gbMat4 ortho_mat;
+ i32 width, height;
+
+} gbglBasicState;
+
+
+GBGL_DEF void gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height);
+GBGL_DEF void gbgl_bs_set_resolution(gbglBasicState *bs, i32 window_width, i32 window_height);
+GBGL_DEF void gbgl_bs_begin(gbglBasicState *bs, i32 window_width, i32 window_height);
+GBGL_DEF void gbgl_bs_end(gbglBasicState *bs);
+
+GBGL_DEF void gbgl_bs_draw_textured_rect(gbglBasicState *bs, gbglTexture *tex, gbVec2 pos, gbVec2 dim, b32 v_up);
+GBGL_DEF void gbgl_bs_draw_rect(gbglBasicState *bs, gbVec2 pos, gbVec2 dim, gbColour col);
+GBGL_DEF void gbgl_bs_draw_outlined_rect(gbglBasicState *bs, gbVec2 pos, gbVec2 dim, gbColour col, f32 thickness);
+GBGL_DEF void gbgl_bs_draw_quad(gbglBasicState *bs,
+ gbVec2 p0, gbVec2 p1, gbVec2 p2, gbVec2 p3,
+ gbColour col);
+GBGL_DEF void gbgl_bs_draw_outlined_quad(gbglBasicState *bs,
+ gbVec2 p0, gbVec2 p1, gbVec2 p2, gbVec2 p3,
+ gbColour col, f32 thickness);
+
+GBGL_DEF void gbgl_bs_draw_line(gbglBasicState *bs, gbVec2 p0, gbVec2 p1, gbColour col, f32 thickness);
+GBGL_DEF void gbgl_bs_draw_circle(gbglBasicState *bs, gbVec2 p, f32 radius, gbColour col);
+GBGL_DEF void gbgl_bs_draw_outlined_circle(gbglBasicState *bs, gbVec2 p, f32 radius, gbColour col, f32 thickness);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// Implementation //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+// //
+////////////////////////////////////////////////////////////////
+
+
+#if defined(GBGL_IMPLEMENTATION)
+
+
+u32
+gbgl_generate_sampler(u32 min_filter, u32 max_filter, u32 s_wrap, u32 t_wrap)
+{
+ u32 samp;
+ glGenSamplers(1, &samp);
+ glSamplerParameteri(samp, GL_TEXTURE_MIN_FILTER, min_filter);
+ glSamplerParameteri(samp, GL_TEXTURE_MAG_FILTER, max_filter);
+ glSamplerParameteri(samp, GL_TEXTURE_WRAP_S, s_wrap);
+ glSamplerParameteri(samp, GL_TEXTURE_WRAP_T, t_wrap);
+ return samp;
+}
+
+
+////////////////////////////////////////////////////////////////
+//
+// Data Buffers
+//
+//
+
+gb_inline u32
+gbgl__make_buffer(isize size, void const *data, i32 target, i32 usage_hint)
+{
+ u32 buffer_handle;
+ glGenBuffers(1, &buffer_handle);
+ glBindBuffer(target, buffer_handle);
+ glBufferData(target, size, data, usage_hint);
+ return buffer_handle;
+}
+
+gb_inline void
+gbgl__buffer_copy(u32 buffer_handle, i32 target, void const *data, isize size, isize offset)
+{
+ glBindBuffer(target, buffer_handle);
+ glBufferSubData(target, offset, size, data);
+}
+
+// NOTE(bill): usage_hint == (GL_STATIC_DRAW, GL_STREAM_DRAW, GL_DYNAMIC_DRAW)
+gb_inline u32
+gbgl_make_vbo(void const *data, isize size, i32 usage_hint)
+{
+ return gbgl__make_buffer(size, data, GL_ARRAY_BUFFER, usage_hint);
+}
+
+gb_inline u32
+gbgl_make_ebo(void const *data, isize size, i32 usage_hint)
+{
+ return gbgl__make_buffer(size, data, GL_ELEMENT_ARRAY_BUFFER, usage_hint);
+}
+
+gb_inline gbglTBO
+gbgl_make_tbo(gbglBufferDataType data_type, i32 channel_count, void const *data, isize size, i32 usage_hint)
+{
+ gbglTBO tbo;
+ i32 internal_format;
+
+ tbo.buffer_obj_handle = gbgl__make_buffer(size, data, GL_TEXTURE_BUFFER, usage_hint);
+
+ glGenTextures(1, &tbo.buffer_handle);
+ glBindTexture(GL_TEXTURE_BUFFER, tbo.buffer_handle);
+ internal_format = gbgl__get_texture_format(data_type, channel_count);
+ glTexBuffer(GL_TEXTURE_BUFFER, internal_format, tbo.buffer_obj_handle);
+ return tbo;
+}
+
+gb_inline void
+gbgl_vbo_copy(u32 vbo_handle, void *const data, isize size, isize offset)
+{
+ gbgl__buffer_copy(vbo_handle, GL_ARRAY_BUFFER, data, size, offset);
+}
+
+gb_inline void
+gbgl_ebo_copy(u32 ebo_handle, void *const data, isize size, isize offset)
+{
+ gbgl__buffer_copy(ebo_handle, GL_ELEMENT_ARRAY_BUFFER, data, size, offset);
+}
+
+gb_inline void
+gbgl_tbo_copy(gbglTBO tbo, void *const data, isize size, isize offset)
+{
+ gbgl__buffer_copy(tbo.buffer_obj_handle, GL_TEXTURE_BUFFER, data, size, offset);
+}
+
+gb_inline void gbgl_bind_vbo(u32 vbo_handle) { glBindBuffer(GL_ARRAY_BUFFER, vbo_handle); }
+gb_inline void gbgl_bind_ebo(u32 ebo_handle) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_handle); }
+
+gb_inline void
+gbgl_bind_tbo(gbglTBO tbo, i32 sampler_handle, i32 tex_unit)
+{
+ glActiveTexture(GL_TEXTURE0 + tex_unit);
+ glBindTexture(GL_TEXTURE_BUFFER, tbo.buffer_handle);
+ glBindSampler(0, sampler_handle);
+}
+
+// NOTE(bill): access = GL_WRITE_ONLY, etc.
+gb_inline void *
+gbgl_map_vbo(u32 vbo_handle, i32 access)
+{
+ gbgl_bind_vbo(vbo_handle);
+ return glMapBuffer(GL_ARRAY_BUFFER, access);
+}
+
+gb_inline void *
+gbgl_map_ebo(u32 ebo_handle, i32 access)
+{
+ gbgl_bind_ebo(ebo_handle);
+ return glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, access);
+}
+
+gb_inline void gbgl_unmap_vbo(void) { glUnmapBuffer(GL_ARRAY_BUFFER); }
+gb_inline void gbgl_unmap_ebo(void) { glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); }
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Shader
+//
+//
+
+
+gbglShaderError
+gbgl__load_single_shader_from_file(gbglShader *shader, gbglShaderType type, char const *name)
+{
+ gbglShaderError err = GBGL_SHADER_ERROR_NONE;
+
+ if (!gb_open_file(&shader->files[type], "%s%s", name, GBGL_SHADER_FILE_EXTENSIONS[type])) {
+ err = GBGL_SHADER_ERROR_UNABLE_TO_READ_FILE;
+ } else {
+ gb_local_persist char info_log[4096];
+ i64 file_size = gb_file_size(&shader->files[type]);
+ char *file_source = cast(char *)gbgl_malloc(file_size+1);
+ // TODO(bill): LOG MALLOC USAGE
+
+
+ GB_ASSERT_NOT_NULL(file_source);
+ if (file_source) {
+ i32 params;
+
+ gb_file_read_at(&shader->files[type], file_source, file_size, 0);
+ file_source[file_size] = '\0';
+
+ shader->shaders[type] = glCreateShader(GBGL_SHADER_TYPE[type]);
+ glShaderSource(shader->shaders[type], 1, &file_source, NULL);
+ glCompileShader(shader->shaders[type]);
+ glGetShaderiv(shader->shaders[type], GL_COMPILE_STATUS, &params);
+ if (!params) {
+ gb_fprintf(stderr, "Shader Source:\n%s\n", file_source);
+ glGetShaderInfoLog(shader->shaders[type], gb_size_of(info_log), NULL, info_log);
+ gb_fprintf(stderr, "Shader compilation failed:\n %s\n", info_log);
+
+ err = GBGL_SHADER_ERROR_SHADER_COMPILE;
+ }
+
+ gbgl_free(file_source);
+ }
+ gb_close_file(&shader->files[type]);
+ }
+
+ return err;
+}
+
+gbglShaderError
+gbgl__load_single_shader_from_source(gbglShader *s, gbglShaderType type, char const *text)
+{
+ gbglShaderError err = GBGL_SHADER_ERROR_NONE;
+ i32 status;
+
+ s->shaders[type] = glCreateShader(GBGL_SHADER_TYPE[type]);
+ glShaderSource(s->shaders[type], 1, &text, 0);
+ glCompileShader(s->shaders[type]);
+
+ glGetShaderiv(s->shaders[type], GL_COMPILE_STATUS, &status);
+ if (!status) {
+ gb_local_persist char log_info[4096];
+ i32 total_len, log_len;
+
+ gb_fprintf(stderr, "Unable to compile shader: %s\n", text);
+ glGetShaderiv(s->shaders[type], GL_INFO_LOG_LENGTH, &status);
+ total_len = status;
+
+ glGetShaderInfoLog(s->shaders[type], 4095, &log_len, log_info);
+ gb_fprintf(stderr, log_info);
+ err = GBGL_SHADER_ERROR_SHADER_COMPILE;
+ }
+
+ return err;
+}
+
+gbglShaderError
+gbgl__link_shader(gbglShader *shader)
+{
+ gbglShaderError err = GBGL_SHADER_ERROR_NONE;
+ i32 i, status;
+ shader->program = glCreateProgram();
+ for (i = 0; i < GBGL_SHADER_TYPE_COUNT; i++) {
+ if (shader->type_flags & GB_BIT(i))
+ glAttachShader(shader->program, shader->shaders[i]);
+ }
+
+ glLinkProgram(shader->program);
+
+ glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
+ if (!status) {
+ gb_local_persist char log_info[4096];
+ glGetProgramInfoLog(shader->program, gb_size_of(log_info), NULL, log_info);
+ gb_fprintf(stderr, "Shader linking failed:\n %s \n", log_info);
+ err = GBGL_SHADER_ERROR_LINKING;
+ }
+
+ for (i = 0; i < GBGL_SHADER_TYPE_COUNT; i++) {
+ if (shader->type_flags & GB_BIT(i))
+ glDetachShader(shader->program, shader->shaders[i]);
+ }
+
+ return err;
+}
+
+
+
+gbglShaderError
+gbgl_load_shader_from_file(gbglShader *shader, u32 type_bits, char const *filename, ...)
+{
+ gbglShaderError err = GBGL_SHADER_ERROR_NONE;
+ b32 loaded_shader[GBGL_SHADER_TYPE_COUNT] = {0};
+ i32 i;
+
+ gb_zero_struct(shader);
+ shader->type_flags = type_bits;
+ gb_strncpy(shader->base_name, filename, gb_size_of(shader->base_name));
+
+ for (i = 0; i < GBGL_SHADER_TYPE_COUNT; i++) {
+ if (type_bits & GB_BIT(i)) {
+ err = gbgl__load_single_shader_from_file(shader, cast(gbglShaderType)i, filename);
+ if (err != GBGL_SHADER_ERROR_NONE)
+ return err;
+ loaded_shader[i] = true;
+ }
+ }
+ err = gbgl__link_shader(shader);
+
+ return err;
+}
+
+
+
+
+gbglShaderError
+gbgl_load_shader_vf_from_source(gbglShader *s, char const *vert_source, char const *frag_source)
+{
+ gbglShaderError err = GBGL_SHADER_ERROR_NONE;
+
+ gb_zero_struct(s);
+ s->type_flags = GB_BIT(GBGL_SHADER_TYPE_VERTEX) | GB_BIT(GBGL_SHADER_TYPE_FRAGMENT);
+
+ err = gbgl__load_single_shader_from_source(s, GBGL_SHADER_TYPE_VERTEX, vert_source);
+ if (err != GBGL_SHADER_ERROR_NONE) return err;
+ err = gbgl__load_single_shader_from_source(s, GBGL_SHADER_TYPE_FRAGMENT, frag_source);
+ if (err != GBGL_SHADER_ERROR_NONE) return err;
+
+ err = gbgl__link_shader(s);
+
+ return err;
+}
+
+gbglShaderError
+gbgl_load_shader_vfg_from_source(gbglShader *s, char const *vert_source, char const *frag_source, char const *geom_source)
+{
+ gbglShaderError err = GBGL_SHADER_ERROR_NONE;
+
+ gb_zero_struct(s);
+ s->type_flags = GB_BIT(GBGL_SHADER_TYPE_VERTEX) | GB_BIT(GBGL_SHADER_TYPE_FRAGMENT) | GB_BIT(GBGL_SHADER_TYPE_GEOMETRY);
+
+ err = gbgl__load_single_shader_from_source(s, GBGL_SHADER_TYPE_VERTEX, vert_source);
+ if (err != GBGL_SHADER_ERROR_NONE) return err;
+ err = gbgl__load_single_shader_from_source(s, GBGL_SHADER_TYPE_FRAGMENT, frag_source);
+ if (err != GBGL_SHADER_ERROR_NONE) return err;
+ err = gbgl__load_single_shader_from_source(s, GBGL_SHADER_TYPE_GEOMETRY, geom_source);
+ if (err != GBGL_SHADER_ERROR_NONE) return err;
+
+ err = gbgl__link_shader(s);
+
+ return err;
+}
+
+gb_inline void
+gbgl_destroy_shader(gbglShader *shader)
+{
+ i32 i;
+ for (i = 0; i < GBGL_SHADER_TYPE_COUNT; i++) {
+ if (shader->type_flags & GB_BIT(i)) {
+ gb_close_file(&shader->files[i]);
+ glDeleteShader(shader->shaders[i]);
+ }
+ }
+
+ glDeleteProgram(shader->program);
+
+ for (i = 0; i < shader->uniform_count; i++) {
+ gbgl_free(shader->uniform_names[i]);
+ }
+}
+
+
+gb_inline b32
+gbgl_has_shader_changed(gbglShader *shader)
+{
+ i32 i;
+ for (i = 0; i < GBGL_SHADER_TYPE_COUNT; i++) {
+ if (shader->type_flags & GB_BIT(i)) {
+ if (gb_has_file_changed(&shader->files[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+b32
+gbgl_reload_shader(gbglShader *shader)
+{
+ i32 i;
+ for (i = 0; i < GBGL_SHADER_TYPE_COUNT; i++) {
+ if (shader->type_flags & GB_BIT(i)) {
+ if (gbgl__load_single_shader_from_file(shader, cast(gbglShaderType)i, shader->base_name) != GBGL_SHADER_ERROR_NONE)
+ return false;
+ }
+ }
+
+ if (gbgl__link_shader(shader) != GBGL_SHADER_ERROR_NONE)
+ return false;
+
+ for (i = 0; i < shader->uniform_count; i++)
+ shader->uniform_locs[i] = glGetUniformLocation(shader->program, shader->uniform_names[i]);
+
+
+ return true;
+}
+
+gb_inline void gbgl_use_shader(gbglShader *s) { glUseProgram(s ? s->program : 0); }
+
+gb_inline b32
+gbgl_is_shader_in_use(gbglShader *s)
+{
+ if (s) {
+ i32 curr = 0;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &curr);
+ return (curr == cast(i32)s->program);
+ }
+ return false;
+}
+
+
+i32
+gbgl_get_uniform(gbglShader *s, char const *name)
+{
+ i32 i, loc = -1;
+ for (i = 0; i < s->uniform_count; i++) {
+ if (gb_strcmp(s->uniform_names[i], name) == 0) {
+ return s->uniform_locs[i];
+ }
+ }
+
+ GB_ASSERT_MSG(s->uniform_count < GBGL_MAX_UNIFORM_COUNT,
+ "Uniform array for shader is full");
+
+ loc = glGetUniformLocation(s->program, name);
+ s->uniform_names[s->uniform_count] = gb_alloc_cstring(gb_heap_allocator(), name);
+ s->uniform_locs[s->uniform_count] = loc;
+ s->uniform_count++;
+
+ return loc;
+}
+
+
+////////////////////////////////////////////////////////////////
+//
+// Render Buffer
+//
+//
+
+#if 0
+b32
+gbgl_render_buffer_init(gbglRenderBuffer *in_out_rb)
+{
+ i32 i;
+ if (in_out_rb->colour_buffer_count >= GBGL_MAX_RENDER_COLOUR_BUFFERS) {
+ return false;
+ }
+ glGenFramebuffers(1, &in_out_rb->gl_frame_buffer_handle);
+ glBindFramebuffer(GL_FRAMEBUFFER, in_out_rb->gl_frame_buffer_handle);
+
+ glGenTextures(in_out_rb->colour_buffer_count, in_out_rb->handles);
+ for (i = 0; i < in_out_rb->colour_buffer_count; i++) {
+ i32 channel_count = in_out_rb->channel_count[i];
+ glBindTexture(GL_TEXTURE_2D, in_out_rb->handles[i]);
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GBGL_INTERNAL_TEXTURE_FORMAT_8[channel_count-1],
+ in_out_rb->width, in_out_rb->height, 0,
+ GBGL_TEXTURE_FORMAT[channel_count-1],
+ in_out_rb->data_type[0], 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
+ in_out_rb->handles[0], 0);
+ }
+ glDrawBuffers(in_out_rb->colour_buffer_count, GBGL_COLOUR_BUFFER_ATTACHMENTS);
+ //@TODO: not every valid permutation has been tested, it's likely that there's a format/internal format mismatch somewhere
+ if (in_out_rb->has_depth || in_out_rb->has_stencil) {
+ if (in_out_rb->has_depth && in_out_rb->has_stencil) {
+ glGenRenderbuffers(1, &in_out_rb->gl_depth_stencil_buffer_handle);
+ glBindRenderbuffer(GL_RENDERBUFFER, in_out_rb->gl_depth_stencil_buffer_handle);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, in_out_rb->width, in_out_rb->height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, in_out_rb->gl_depth_stencil_buffer_handle);
+ } else if (in_out_rb->has_depth) {
+ glGenRenderbuffers(1, &in_out_rb->gl_depth_stencil_buffer_handle);
+ glBindRenderbuffer(GL_RENDERBUFFER, in_out_rb->gl_depth_stencil_buffer_handle);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, in_out_rb->width, in_out_rb->height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, in_out_rb->gl_depth_stencil_buffer_handle);
+ } else if (in_out_rb->has_stencil) {
+ GB_PANIC("A framebuffer cannot have a stencil without depth"); // NOTE(bill): no stencil w/o depth
+ }
+ }
+
+ in_out_rb->gl_frame_buffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (in_out_rb->gl_frame_buffer_status != GL_FRAMEBUFFER_COMPLETE) {
+ gb_fprintf(stderr, "Unable to create OpenGL Frame buffer. Frame buffer incomplete: %d\n", in_out_rb->gl_frame_buffer_status);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return in_out_rb->gl_frame_buffer_status == GL_FRAMEBUFFER_COMPLETE;
+}
+#endif
+
+b32
+gbgl_init_render_buffer(gbglRenderBuffer *rb, i32 width, i32 height, i32 channel_count)
+{
+ if ((rb->width == width) && (rb->height == height) && (rb->channel_count == channel_count)) return true;
+ gbgl_destroy_render_buffer(rb);
+ gb_zero_struct(rb);
+
+ rb->width = width;
+ rb->height = height;
+
+ glEnable(GL_FRAMEBUFFER_SRGB);
+
+ glGenFramebuffers(1, &rb->handle);
+ glBindFramebuffer(GL_FRAMEBUFFER, rb->handle);
+
+ gbgl_load_texture2d_from_memory(&rb->colour_texture, NULL, width, height, channel_count);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rb->colour_texture.handle, 0);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ {
+ u32 draw_buffers[] = {GL_COLOR_ATTACHMENT0};
+ glDrawBuffers(gb_count_of(draw_buffers), draw_buffers);
+ }
+
+ {
+ u32 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ gb_fprintf(stderr, "Framebuffer Status: 0x%x\n", status);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+gb_inline void
+gbgl_destroy_render_buffer(gbglRenderBuffer *rb)
+{
+ if (rb->handle)
+ glDeleteFramebuffers(1, &rb->handle);
+
+ gbgl_destroy_texture(&rb->colour_texture);
+}
+
+
+gb_inline void
+gbgl_render_to_buffer(gbglRenderBuffer const *rb)
+{
+ GB_ASSERT_NOT_NULL(rb);
+ glViewport(0, 0, rb->width, rb->height);
+ glBindFramebuffer(GL_FRAMEBUFFER, rb->handle);
+}
+
+gb_inline void
+gbgl_render_to_screen(i32 width, i32 height)
+{
+ glViewport(0, 0, width, height);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+
+////////////////////////////////////////////////////////////////
+//
+// Texture
+//
+//
+
+
+b32
+gbgl_load_texture2d_from_memory(gbglTexture *tex, void const *data, i32 width, i32 height, i32 channel_count)
+{
+ b32 result = true;
+
+ gb_zero_struct(tex);
+
+ tex->width = width;
+ tex->height = height;
+ tex->channel_count = channel_count;
+ tex->data_type = GBGL_BDT_U8;
+ tex->type = GBGL_TEXTURE_TYPE_2D;
+
+ glGenTextures(1, &tex->handle);
+ glBindTexture(GL_TEXTURE_2D, tex->handle);
+
+
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GBGL_INTERNAL_TEXTURE_FORMAT_8[channel_count-1],
+ width, height, 0,
+ GBGL_TEXTURE_FORMAT[channel_count-1],
+ GL_UNSIGNED_BYTE, data);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glFinish();
+
+
+ return result;
+}
+
+b32
+gbgl_load_texture2d_from_file(gbglTexture *texture, b32 flip_vertically, char const *filename, ...)
+{
+ b32 result;
+ u8 *data;
+ int width, height, comp;
+ char *path;
+
+ va_list va;
+ va_start(va, filename);
+ path = gb_sprintf_va(filename, va);
+ va_end(va);
+
+ stbi_set_flip_vertically_on_load(flip_vertically);
+ data = stbi_load(path, &width, &height, &comp, 0);
+ if (data == NULL) {
+ gb_fprintf(stderr, "Failed to load image: %s\n", path);
+ result = false;
+ } else {
+ result = gbgl_load_texture2d_from_memory(texture, data, width, height, comp);
+ stbi_image_free(data);
+ }
+ return result;
+}
+
+gb_inline b32
+gbgl_make_texture2d_coloured(gbglTexture *t, gbColour colour)
+{
+ return gbgl_load_texture2d_from_memory(t, &colour.rgba, 1, 1, 4);
+}
+
+
+void
+gbgl_bind_texture2d(gbglTexture const *t, u32 position, u32 sampler)
+{
+ GB_ASSERT(t->type == GBGL_TEXTURE_TYPE_2D);
+
+ if (position > 31) {
+ position = 31;
+ gb_fprintf(stderr, "Textures can only bound to position [0 ... 31]\n");
+ gb_fprintf(stderr, "Will bind to position [31]\n");
+ }
+
+ glActiveTexture(GL_TEXTURE0 + position);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, t ? t->handle : 0);
+ glBindSampler(position, sampler);
+}
+
+gb_inline void
+gbgl_destroy_texture(gbglTexture *t)
+{
+ if (t->handle) {
+ glDeleteTextures(1, &t->handle);
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////
+//
+// Basic State
+//
+//
+
+
+
+void
+gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height)
+{
+ isize i;
+
+ gbgl_bs_set_resolution(bs, window_width, window_height);
+ glGenVertexArrays(1, &bs->vao);
+ glBindVertexArray(bs->vao);
+
+ bs->vbo = gbgl_make_vbo(NULL, gb_size_of(gbglBasicVertex) * GBGL_BS_MAX_VERTEX_COUNT, GL_DYNAMIC_DRAW);
+
+ for (i = 0; i < GBGL_BS_MAX_INDEX_COUNT / 6; i++) {
+ bs->indices[i*6 + 0] = i*4 + 0;
+ bs->indices[i*6 + 1] = i*4 + 1;
+ bs->indices[i*6 + 2] = i*4 + 2;
+ bs->indices[i*6 + 3] = i*4 + 2;
+ bs->indices[i*6 + 4] = i*4 + 3;
+ bs->indices[i*6 + 5] = i*4 + 0;
+ }
+ bs->ebo = gbgl_make_ebo(bs->indices, gb_size_of(u16) * GBGL_BS_MAX_INDEX_COUNT, GL_STATIC_DRAW);
+
+ bs->nearest_sampler = gbgl_generate_sampler(GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+ bs->linear_sampler = gbgl_generate_sampler(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+
+ gbgl_load_shader_vf_from_source(&bs->ortho_tex_shader,
+ "#version 410 core\n"
+ "layout (location = 0) in vec4 a_position;\n"
+ "layout (location = 1) in vec2 a_tex_coord;\n"
+ "uniform mat4 u_ortho_mat;\n"
+ "out vec2 v_tex_coord;\n"
+ "void main(void) {\n"
+ " gl_Position = u_ortho_mat * a_position;\n"
+ " v_tex_coord = a_tex_coord;\n"
+ "}\n",
+
+ "#version 410 core\n"
+ "precision mediump float;"
+ "in vec2 v_tex_coord;\n"
+ "layout (binding = 0) uniform sampler2D u_tex;\n"
+ "out vec4 o_colour;\n"
+ "void main(void) {\n"
+ " o_colour = texture2D(u_tex, v_tex_coord);\n"
+ "}\n");
+
+ gbgl_load_shader_vf_from_source(&bs->ortho_col_shader,
+ "#version 410 core\n"
+ "precision mediump float;"
+ "layout (location = 0) in vec4 a_position;\n"
+ "uniform mat4 u_ortho_mat;\n"
+ "void main(void) {\n"
+ " gl_Position = u_ortho_mat * a_position;\n"
+ "}\n",
+
+ "#version 410 core\n"
+ "uniform vec4 u_colour;\n"
+ "out vec4 o_colour;\n"
+ "void main(void) {\n"
+ " o_colour = u_colour;\n"
+ "}\n");
+}
+
+void
+gbgl_bs_set_resolution(gbglBasicState *bs, i32 window_width, i32 window_height)
+{
+ bs->width = window_width;
+ bs->height = window_height;
+ gb_mat4_ortho2d(&bs->ortho_mat, 0, bs->width, 0, bs->height);
+}
+
+void
+gbgl_bs_begin(gbglBasicState *bs, i32 window_width, i32 window_height)
+{
+ glBindVertexArray(bs->vao);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_CULL_FACE);
+ gbgl_bs_set_resolution(bs, window_width, window_height);
+}
+
+void
+gbgl_bs_end(gbglBasicState *bs)
+{
+ glBindVertexArray(0);
+}
+
+
+
+
+void
+gbgl_bs_draw_textured_rect(gbglBasicState *bs, gbglTexture *tex, gbVec2 pos, gbVec2 dim, b32 v_up)
+{
+ bs->vertices[0].x = pos.x;
+ bs->vertices[0].y = pos.y;
+ bs->vertices[0].u = 0.0f;
+ bs->vertices[0].v = v_up ? 0.0f : 1.0f;
+
+ bs->vertices[1].x = pos.x + dim.x;
+ bs->vertices[1].y = pos.y;
+ bs->vertices[1].u = 1.0f;
+ bs->vertices[1].v = v_up ? 0.0f : 1.0f;
+
+ bs->vertices[2].x = pos.x + dim.x;
+ bs->vertices[2].y = pos.y + dim.y;
+ bs->vertices[2].u = 1.0f;
+ bs->vertices[2].v = v_up ? 1.0f : 0.0f;
+
+ bs->vertices[3].x = pos.x;
+ bs->vertices[3].y = pos.y + dim.y;
+ bs->vertices[3].u = 0.0f;
+ bs->vertices[3].v = v_up ? 1.0f : 0.0f;
+
+ gbgl_use_shader(&bs->ortho_tex_shader);
+ gbgl_set_uniform_mat4(gbgl_get_uniform(&bs->ortho_tex_shader, "u_ortho_mat"), bs->ortho_mat.e);
+ gbgl_bind_texture2d(tex, 0, bs->nearest_sampler);
+
+ gbgl_vbo_copy(bs->vbo, bs->vertices, 4*gb_size_of(bs->vertices[0]), 0);
+
+ gbgl_vert_ptr_aa(0, 2, gbglBasicVertex, x);
+ gbgl_vert_ptr_aa(1, 2, gbglBasicVertex, u);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs->ebo);
+
+ glEnable(GL_BLEND);
+ glBlendEquationi(0, GL_FUNC_ADD);
+ glBlendFunci(0, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
+}
+
+void
+gbgl_bs_draw_rect(gbglBasicState *bs, gbVec2 pos, gbVec2 dim, gbColour col)
+{
+ gbgl_bs_draw_quad(bs,
+ gb_vec2(pos.x, pos.y),
+ gb_vec2(pos.x+dim.x, pos.y),
+ gb_vec2(pos.x+dim.x, pos.y+dim.y),
+ gb_vec2(pos.x, pos.y+dim.y),
+ col);
+}
+
+void
+gbgl_bs_draw_outlined_rect(gbglBasicState *bs, gbVec2 pos, gbVec2 dim, gbColour col, f32 thickness)
+{
+ gbgl_bs_draw_outlined_quad(bs,
+ gb_vec2(pos.x, pos.y),
+ gb_vec2(pos.x+dim.x, pos.y),
+ gb_vec2(pos.x+dim.x, pos.y+dim.y),
+ gb_vec2(pos.x, pos.y+dim.y),
+ col,
+ thickness);
+}
+
+
+gb_internal void
+gbgl__bs_setup_ortho_colour_state(gbglBasicState *bs, isize vertex_count, gbColour col)
+{
+ gbVec4 vcol = gb_vec4(col.r/255.0f, col.g/255.0f, col.b/255.0f, col.a/255.0f);
+
+ gbgl_use_shader(&bs->ortho_col_shader);
+ gbgl_set_uniform_mat4(gbgl_get_uniform(&bs->ortho_col_shader, "u_ortho_mat"), bs->ortho_mat.e);
+ gbgl_set_uniform_vec4(gbgl_get_uniform(&bs->ortho_col_shader, "u_colour"), vcol);
+
+ gbgl_vbo_copy(bs->vbo, bs->vertices, vertex_count*gb_size_of(bs->vertices[0]), 0);
+ gbgl_vert_ptr_aa(0, 2, gbglBasicVertex, x);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs->ebo);
+
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void
+gbgl_bs_draw_quad(gbglBasicState *bs,
+ gbVec2 p0, gbVec2 p1, gbVec2 p2, gbVec2 p3, gbColour col)
+{
+ bs->vertices[0].x = p0.x;
+ bs->vertices[0].y = p0.y;
+
+ bs->vertices[1].x = p1.x;
+ bs->vertices[1].y = p1.y;
+
+ bs->vertices[2].x = p2.x;
+ bs->vertices[2].y = p2.y;
+
+ bs->vertices[3].x = p3.x;
+ bs->vertices[3].y = p3.y;
+
+ gbgl__bs_setup_ortho_colour_state(bs, 4, col);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
+}
+
+void
+gbgl_bs_draw_outlined_quad(gbglBasicState *bs,
+ gbVec2 p0, gbVec2 p1, gbVec2 p2, gbVec2 p3, gbColour col, f32 thickness)
+{
+ bs->vertices[0].x = p0.x;
+ bs->vertices[0].y = p0.y;
+
+ bs->vertices[1].x = p1.x;
+ bs->vertices[1].y = p1.y;
+
+ bs->vertices[2].x = p2.x;
+ bs->vertices[2].y = p2.y;
+
+ bs->vertices[3].x = p3.x;
+ bs->vertices[3].y = p3.y;
+
+ gbgl__bs_setup_ortho_colour_state(bs, 4, col);
+ glLineWidth(thickness);
+ glDrawArrays(GL_LINE_LOOP, 0, 4);
+}
+
+void
+gbgl_bs_draw_line(gbglBasicState *bs, gbVec2 p0, gbVec2 p1, gbColour col, f32 thickness)
+{
+ bs->vertices[0].x = p0.x;
+ bs->vertices[0].y = p0.y;
+
+ bs->vertices[1].x = p1.x;
+ bs->vertices[1].y = p1.y;
+
+ gbgl__bs_setup_ortho_colour_state(bs, 2, col);
+ glLineWidth(thickness);
+ glDrawArrays(GL_LINES, 0, 2);
+}
+
+void
+gbgl_bs_draw_circle(gbglBasicState *bs, gbVec2 p, f32 radius, gbColour col)
+{
+ isize i;
+
+ bs->vertices[0].x = p.x;
+ bs->vertices[0].y = p.y;
+
+ for (i = 0; i < 31; i++) {
+ f32 t = cast(f32)i / 30.0f;
+ f32 theta = t * GB_MATH_TAU;
+ f32 c = gb_cos(theta);
+ f32 s = gb_sin(theta);
+ bs->vertices[i+1].x = p.x + c*radius;
+ bs->vertices[i+1].y = p.y + s*radius;
+ }
+
+ gbgl__bs_setup_ortho_colour_state(bs, 32, col);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 32);
+}
+
+void
+gbgl_bs_draw_outlined_circle(gbglBasicState *bs, gbVec2 p, f32 radius, gbColour col, f32 thickness)
+{
+ isize i;
+
+ for (i = 0; i < 32; i++) {
+ f32 t = cast(f32)i / 31.0f;
+ f32 theta = t * GB_MATH_TAU;
+ f32 c = gb_cos(theta);
+ f32 s = gb_sin(theta);
+ bs->vertices[i].x = p.x + c*radius;
+ bs->vertices[i].y = p.y + s*radius;
+ }
+
+ gbgl__bs_setup_ortho_colour_state(bs, 32, col);
+ glLineWidth(thickness);
+ glDrawArrays(GL_LINE_LOOP, 0, 32);
+}
+
+
+
+
+#endif