A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer.

The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture.

So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size.

Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder.

I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`.

I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
This commit is contained in:
Simon Anciaux 2025-01-06 18:37:44 +01:00 committed by Peter Slattery
parent e040b1a29b
commit 0e2b8d0df8
24 changed files with 2298 additions and 2098 deletions

View File

@ -26,5 +26,55 @@ Welcome to the 4coder community repository.
1. `$ cd 4cc/code`
2. `$ ./bin/build-linux.sh`
## Mac (Untested)
1. The steps should be the same as linux but replace the `*-linux.sh` with their `*-mac.sh` equivalents.
## Mac
> 4coder targets x86_64. If you are using a M1+ ARM CPU you need to prefix the build scripts commands with: `arch -arch x86_64`
1. Use the `package-mac.sh` script from the code directory (this builds a distribution in the `distributions` directory with all the non-binary dependencies)
1. `$ cd 4cc/code`
2. `$ ./bin/package-mac.sh`
2. You can also use the `build-mac.sh` script if you want just build the binaries, (this produces the build artifacts in the `build` directory, this doesn't produce a functional distribution)
1. `$ cd 4cc/code`
2. `$ ./bin/build-mac.sh`
### Older Macs, 10.15.7 Catalina
If you are using an older version of mac, such as 10.15.7 Catalina you need to install the realpath command:
1. `$ sudo port install coreutils`
2. macports names the `realpath` command `grealpath`, so make a symbolic link in order to use build-mac.sh:
`$ sudo ln -s /opt/local/bin/grealpath /opt/local/bin/realpath`
## Build script parameter
The build script accepts a parameter (mutually exclusive):
- `/DDEV_BUILD` or `/DDEV_BUILD_X86` (default value) : build without optimizations.
Produces debug symbols.
Defines: `FRED_INTERNAL`, `FRED_SUPER`, `DO_CRAZY_EXPENSIVE_ASSERTS` (on Windows) macros.
- `/DOPT_BUILD` or `/DOPT_BUILD_X86` (similar to `build_optimized` script): build with optimizations.
Doesn't produce debug symbols.
Defines `FRED_SUPER` macro.
- `/DPACKAGE_SUPER_X64` or `/DPACKAGE_SUPER_X86` (similar to `package` script): package 4coder for distribution.
Turns on optimizations.
Produces debug symbols.
Defines `SHIP_MODE`, `FRED_SUPER`, `DO_CRAZY_EXPENSIVE_ASSERTS` (on Windows) macros.
- `/DPACKAGE_DEMO_X64` or `/DPACKAGE_DEMO_X86`: packages 4coder demo for distribution.
Turns on optimizations.
Produces debug symbols.
Defines `SHIP_MODE`, `DO_CRAZY_EXPENSIVE_ASSERTS` (on Windows) macros.
## API generators
4coder uses several small programs to generate some headers and source files. Those do not run automatically, you must build them and run them when needed (which shouldn't really happen).
- `code\4ed_font_api.cpp` creates, in `code\generated`, `font_api.h`, `font_api.cpp`, `font_api_constructor.cpp` (not used) and `font_api_master_list.h` (not used);
- `code\4ed_graphics_api.cpp` creates, in `code\generated`, `graphics_api.h` and `graphics_api.cpp`, `graphics_api_constructor.cpp` (not used) and `graphics_api_master_list.h` (not used);
- `code\4ed_system_api.cpp` creates, in `code\custom\generated`, `system_api.h`, `system_api.cpp`, `system_api_constructor.cpp`, `system_api_master_list.h`;
- `code\4ed_api_parser_main.cpp` is a little different, as it parses source files passed as parameters to search for functions and type preceded by `api(some_api_name)` and creates 4 files in the `code\custom\generated`. It is used to generate `custom_api.h`, `custom_api.cpp`, `custom_api_constructor.cpp` and `custom_api_master_list.h` by passing `code\4ed_api_implementation.cpp` as a parameter.
You need to compile one of those file and run it from the `code` directory.
There is also `code\4ed_api_check.cpp` to verify the generated file but it's not clear at the moment what to check against.
- `code\4ed_generate_keycodes.cpp` is also a bit appart as it generates `code\custom\generated\4coder_event_codes.h` which are keyboard key codes and some event hook ids.

View File

@ -208,7 +208,10 @@ api_get_callable_name(Arena *arena, String_Const_u8 api_name, String_Const_u8 na
////////////////////////////////
function void
generate_api_master_list(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out){
generate_api_master_list(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out, String_Const_u8 generated_by){
fprintf(out, "/* Generated by \"%.*s\" */\n\n", string_expand(generated_by));
for (API_Call *call = api->first_call;
call != 0;
call = call->next){
@ -236,7 +239,10 @@ generate_api_master_list(Arena *scratch, API_Definition *api, API_Generation_Fla
}
function void
generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out){
generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out, String_Const_u8 generated_by){
fprintf(out, "/* Generated by \"%.*s\" */\n\n", string_expand(generated_by));
for (API_Call *call = api->first_call;
call != 0;
call = call->next){
@ -264,6 +270,8 @@ generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags,
fprintf(out, ")\n");
}
fprintf(out, "\n");
for (API_Call *call = api->first_call;
call != 0;
call = call->next){
@ -289,6 +297,8 @@ generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags,
fprintf(out, ");\n");
}
fprintf(out, "\n");
fprintf(out, "struct API_VTable_%.*s{\n", string_expand(api->name));
for (API_Call *call = api->first_call;
call != 0;
@ -302,6 +312,8 @@ generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags,
}
fprintf(out, "};\n");
fprintf(out, "\n");
fprintf(out, "#if defined(STATIC_LINK_API)\n");
for (API_Call *call = api->first_call;
call != 0;
@ -328,6 +340,7 @@ generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags,
fprintf(out, ");\n");
}
fprintf(out, "#undef STATIC_LINK_API\n");
fprintf(out, "\n");
fprintf(out, "#elif defined(DYNAMIC_LINK_API)\n");
for (API_Call *call = api->first_call;
call != 0;
@ -343,7 +356,10 @@ generate_header(Arena *scratch, API_Definition *api, API_Generation_Flag flags,
}
function void
generate_cpp(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out){
generate_cpp(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out, String_Const_u8 generated_by){
fprintf(out, "/* Generated by \"%.*s\" */\n\n", string_expand(generated_by));
fprintf(out, "function void\n");
fprintf(out, "%.*s_api_fill_vtable(API_VTable_%.*s *vtable){\n",
string_expand(api->name),
@ -357,6 +373,7 @@ generate_cpp(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FIL
string_expand(callable_name));
}
fprintf(out, "}\n");
fprintf(out, "\n");
fprintf(out, "#if defined(DYNAMIC_LINK_API)\n");
fprintf(out, "function void\n");
@ -377,7 +394,10 @@ generate_cpp(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FIL
}
function void
generate_constructor(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out){
generate_constructor(Arena *scratch, API_Definition *api, API_Generation_Flag flags, FILE *out, String_Const_u8 generated_by){
fprintf(out, "/* Generated by \"%.*s\" */\n\n", string_expand(generated_by));
fprintf(out, "function API_Definition*\n");
fprintf(out, "%.*s_api_construct(Arena *arena){\n",
string_expand(api->name));
@ -418,7 +438,7 @@ generate_constructor(Arena *scratch, API_Definition *api, API_Generation_Flag fl
////////////////////////////////
function b32
api_definition_generate_api_includes(Arena *arena, API_Definition *api, Generated_Group group, API_Generation_Flag flags){
api_definition_generate_api_includes(Arena *arena, API_Definition *api, Generated_Group group, API_Generation_Flag flags, String_Const_u8 generated_by){
// NOTE(allen): Arrange output files
String_Const_u8 path_to_self = string_u8_litexpr(__FILE__);
@ -494,10 +514,10 @@ api_definition_generate_api_includes(Arena *arena, API_Definition *api, Generate
// NOTE(allen): Generate output
generate_api_master_list(arena, api, flags, out_file_ml);
generate_header(arena, api, flags, out_file_h);
generate_cpp(arena, api, flags, out_file_cpp);
generate_constructor(arena, api, flags, out_file_con);
generate_api_master_list(arena, api, flags, out_file_ml, generated_by);
generate_header(arena, api, flags, out_file_h, generated_by);
generate_cpp(arena, api, flags, out_file_cpp, generated_by);
generate_constructor(arena, api, flags, out_file_con, generated_by);
////////////////////////////////

View File

@ -31,7 +31,7 @@ int
main(void){
Arena arena = make_arena_malloc();
API_Definition *api = define_api(&arena);
if (!api_definition_generate_api_includes(&arena, api, get_api_group(), 0)){
if (!api_definition_generate_api_includes(&arena, api, get_api_group(), 0, SCu8(GENERATED_BY))){
return(1);
}
return(0);

View File

@ -37,9 +37,49 @@ main(int argc, char **argv){
exit(1);
}
String_Const_u8 exe = SCu8("4ed_api_parser_main.exe");
u32 command_line_length = exe.size + 1;
String_Const_u8 command_line = { 0 };
for (i32 i = 1; i < argc; i+=1){
command_line_length += cstring_length(argv[i]) + 1;
}
command_line = push_data(&arena, command_line_length);
u8* command_line_current = command_line.str;
u8* command_line_end = command_line.str + command_line.size;
{
char* c = ( char* ) exe.str;
while ( *c != 0 && command_line_current < command_line_end ) {
*command_line_current = *c;
command_line_current++;
c++;
}
}
if ( command_line_current < command_line_end ) {
*command_line_current = ' ';
command_line_current++;
}
API_Definition_List list = {};
for (i32 i = 1; i < argc; i += 1){
char *file_name = argv[i];
char* c = file_name;
while ( *c != 0 && command_line_current < command_line_end ) {
*command_line_current = *c;
command_line_current++;
c++;
}
if ( command_line_current < command_line_end ) {
*command_line_current = ' ';
command_line_current++;
}
FILE *file = fopen(file_name, "rb");
if (file == 0){
printf("error: could not open input file: '%s'\n", argv[i]);
@ -57,7 +97,7 @@ main(int argc, char **argv){
for (API_Definition *node = list.first;
node != 0;
node = node->next){
api_definition_generate_api_includes(&arena, node, GeneratedGroup_Custom, APIGeneration_NoAPINameOnCallables);
api_definition_generate_api_includes(&arena, node, GeneratedGroup_Custom, APIGeneration_NoAPINameOnCallables, command_line);
}
}

View File

@ -9,6 +9,8 @@
// TOP
#define GENERATED_BY "4ed_font_api.cpp"
#include "4ed_api_definition_main.cpp"
function API_Definition*

View File

@ -332,6 +332,11 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
Texture_Kind texture_kind = TextureKind_Mono;
u32 texture = graphics_get_texture(pack.dim, texture_kind);
/* NOTE simon (06/01/25): This assumes that every platforms don't use 0 as a valid texture id.
This is valid for OpenGL and the DX11 implementaion. Someone needs to check the MAC versions. */
if (texture != 0 ){
face->texture_kind = texture_kind;
face->texture = texture;
@ -386,6 +391,11 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
26*met->normal_uppercase_advance +
10*met->decimal_digit_advance)/62.f;
}
} else {
pop_array(arena, Face, 1);
face = 0;
}
}
FT_Done_FreeType(ft);

View File

@ -153,6 +153,9 @@ font_set_modify_face(Font_Set *set, Face_ID id, Face_Description *description){
Arena arena = make_arena_system();
Face *face = font_make_face(&arena, description, set->scale_factor);
if (face != 0){
if (slot->face->texture != 0){
graphics_free_texture(slot->face->texture);
}
linalloc_clear(&slot->arena);
slot->arena = arena;
slot->face = face;

View File

@ -9,6 +9,8 @@
// TOP
#define GENERATED_BY "4ed_graphics_api.cpp"
#include "4ed_api_definition_main.cpp"
function API_Definition*
@ -30,6 +32,11 @@ define_api(Arena *arena){
api_param(arena, call, "void*", "data");
}
{
API_Call *call = api_call(arena, api, "free_texture", "void");
api_param(arena, call, "u32", "texid");
}
return(api);
}

View File

@ -9,6 +9,8 @@
// TOP
#define GENERATED_BY "4ed_system_api.cpp"
#include "4ed_api_definition_main.cpp"
function API_Definition*

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_api_parser_main.exe 4ed_api_implementation.cpp " */
function void
custom_api_fill_vtable(API_VTable_custom *vtable){
vtable->global_set_setting = global_set_setting;
@ -180,6 +182,7 @@ vtable->buffer_find_all_matches = buffer_find_all_matches;
vtable->get_core_profile_list = get_core_profile_list;
vtable->get_custom_layer_boundary_docs = get_custom_layer_boundary_docs;
}
#if defined(DYNAMIC_LINK_API)
function void
custom_api_read_vtable(API_VTable_custom *vtable){

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_api_parser_main.exe 4ed_api_implementation.cpp " */
#define custom_global_set_setting_sig() b32 custom_global_set_setting(Application_Links* app, Global_Setting_ID setting, i64 value)
#define custom_global_get_screen_rectangle_sig() Rect_f32 custom_global_get_screen_rectangle(Application_Links* app)
#define custom_get_thread_context_sig() Thread_Context* custom_get_thread_context(Application_Links* app)
@ -177,6 +179,7 @@
#define custom_buffer_find_all_matches_sig() String_Match_List custom_buffer_find_all_matches(Application_Links* app, Arena* arena, Buffer_ID buffer, i32 string_id, Range_i64 range, String_Const_u8 needle, Character_Predicate* predicate, Scan_Direction direction)
#define custom_get_core_profile_list_sig() Profile_Global_List* custom_get_core_profile_list(Application_Links* app)
#define custom_get_custom_layer_boundary_docs_sig() Doc_Cluster* custom_get_custom_layer_boundary_docs(Application_Links* app, Arena* arena)
typedef b32 custom_global_set_setting_type(Application_Links* app, Global_Setting_ID setting, i64 value);
typedef Rect_f32 custom_global_get_screen_rectangle_type(Application_Links* app);
typedef Thread_Context* custom_get_thread_context_type(Application_Links* app);
@ -356,6 +359,7 @@ typedef void custom_animate_in_n_milliseconds_type(Application_Links* app, u32 n
typedef String_Match_List custom_buffer_find_all_matches_type(Application_Links* app, Arena* arena, Buffer_ID buffer, i32 string_id, Range_i64 range, String_Const_u8 needle, Character_Predicate* predicate, Scan_Direction direction);
typedef Profile_Global_List* custom_get_core_profile_list_type(Application_Links* app);
typedef Doc_Cluster* custom_get_custom_layer_boundary_docs_type(Application_Links* app, Arena* arena);
struct API_VTable_custom{
custom_global_set_setting_type *global_set_setting;
custom_global_get_screen_rectangle_type *global_get_screen_rectangle;
@ -537,6 +541,7 @@ custom_buffer_find_all_matches_type *buffer_find_all_matches;
custom_get_core_profile_list_type *get_core_profile_list;
custom_get_custom_layer_boundary_docs_type *get_custom_layer_boundary_docs;
};
#if defined(STATIC_LINK_API)
internal b32 global_set_setting(Application_Links* app, Global_Setting_ID setting, i64 value);
internal Rect_f32 global_get_screen_rectangle(Application_Links* app);
@ -718,6 +723,7 @@ internal String_Match_List buffer_find_all_matches(Application_Links* app, Arena
internal Profile_Global_List* get_core_profile_list(Application_Links* app);
internal Doc_Cluster* get_custom_layer_boundary_docs(Application_Links* app, Arena* arena);
#undef STATIC_LINK_API
#elif defined(DYNAMIC_LINK_API)
global custom_global_set_setting_type *global_set_setting = 0;
global custom_global_get_screen_rectangle_type *global_get_screen_rectangle = 0;

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_api_parser_main.exe 4ed_api_implementation.cpp " */
function API_Definition*
custom_api_construct(Arena *arena){
API_Definition *result = begin_api(arena, "custom");

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_api_parser_main.exe 4ed_api_implementation.cpp " */
api(custom) function b32 global_set_setting(Application_Links* app, Global_Setting_ID setting, i64 value);
api(custom) function Rect_f32 global_get_screen_rectangle(Application_Links* app);
api(custom) function Thread_Context* get_thread_context(Application_Links* app);

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_system_api.cpp" */
function void
system_api_fill_vtable(API_VTable_system *vtable){
vtable->error_box = system_error_box;
@ -58,6 +60,7 @@ vtable->set_key_mode = system_set_key_mode;
vtable->set_source_mixer = system_set_source_mixer;
vtable->set_destination_mixer = system_set_destination_mixer;
}
#if defined(DYNAMIC_LINK_API)
function void
system_api_read_vtable(API_VTable_system *vtable){

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_system_api.cpp" */
#define system_error_box_sig() void system_error_box(char* msg)
#define system_get_path_sig() String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code)
#define system_get_canonical_sig() String_Const_u8 system_get_canonical(Arena* arena, String_Const_u8 name)
@ -55,6 +57,7 @@
#define system_set_key_mode_sig() void system_set_key_mode(Key_Mode mode)
#define system_set_source_mixer_sig() void system_set_source_mixer(void* ctx, Audio_Mix_Sources_Function* mix_func)
#define system_set_destination_mixer_sig() void system_set_destination_mixer(Audio_Mix_Destination_Function* mix_func)
typedef void system_error_box_type(char* msg);
typedef String_Const_u8 system_get_path_type(Arena* arena, System_Path_Code path_code);
typedef String_Const_u8 system_get_canonical_type(Arena* arena, String_Const_u8 name);
@ -112,6 +115,7 @@ typedef Input_Modifier_Set system_get_keyboard_modifiers_type(Arena* arena);
typedef void system_set_key_mode_type(Key_Mode mode);
typedef void system_set_source_mixer_type(void* ctx, Audio_Mix_Sources_Function* mix_func);
typedef void system_set_destination_mixer_type(Audio_Mix_Destination_Function* mix_func);
struct API_VTable_system{
system_error_box_type *error_box;
system_get_path_type *get_path;
@ -171,6 +175,7 @@ system_set_key_mode_type *set_key_mode;
system_set_source_mixer_type *set_source_mixer;
system_set_destination_mixer_type *set_destination_mixer;
};
#if defined(STATIC_LINK_API)
internal void system_error_box(char* msg);
internal String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code);
@ -230,6 +235,7 @@ internal void system_set_key_mode(Key_Mode mode);
internal void system_set_source_mixer(void* ctx, Audio_Mix_Sources_Function* mix_func);
internal void system_set_destination_mixer(Audio_Mix_Destination_Function* mix_func);
#undef STATIC_LINK_API
#elif defined(DYNAMIC_LINK_API)
global system_error_box_type *system_error_box = 0;
global system_get_path_type *system_get_path = 0;

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_system_api.cpp" */
function API_Definition*
system_api_construct(Arena *arena){
API_Definition *result = begin_api(arena, "system");

View File

@ -1,3 +1,5 @@
/* Generated by "4ed_system_api.cpp" */
api(system) function void error_box(char* msg);
api(system) function String_Const_u8 get_path(Arena* arena, System_Path_Code path_code);
api(system) function String_Const_u8 get_canonical(Arena* arena, String_Const_u8 name);

View File

@ -1,7 +1,10 @@
/* Generated by "4ed_font_api.cpp" */
function void
font_api_fill_vtable(API_VTable_font *vtable){
vtable->make_face = font_make_face;
}
#if defined(DYNAMIC_LINK_API)
function void
font_api_read_vtable(API_VTable_font *vtable){

View File

@ -1,11 +1,17 @@
/* Generated by "4ed_font_api.cpp" */
#define font_make_face_sig() Face* font_make_face(Arena* arena, Face_Description* description, f32 scale_factor)
typedef Face* font_make_face_type(Arena* arena, Face_Description* description, f32 scale_factor);
struct API_VTable_font{
font_make_face_type *make_face;
};
#if defined(STATIC_LINK_API)
internal Face* font_make_face(Arena* arena, Face_Description* description, f32 scale_factor);
#undef STATIC_LINK_API
#elif defined(DYNAMIC_LINK_API)
global font_make_face_type *font_make_face = 0;
#undef DYNAMIC_LINK_API

View File

@ -1,13 +1,18 @@
/* Generated by "4ed_graphics_api.cpp" */
function void
graphics_api_fill_vtable(API_VTable_graphics *vtable){
vtable->get_texture = graphics_get_texture;
vtable->fill_texture = graphics_fill_texture;
vtable->free_texture = graphics_free_texture;
}
#if defined(DYNAMIC_LINK_API)
function void
graphics_api_read_vtable(API_VTable_graphics *vtable){
graphics_get_texture = vtable->get_texture;
graphics_fill_texture = vtable->fill_texture;
graphics_free_texture = vtable->free_texture;
}
#undef DYNAMIC_LINK_API
#endif

View File

@ -1,17 +1,28 @@
/* Generated by "4ed_graphics_api.cpp" */
#define graphics_get_texture_sig() u32 graphics_get_texture(Vec3_i32 dim, Texture_Kind texture_kind)
#define graphics_fill_texture_sig() b32 graphics_fill_texture(Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 dim, void* data)
#define graphics_free_texture_sig() void graphics_free_texture(u32 texid)
typedef u32 graphics_get_texture_type(Vec3_i32 dim, Texture_Kind texture_kind);
typedef b32 graphics_fill_texture_type(Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 dim, void* data);
typedef void graphics_free_texture_type(u32 texid);
struct API_VTable_graphics{
graphics_get_texture_type *get_texture;
graphics_fill_texture_type *fill_texture;
graphics_free_texture_type *free_texture;
};
#if defined(STATIC_LINK_API)
internal u32 graphics_get_texture(Vec3_i32 dim, Texture_Kind texture_kind);
internal b32 graphics_fill_texture(Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 dim, void* data);
internal void graphics_free_texture(u32 texid);
#undef STATIC_LINK_API
#elif defined(DYNAMIC_LINK_API)
global graphics_get_texture_type *graphics_get_texture = 0;
global graphics_fill_texture_type *graphics_fill_texture = 0;
global graphics_free_texture_type *graphics_free_texture = 0;
#undef DYNAMIC_LINK_API
#endif

View File

@ -53,6 +53,11 @@ gl__fill_texture(Texture_Kind texture_kind, u32 texture, Vec3_i32 p, Vec3_i32 di
return(result);
}
internal void
gl__free_texture(u32 texture){
glDeleteTextures(1, &texture);
}
internal void
gl__error_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam){
switch (id){

View File

@ -588,6 +588,11 @@ graphics_fill_texture_sig(){
return(gl__fill_texture(texture_kind, texture, p, dim, data));
}
internal
graphics_free_texture_sig(){
gl__free_texture(texid);
}
////////////////////////////
internal Face*

View File

@ -670,6 +670,11 @@ graphics_fill_texture_sig(){
return(gl__fill_texture(texture_kind, texture, p, dim, data));
}
internal
graphics_free_texture_sig(){
gl__free_texture(texid);
}
internal
font_make_face_sig(){
return(ft__font_make_face(arena, description, scale_factor));