initial
This commit is contained in:
commit
fb91a10918
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Example use of customization API
|
||||
*/
|
||||
|
||||
#include "4coder_custom.h"
|
||||
|
||||
// NOTE(allen): All this helper stuff is here to make the new API
|
||||
// work a lot like the old API
|
||||
struct Bind_Helper{
|
||||
Binding_Unit *cursor, *start, *end;
|
||||
Binding_Unit *header, *map;
|
||||
int write_total;
|
||||
int error;
|
||||
};
|
||||
|
||||
#define BH_ERR_NONE 0
|
||||
#define BH_ERR_MISSING_END_MAP 1
|
||||
#define BH_ERR_MISSING_BEGIN_MAP 2
|
||||
|
||||
inline Binding_Unit*
|
||||
write_unit(Bind_Helper *helper, Binding_Unit unit){
|
||||
Binding_Unit *p = 0;
|
||||
helper->write_total += sizeof(Binding_Unit);
|
||||
if (helper->error == 0 && helper->cursor != helper->end){
|
||||
p = helper->cursor++;
|
||||
*p = unit;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline Bind_Helper
|
||||
begin_bind_helper(void *data, int size){
|
||||
Bind_Helper result;
|
||||
|
||||
result.header = 0;
|
||||
result.map = 0;
|
||||
result.write_total = 0;
|
||||
result.error = 0;
|
||||
|
||||
result.cursor = (Binding_Unit*)data;
|
||||
result.start = result.cursor;
|
||||
result.end = result.start + size / sizeof(Binding_Unit);
|
||||
|
||||
Binding_Unit unit;
|
||||
unit.type = UNIT_HEADER;
|
||||
unit.header.total_size = sizeof(Binding_Unit);
|
||||
result.header = write_unit(&result, unit);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void
|
||||
begin_map(Bind_Helper *helper, int mapid){
|
||||
if (helper->map != 0 && helper->error == 0) helper->error = BH_ERR_MISSING_END_MAP;
|
||||
|
||||
Binding_Unit unit;
|
||||
unit.type = UNIT_MAP_BEGIN;
|
||||
unit.map_begin.mapid = mapid;
|
||||
helper->map = write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline void
|
||||
end_map(Bind_Helper *helper){
|
||||
if (helper->map == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN_MAP;
|
||||
|
||||
helper->map = 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
bind(Bind_Helper *helper, short code, unsigned char modifiers, int cmdid){
|
||||
if (helper->map == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN_MAP;
|
||||
|
||||
Binding_Unit unit;
|
||||
unit.type = UNIT_BINDING;
|
||||
unit.binding.command_id = cmdid;
|
||||
unit.binding.code = code;
|
||||
unit.binding.modifiers = modifiers;
|
||||
|
||||
write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline void
|
||||
bind_me(Bind_Helper *helper, short code, unsigned char modifiers, Custom_Command_Function *func){
|
||||
if (helper->map == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN_MAP;
|
||||
|
||||
Binding_Unit unit;
|
||||
unit.type = UNIT_CALLBACK;
|
||||
unit.callback.func = func;
|
||||
unit.callback.code = code;
|
||||
unit.callback.modifiers = modifiers;
|
||||
|
||||
write_unit(helper, unit);
|
||||
}
|
||||
|
||||
inline void
|
||||
bind_vanilla_keys(Bind_Helper *helper, int cmdid){
|
||||
bind(helper, 0, 0, cmdid);
|
||||
}
|
||||
|
||||
inline void
|
||||
bind_me_vanilla_keys(Bind_Helper *helper, Custom_Command_Function *func){
|
||||
bind_me(helper, 0, 0, func);
|
||||
}
|
||||
|
||||
inline void
|
||||
end_bind_helper(Bind_Helper *helper){
|
||||
if (helper->header){
|
||||
helper->header->header.total_size = (int)(helper->cursor - helper->start);
|
||||
helper->header->header.error = helper->error;
|
||||
}
|
||||
}
|
||||
|
||||
#define exec_command app.exec_command
|
||||
#define fulfill_interaction app.fulfill_interaction
|
||||
|
||||
extern "C" START_HOOK_SIG(start_hook){
|
||||
exec_command(cmd_context, cmdid_open_panel_vsplit);
|
||||
exec_command(cmd_context, cmdid_change_active_panel);
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(open_in_other){
|
||||
exec_command(cmd_context, cmdid_change_active_panel);
|
||||
exec_command(cmd_context, cmdid_interactive_open);
|
||||
}
|
||||
|
||||
extern "C" GET_BINDING_DATA(get_bindings){
|
||||
Bind_Helper context_actual = begin_bind_helper(data, size);
|
||||
Bind_Helper *context = &context_actual;
|
||||
|
||||
begin_map(context, MAPID_GLOBAL);
|
||||
|
||||
// NOTE(allen): Here put the contents of your set_global_bindings
|
||||
bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit);
|
||||
bind(context, '-', MDFR_CTRL, cmdid_open_panel_hsplit);
|
||||
bind(context, 'P', MDFR_CTRL, cmdid_close_panel);
|
||||
bind(context, 'n', MDFR_CTRL, cmdid_interactive_new);
|
||||
bind(context, 'o', MDFR_CTRL, cmdid_interactive_open);
|
||||
bind(context, ',', MDFR_CTRL, cmdid_change_active_panel);
|
||||
bind(context, 'k', MDFR_CTRL, cmdid_interactive_kill_file);
|
||||
bind(context, 'i', MDFR_CTRL, cmdid_interactive_switch_file);
|
||||
bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker);
|
||||
bind(context, 'x', MDFR_ALT, cmdid_open_menu);
|
||||
bind_me(context, 'o', MDFR_ALT, open_in_other);
|
||||
|
||||
end_map(context);
|
||||
|
||||
|
||||
begin_map(context, MAPID_FILE);
|
||||
|
||||
// NOTE(allen): This is a new concept in the API. Binding this can be thought of as binding
|
||||
// all combos which have an ascii code (shifted or not) and unmodified by CTRL or ALT.
|
||||
// As of now, if this is used it cannot be overriden for particular combos; this overrides
|
||||
// normal bindings.
|
||||
bind_vanilla_keys(context, cmdid_write_character);
|
||||
|
||||
// NOTE(allen): Here put the contents of your set_file_bindings
|
||||
bind(context, codes->left, MDFR_NONE, cmdid_move_left);
|
||||
bind(context, codes->right, MDFR_NONE, cmdid_move_right);
|
||||
bind(context, codes->del, MDFR_NONE, cmdid_delete);
|
||||
bind(context, codes->back, MDFR_NONE, cmdid_backspace);
|
||||
bind(context, codes->up, MDFR_NONE, cmdid_move_up);
|
||||
bind(context, codes->down, MDFR_NONE, cmdid_move_down);
|
||||
bind(context, codes->end, MDFR_NONE, cmdid_seek_end_of_line);
|
||||
bind(context, codes->home, MDFR_NONE, cmdid_seek_beginning_of_line);
|
||||
bind(context, codes->page_up, MDFR_NONE, cmdid_page_up);
|
||||
bind(context, codes->page_down, MDFR_NONE, cmdid_page_down);
|
||||
|
||||
bind(context, codes->right, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_right);
|
||||
bind(context, codes->left, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_left);
|
||||
bind(context, codes->up, MDFR_CTRL, cmdid_seek_whitespace_up);
|
||||
bind(context, codes->down, MDFR_CTRL, cmdid_seek_whitespace_down);
|
||||
|
||||
bind(context, ' ', MDFR_CTRL, cmdid_set_mark);
|
||||
bind(context, 'm', MDFR_CTRL, cmdid_cursor_mark_swap);
|
||||
bind(context, 'c', MDFR_CTRL, cmdid_copy);
|
||||
bind(context, 'x', MDFR_CTRL, cmdid_cut);
|
||||
bind(context, 'v', MDFR_CTRL, cmdid_paste);
|
||||
bind(context, 'V', MDFR_CTRL, cmdid_paste_next);
|
||||
bind(context, 'd', MDFR_CTRL, cmdid_delete_chunk);
|
||||
bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap);
|
||||
bind(context, 'L', MDFR_CTRL, cmdid_toggle_endline_mode);
|
||||
bind(context, 'u', MDFR_CTRL, cmdid_to_uppercase);
|
||||
bind(context, 'j', MDFR_CTRL, cmdid_to_lowercase);
|
||||
bind(context, '?', MDFR_CTRL, cmdid_toggle_show_whitespace);
|
||||
bind(context, '`', MDFR_CTRL, cmdid_clean_line);
|
||||
bind(context, '~', MDFR_CTRL, cmdid_clean_all_lines);
|
||||
bind(context, '1', MDFR_CTRL, cmdid_eol_dosify);
|
||||
bind(context, '!', MDFR_CTRL, cmdid_eol_nixify);
|
||||
bind(context, 'f', MDFR_CTRL, cmdid_search);
|
||||
bind(context, 'r', MDFR_CTRL, cmdid_rsearch);
|
||||
bind(context, 'g', MDFR_CTRL, cmdid_goto_line);
|
||||
|
||||
bind(context, '\t', MDFR_CTRL, cmdid_auto_tab);
|
||||
|
||||
bind(context, 'K', MDFR_CTRL, cmdid_kill_file);
|
||||
bind(context, 'O', MDFR_CTRL, cmdid_reopen);
|
||||
bind(context, 'w', MDFR_CTRL, cmdid_interactive_save_as);
|
||||
bind(context, 's', MDFR_CTRL, cmdid_save);
|
||||
|
||||
end_map(context);
|
||||
end_bind_helper(context);
|
||||
|
||||
return context->write_total;
|
||||
}
|
||||
|
||||
inline void
|
||||
strset_(char *dst, char *src){
|
||||
do{
|
||||
*dst++ = *src++;
|
||||
}while (*src);
|
||||
}
|
||||
|
||||
#define strset(d,s) if (sizeof(s) <= sizeof(d)) strset_(d,s)
|
||||
|
||||
extern "C" SET_EXTRA_FONT_SIG(set_extra_font){
|
||||
strset(font_out->file_name, "liberation-mono.ttf");
|
||||
strset(font_out->font_name, "BIG");
|
||||
font_out->size = 25;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
|
||||
#define MDFR_NONE 0
|
||||
#define MDFR_CTRL 1
|
||||
#define MDFR_ALT 2
|
||||
#define MDFR_SHIFT 4
|
||||
|
||||
typedef unsigned short Code;
|
||||
|
||||
struct Key_Codes{
|
||||
Code back;
|
||||
Code up;
|
||||
Code down;
|
||||
Code left;
|
||||
Code right;
|
||||
Code del;
|
||||
Code insert;
|
||||
Code home;
|
||||
Code end;
|
||||
Code page_up;
|
||||
Code page_down;
|
||||
Code esc;
|
||||
|
||||
#if 0 // TODO(allen): Get these working sometime
|
||||
union{
|
||||
struct{
|
||||
Code f1;
|
||||
Code f2;
|
||||
Code f3;
|
||||
Code f4;
|
||||
Code f5;
|
||||
Code f6;
|
||||
Code f7;
|
||||
Code f8;
|
||||
|
||||
Code f9;
|
||||
Code f10;
|
||||
Code f11;
|
||||
Code f12;
|
||||
Code f13;
|
||||
Code f14;
|
||||
Code f15;
|
||||
Code f16;
|
||||
};
|
||||
Code f[16];
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
enum Command_ID{
|
||||
cmdid_null,
|
||||
cmdid_write_character,
|
||||
cmdid_seek_whitespace_right,
|
||||
cmdid_seek_whitespace_left,
|
||||
cmdid_seek_whitespace_up,
|
||||
cmdid_seek_whitespace_down,
|
||||
cmdid_seek_token_left,
|
||||
cmdid_seek_token_right,
|
||||
cmdid_seek_white_or_token_left,
|
||||
cmdid_seek_white_or_token_right,
|
||||
cmdid_seek_alphanumeric_left,
|
||||
cmdid_seek_alphanumeric_right,
|
||||
cmdid_seek_alphanumeric_or_camel_left,
|
||||
cmdid_seek_alphanumeric_or_camel_right,
|
||||
cmdid_search,
|
||||
cmdid_rsearch,
|
||||
cmdid_goto_line,
|
||||
cmdid_set_mark,
|
||||
cmdid_copy,
|
||||
cmdid_cut,
|
||||
cmdid_paste,
|
||||
cmdid_paste_next,
|
||||
cmdid_delete_chunk,
|
||||
cmdid_interactive_new,
|
||||
cmdid_interactive_open,
|
||||
cmdid_reopen,
|
||||
cmdid_save,
|
||||
cmdid_interactive_save_as,
|
||||
cmdid_change_active_panel,
|
||||
cmdid_interactive_switch_file,
|
||||
cmdid_interactive_kill_file,
|
||||
cmdid_kill_file,
|
||||
cmdid_toggle_line_wrap,
|
||||
cmdid_toggle_endline_mode,
|
||||
cmdid_to_uppercase,
|
||||
cmdid_to_lowercase,
|
||||
cmdid_toggle_show_whitespace,
|
||||
cmdid_clean_line,
|
||||
cmdid_clean_all_lines,
|
||||
cmdid_eol_dosify,
|
||||
cmdid_eol_nixify,
|
||||
cmdid_auto_tab,
|
||||
cmdid_open_panel_vsplit,
|
||||
cmdid_open_panel_hsplit,
|
||||
cmdid_close_panel,
|
||||
cmdid_move_left,
|
||||
cmdid_move_right,
|
||||
cmdid_delete,
|
||||
cmdid_backspace,
|
||||
cmdid_move_up,
|
||||
cmdid_move_down,
|
||||
cmdid_seek_end_of_line,
|
||||
cmdid_seek_beginning_of_line,
|
||||
cmdid_page_up,
|
||||
cmdid_page_down,
|
||||
cmdid_open_color_tweaker,
|
||||
cmdid_close_minor_view,
|
||||
cmdid_cursor_mark_swap,
|
||||
cmdid_open_menu,
|
||||
//
|
||||
cmdid_count
|
||||
};
|
||||
|
||||
struct Extra_Font{
|
||||
char file_name[256];
|
||||
char font_name[24];
|
||||
int size;
|
||||
};
|
||||
|
||||
#define GET_BINDING_DATA(name) int name(void *data, int size, Key_Codes *codes)
|
||||
#define SET_EXTRA_FONT_SIG(name) void name(Extra_Font *font_out)
|
||||
#define CUSTOM_COMMAND_SIG(name) void name(void *cmd_context, struct Application_Links app)
|
||||
#define START_HOOK_SIG(name) void name(void *cmd_context, struct Application_Links app)
|
||||
|
||||
extern "C"{
|
||||
typedef CUSTOM_COMMAND_SIG(Custom_Command_Function);
|
||||
typedef GET_BINDING_DATA(Get_Binding_Data_Function);
|
||||
typedef SET_EXTRA_FONT_SIG(Set_Extra_Font_Function);
|
||||
typedef START_HOOK_SIG(Start_Hook_Function);
|
||||
}
|
||||
|
||||
#define EXECUTE_COMMAND_SIG(name) void name(void *cmd_context, int command_id)
|
||||
#define FULFILL_INTERACTION_SIG(name) void name(void *cmd_context, char *data, bool full_set)
|
||||
|
||||
extern "C"{
|
||||
typedef EXECUTE_COMMAND_SIG(Exec_Command_Function);
|
||||
typedef FULFILL_INTERACTION_SIG(Fulfill_Interaction_Function);
|
||||
}
|
||||
|
||||
struct Application_Links{
|
||||
Exec_Command_Function *exec_command;
|
||||
Fulfill_Interaction_Function *fulfill_interaction;
|
||||
};
|
||||
|
||||
enum Binding_Unit_Type{
|
||||
UNIT_HEADER,
|
||||
UNIT_MAP_BEGIN,
|
||||
UNIT_BINDING,
|
||||
UNIT_CALLBACK
|
||||
};
|
||||
|
||||
enum Map_ID{
|
||||
MAPID_GLOBAL,
|
||||
MAPID_FILE
|
||||
};
|
||||
|
||||
struct Binding_Unit{
|
||||
Binding_Unit_Type type;
|
||||
union{
|
||||
struct{ int total_size; int error; } header;
|
||||
|
||||
struct{ int mapid; } map_begin;
|
||||
|
||||
struct{
|
||||
int command_id;
|
||||
short code;
|
||||
unsigned char modifiers;
|
||||
} binding;
|
||||
|
||||
struct{
|
||||
Custom_Command_Function *func;
|
||||
short code;
|
||||
unsigned char modifiers;
|
||||
} callback;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/* "4cpp" Open C++ Parser v0.1: Clear Config
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
NOTES ON USE:
|
||||
This file is used to clear options. The main use for this is for cases when you want
|
||||
it include different portions of the library with different settings. So that the compiler
|
||||
does not complain about redifintion, and so that you do not have to undef everything yourself
|
||||
this is provided to undef everything at once.
|
||||
*/
|
||||
|
||||
#ifdef FCPP_NO_CRT
|
||||
#undef FCPP_NO_CRT
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_NO_MALLOC
|
||||
#undef FCPP_NO_MALLOC
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_NO_ASSERT
|
||||
#undef FCPP_NO_ASSERT
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_NO_STRING
|
||||
#undef FCPP_NO_STRING
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_GET_MEMORY
|
||||
#undef FCPP_GET_MEMORY
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_FREE_MEMORY
|
||||
#undef FCPP_FREE_MEMORY
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_ASSERT
|
||||
#undef FCPP_ASSERT
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_MEM_COPY
|
||||
#undef FCPP_MEM_COPY
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_MEM_MOVE
|
||||
#undef FCPP_MEM_MOVE
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_LINK
|
||||
#undef FCPP_LINK
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_EXTERN
|
||||
#undef FCPP_EXTERN
|
||||
#endif
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/* "4cpp" Open C++ Parser v0.1: Config
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
NOTES ON USE:
|
||||
This file is used to configure 4cpp options at the begining of 4cpp files.
|
||||
It is not meant to be used directly.
|
||||
*/
|
||||
|
||||
#ifdef FCPP_NO_CRT
|
||||
# ifndef FCPP_NO_MALLOC
|
||||
# define FCPP_NO_MALLOC
|
||||
# endif
|
||||
# ifndef FCPP_NO_ASSERT
|
||||
# define FCPP_NO_ASSERT
|
||||
# endif
|
||||
# ifndef FCPP_NO_STRING
|
||||
# define FCPP_NO_STRING
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef FCPP_FORBID_MALLOC
|
||||
# define FCPP_NO_MALLOC
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_NO_MALLOC
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_NO_ASSERT
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_NO_STRING
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_NO_MALLOC
|
||||
# ifndef FCPP_GET_MEMORY
|
||||
# define FCPP_GET_MEMORY malloc
|
||||
# endif
|
||||
# ifndef FCPP_FREE_MEMORY
|
||||
# define FCPP_FREE_MEMORY free
|
||||
# endif
|
||||
#else
|
||||
# ifndef FCPP_FORBID_MALLOC
|
||||
# ifndef FCPP_GET_MEMORY
|
||||
# error Missing definition for FCPP_GET_MEMORY
|
||||
# endif
|
||||
# ifndef FCPP_FREE_MEMORY
|
||||
# error Missing definition for FCPP_FREE_MEMORY
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_NO_ASSERT
|
||||
# ifndef FCPP_ASSERT
|
||||
# define FCPP_ASSERT assert
|
||||
# endif
|
||||
#else
|
||||
# ifndef FCPP_ASSERT
|
||||
# define FCPP_ASSERT(x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_NO_STRING
|
||||
# ifndef FCPP_MEM_COPY
|
||||
# define FCPP_MEM_COPY memcpy
|
||||
# endif
|
||||
# ifndef FCPP_MEM_MOVE
|
||||
# define FCPP_MEM_MOVE memmove
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FCPP_LINK
|
||||
# ifdef FCPP_EXTERN
|
||||
# define FCPP_LINK extern
|
||||
# else
|
||||
# define FCPP_LINK static
|
||||
# endif
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,997 @@
|
|||
/* "4cpp" Open C++ Parser v0.1: String
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
NOTES ON USE:
|
||||
OPTIONS:
|
||||
Set options by defining macros before including this file
|
||||
|
||||
FCPP_STRING_IMPLEMENTATION - causes this file to output function implementations
|
||||
- this option is unset after use so that future includes of this file
|
||||
in the same unit do not continue to output implementations
|
||||
|
||||
FCPP_LINK - defines linkage of non-inline functions, defaults to static
|
||||
FCPP_EXTERN changes FCPP_LINK default to extern, this option is ignored if FCPP_LINK is defined
|
||||
|
||||
include the file "4cpp_clear_config.h" if yo want to undefine all options for some reason
|
||||
|
||||
HIDDEN DEPENDENCIES:
|
||||
none
|
||||
*/
|
||||
|
||||
// TOP
|
||||
// TODO(allen):
|
||||
// - comments
|
||||
// - memcpy / memmove replacements (different file for optimization options?)
|
||||
//
|
||||
|
||||
#include "4cpp_config.h"
|
||||
|
||||
#ifndef FCPP_STRING_INC
|
||||
#define FCPP_STRING_INC
|
||||
|
||||
struct String{
|
||||
char *str;
|
||||
int size;
|
||||
int memory_size;
|
||||
};
|
||||
|
||||
inline bool char_not_slash(char c) { return (c != '\\' && c != '/'); }
|
||||
inline bool char_is_slash(char c) { return (c == '\\' || c == '/'); }
|
||||
|
||||
inline char char_to_upper(char c) { return (c >= 'a' && c <= 'z') ? c + (char)('A' - 'a') : c; }
|
||||
inline char char_to_lower(char c) { return (c >= 'A' && c <= 'Z') ? c - (char)('A' - 'a') : c; }
|
||||
|
||||
inline bool char_is_whitespace(char c) { return (c == ' ' || c == '\n' || c == '\r' || c == '\t'); }
|
||||
inline bool char_is_white_not_r(char c) { return (c == ' ' || c == '\n' || c == '\t'); }
|
||||
inline bool char_is_lower(char c) { return (c >= 'a' && c <= 'z'); }
|
||||
inline bool char_is_upper(char c) { return (c >= 'A' && c <= 'Z'); }
|
||||
inline bool char_is_alpha(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); }
|
||||
inline bool char_is_alpha_true(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); }
|
||||
inline bool char_is_numeric(char c) { return (c >= '0' && c <= '9'); }
|
||||
inline bool char_is_alpha_numeric_true(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'); }
|
||||
inline bool char_is_alpha_numeric(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'); }
|
||||
inline bool char_is_hex(char c) { return c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'; }
|
||||
inline bool char_is_basic(char c) { return c >= ' ' && c <= '~'; }
|
||||
|
||||
inline String make_string(char *s, int size, int mem_size);
|
||||
inline String make_string(char *s, int size);
|
||||
|
||||
#define make_lit_string(str) (make_string((char*)(str), sizeof(str)-1, sizeof(str)))
|
||||
#define make_fixed_width_string(str) (make_string((char*)(str), 0, sizeof(str)))
|
||||
|
||||
inline String make_string_slowly(char *s);
|
||||
inline char* make_c_str(String s);
|
||||
|
||||
inline String substr(String str, int start);
|
||||
inline String substr(String str, int start, int size);
|
||||
inline String substr_slowly(char *s, int start);
|
||||
inline String substr(char *s, int start, int size);
|
||||
inline String tailstr(String s);
|
||||
|
||||
|
||||
FCPP_LINK int str_size(char *s);
|
||||
|
||||
FCPP_LINK bool match(char *a, char *b);
|
||||
FCPP_LINK bool match(String a, char *b);
|
||||
inline bool match(char *a, String b) { return match(b,a); }
|
||||
FCPP_LINK bool match(String a, String b);
|
||||
|
||||
FCPP_LINK bool match_part(char *a, char *b, int *len);
|
||||
FCPP_LINK bool match_part(String a, char *b, int *len);
|
||||
inline bool match_part(char *a, char *b) { int x; return match_part(a,b,&x); }
|
||||
inline bool match_part(String a, char *b) { int x; return match_part(a,b,&x); }
|
||||
FCPP_LINK bool match_part(char *a, String b);
|
||||
FCPP_LINK bool match_part(String a, String b);
|
||||
|
||||
FCPP_LINK int find(char *s, int start, char c);
|
||||
FCPP_LINK int find(String s, int start, char c);
|
||||
FCPP_LINK int find(char *s, int start, char *c);
|
||||
FCPP_LINK int find(String s, int start, char *c);
|
||||
|
||||
FCPP_LINK int find_substr(char *s, int start, String seek);
|
||||
FCPP_LINK int find_substr(String s, int start, String seek);
|
||||
FCPP_LINK int rfind_substr(String s, int start, String seek);
|
||||
|
||||
FCPP_LINK int find_substr_unsensitive(char *s, int start, String seek);
|
||||
FCPP_LINK int find_substr_unsensitive(String s, int start, String seek);
|
||||
|
||||
inline bool has_substr(char *s, String seek) { return (s[find_substr(s, 0, seek)] != 0); }
|
||||
inline bool has_substr(String s, String seek) { return (find_substr(s, 0, seek) < s.size); }
|
||||
|
||||
inline bool has_substr_unsensitive(char *s, String seek) { return (s[find_substr_unsensitive(s, 0, seek)] != 0); }
|
||||
inline bool has_substr_unsensitive(String s, String seek) { return (find_substr_unsensitive(s, 0, seek) < s.size); }
|
||||
|
||||
FCPP_LINK int int_to_str_size(int x);
|
||||
FCPP_LINK int int_to_str(int x, char *s_out);
|
||||
FCPP_LINK bool int_to_str(int x, String *s_out);
|
||||
FCPP_LINK bool append_int_to_str(int x, String *s_out);
|
||||
|
||||
FCPP_LINK int str_to_int(String s);
|
||||
FCPP_LINK int hexchar_to_int(char c);
|
||||
FCPP_LINK int int_to_hexchar(char c);
|
||||
FCPP_LINK int hexstr_to_int(String s);
|
||||
|
||||
FCPP_LINK void copy_fast_unsafe(char *dest, char *src);
|
||||
FCPP_LINK void copy_fast_unsafe(char *dest, String src);
|
||||
FCPP_LINK bool copy_checked(String *dest, String src);
|
||||
FCPP_LINK bool copy_partial(String *dest, char *src);
|
||||
FCPP_LINK bool copy_partial(String *dest, String src);
|
||||
|
||||
inline void copy(char *dest, char *src) { copy_fast_unsafe(dest, src); }
|
||||
inline void copy(String *dest, String src) { copy_checked(dest, src); }
|
||||
inline void copy(String *dest, char *src) { copy_partial(dest, src); }
|
||||
|
||||
FCPP_LINK bool append_checked(String *dest, String src);
|
||||
FCPP_LINK bool append_partial(String *dest, char *src);
|
||||
FCPP_LINK bool append_partial(String *dest, String src);
|
||||
|
||||
FCPP_LINK bool append(String *dest, char c);
|
||||
inline bool append(String *dest, String src) { return append_partial(dest, src); }
|
||||
inline bool append(String *dest, char *src) { return append_partial(dest, src); }
|
||||
inline void terminate_with_null(String *str)
|
||||
{ if (str->size < str->memory_size) str->str[str->size] = 0; else str->str[str->size-1] = 0; }
|
||||
|
||||
FCPP_LINK int compare(char *a, char *b);
|
||||
FCPP_LINK int compare(String a, char *b);
|
||||
inline int compare(char *a, String b) { return -compare(b,a); }
|
||||
FCPP_LINK int compare(String a, String b);
|
||||
|
||||
FCPP_LINK int reverse_seek_slash(String str);
|
||||
inline bool get_front_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, reverse_seek_slash(dir) + 1)); }
|
||||
inline bool get_path_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, 0, reverse_seek_slash(dir) + 1)); }
|
||||
FCPP_LINK bool set_last_folder(String *dir, char *folder_name);
|
||||
FCPP_LINK bool set_last_folder(String *dir, String folder_name);
|
||||
FCPP_LINK String file_extension(String str);
|
||||
FCPP_LINK String file_extension_slowly(char *str);
|
||||
|
||||
inline String make_string(char *str, int size, int mem_size){
|
||||
String result;
|
||||
result.str = str;
|
||||
result.size = size;
|
||||
result.memory_size = mem_size;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String
|
||||
make_string(char *str, int size){
|
||||
String result;
|
||||
result.str = str;
|
||||
result.size = size;
|
||||
result.memory_size = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String
|
||||
make_string_slowly(char *str){
|
||||
String result;
|
||||
result.str = str;
|
||||
result.size = str_size(str);
|
||||
result.memory_size = result.size;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline char*
|
||||
make_c_str(String str){
|
||||
if (str.size < str.memory_size){
|
||||
str.str[str.size] = 0;
|
||||
}
|
||||
else{
|
||||
str.str[str.memory_size-1] = 0;
|
||||
}
|
||||
return (char*)str.str;
|
||||
}
|
||||
|
||||
inline String
|
||||
substr(String str, int start){
|
||||
String result;
|
||||
result.str = str.str + start;
|
||||
result.size = str.size - start;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String
|
||||
substr(String str, int start, int size){
|
||||
String result;
|
||||
result.str = str.str + start;
|
||||
if (start + size > str.size){
|
||||
result.size = str.size - start;
|
||||
}
|
||||
else{
|
||||
result.size = size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String
|
||||
substr_slowly(char *str, int start){
|
||||
String result;
|
||||
result.str = str + start;
|
||||
result.size = str_size(result.str);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String
|
||||
substr(char *str, int start, int size){
|
||||
String result;
|
||||
result.str = str + start;
|
||||
result.size = size;
|
||||
for (int i = 0; i < size; ++i){
|
||||
if (result.str[i] == 0){
|
||||
result.size = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String
|
||||
tailstr(String str){
|
||||
String result;
|
||||
result.str = str.str + str.size;
|
||||
result.memory_size = str.memory_size - str.size;
|
||||
result.size = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // #ifndef FCPP_STRING_INC
|
||||
|
||||
#ifdef FCPP_STRING_IMPLEMENTATION
|
||||
|
||||
FCPP_LINK int
|
||||
str_size(char *str){
|
||||
int i = 0;
|
||||
while (str[i]) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match(char *a, char *b){
|
||||
for (int i = 0;; ++i){
|
||||
if (a[i] != b[i]){
|
||||
return 0;
|
||||
}
|
||||
if (a[i] == 0){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match(String a, char *b){
|
||||
int i = 0;
|
||||
for (; i < a.size; ++i){
|
||||
if (a.str[i] != b[i]){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (b[i] != 0){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match(String a, String b){
|
||||
if (a.size != b.size){
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < b.size; ++i){
|
||||
if (a.str[i] != b.str[i]){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match_part(char *a, char *b, int *len){
|
||||
int i;
|
||||
for (i = 0; b[i] != 0; ++i){
|
||||
if (a[i] != b[i]){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*len = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match_part(String a, char *b, int *len){
|
||||
int i;
|
||||
for (i = 0; b[i] != 0; ++i){
|
||||
if (a.str[i] != b[i] || i == a.size){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*len = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match_part(char *a, String b){
|
||||
for (int i = 0; i != b.size; ++i){
|
||||
if (a[i] != b.str[i]){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
match_part(String a, String b){
|
||||
if (a.size < b.size){
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < b.size; ++i){
|
||||
if (a.str[i] != b.str[i]){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find(char *str, int start, char character){
|
||||
int i = start;
|
||||
while (str[i] != character && str[i] != 0) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find(String str, int start, char character){
|
||||
int i = start;
|
||||
while (i < str.size && str.str[i] != character) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find(char *str, int start, char *characters){
|
||||
int i = start, j;
|
||||
while (str[i] != 0){
|
||||
for (j = 0; characters[j]; ++j){
|
||||
if (str[i] == characters[j]){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find(String str, int start, char *characters){
|
||||
int i = start, j;
|
||||
while (i < str.size){
|
||||
for (j = 0; characters[j]; ++j){
|
||||
if (str.str[i] == characters[j]){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find_substr(char *str, int start, String seek){
|
||||
int i, j, k;
|
||||
bool hit;
|
||||
|
||||
if (seek.size == 0){
|
||||
return str_size(str);
|
||||
}
|
||||
for (i = start; str[i]; ++i){
|
||||
if (str[i] == seek.str[0]){
|
||||
hit = 1;
|
||||
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
|
||||
if (str[k] != seek.str[j]){
|
||||
hit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find_substr(String str, int start, String seek){
|
||||
int stop_at, i, j, k;
|
||||
bool hit;
|
||||
|
||||
if (seek.size == 0){
|
||||
return str.size;
|
||||
}
|
||||
stop_at = str.size - seek.size + 1;
|
||||
for (i = start; i < stop_at; ++i){
|
||||
if (str.str[i] == seek.str[0]){
|
||||
hit = 1;
|
||||
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
|
||||
if (str.str[k] != seek.str[j]){
|
||||
hit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return str.size;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
rfind_substr(String str, int start, String seek){
|
||||
int i, j, k;
|
||||
bool hit;
|
||||
|
||||
if (seek.size == 0){
|
||||
return -1;
|
||||
}
|
||||
if (start + seek.size > str.size){
|
||||
start = str.size - seek.size;
|
||||
}
|
||||
for (i = start; i >= 0; --i){
|
||||
if (str.str[i] == seek.str[0]){
|
||||
hit = 1;
|
||||
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
|
||||
if (str.str[k] != seek.str[j]){
|
||||
hit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find_substr_unsensitive(char *str, int start, String seek){
|
||||
int i, j, k;
|
||||
bool hit;
|
||||
char a_upper, b_upper;
|
||||
|
||||
if (seek.size == 0){
|
||||
return str_size(str);
|
||||
}
|
||||
for (i = start; str[i]; ++i){
|
||||
if (str[i] == seek.str[0]){
|
||||
hit = 1;
|
||||
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
|
||||
a_upper = char_to_upper(str[k]);
|
||||
b_upper = char_to_upper(seek.str[j]);
|
||||
if (a_upper != b_upper){
|
||||
hit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
find_substr_unsensitive(String str, int start, String seek){
|
||||
int i, j, k;
|
||||
int stop_at;
|
||||
bool hit;
|
||||
char a_upper, b_upper;
|
||||
|
||||
if (seek.size == 0){
|
||||
return str.size;
|
||||
}
|
||||
stop_at = str.size - seek.size + 1;
|
||||
for (i = start; i < stop_at; ++i){
|
||||
if (str.str[i] == seek.str[0]){
|
||||
hit = 1;
|
||||
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
|
||||
a_upper = char_to_upper(str.str[k]);
|
||||
b_upper = char_to_upper(seek.str[j]);
|
||||
if (a_upper != b_upper){
|
||||
hit = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return str.size;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
int_to_str_size(int x){
|
||||
int size;
|
||||
if (x < 0){
|
||||
size = 0;
|
||||
}
|
||||
else{
|
||||
size = 1;
|
||||
x /= 10;
|
||||
while (x != 0){
|
||||
x /= 10;
|
||||
++size;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
int_to_str(int x, char *str){
|
||||
int size, i, j;
|
||||
bool negative;
|
||||
char temp;
|
||||
|
||||
size = 0;
|
||||
if (x == 0){
|
||||
str[0] = '0';
|
||||
str[1] = 0;
|
||||
size = 1;
|
||||
}
|
||||
else{
|
||||
size = 0;
|
||||
negative = 0;
|
||||
if (x < 0){
|
||||
negative = 1;
|
||||
x = -x;
|
||||
str[size++] = '-';
|
||||
}
|
||||
while (x != 0){
|
||||
i = x % 10;
|
||||
x /= 10;
|
||||
str[size++] = (char)('0' + i);
|
||||
}
|
||||
// NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative
|
||||
// because - should not be flipped if it is negative :)
|
||||
for (i = negative, j = size-1; i < j; ++i, --j){
|
||||
temp = str[i];
|
||||
str[i] = str[j];
|
||||
str[j] = temp;
|
||||
}
|
||||
str[size] = 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
int_to_str(int x, String *dest){
|
||||
bool result = 1;
|
||||
char *str = dest->str;
|
||||
int memory_size = dest->memory_size;
|
||||
int size, i, j;
|
||||
bool negative;
|
||||
|
||||
if (x == 0){
|
||||
str[0] = '0';
|
||||
dest->size = 1;
|
||||
}
|
||||
else{
|
||||
size = 0;
|
||||
negative = 0;
|
||||
if (x < 0){
|
||||
negative = 1;
|
||||
x = -x;
|
||||
str[size++] = '-';
|
||||
}
|
||||
while (x != 0){
|
||||
if (size == memory_size){
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
i = x % 10;
|
||||
x /= 10;
|
||||
str[size++] = (char)('0' + i);
|
||||
}
|
||||
if (result){
|
||||
// NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative
|
||||
// because - should not be flipped if it is negative :)
|
||||
for (i = negative, j = size-1; i < j; ++i, --j){
|
||||
char temp = str[i];
|
||||
str[i] = str[j];
|
||||
str[j] = temp;
|
||||
}
|
||||
dest->size = size;
|
||||
}
|
||||
else{
|
||||
dest->size = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
append_int_to_str(int x, String *dest){
|
||||
String last_part = tailstr(*dest);
|
||||
bool result = int_to_str(x, &last_part);
|
||||
if (result){
|
||||
dest->size += last_part.size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
str_to_int(String str){
|
||||
int x, i;
|
||||
if (str.size == 0){
|
||||
x = 0;
|
||||
}
|
||||
else{
|
||||
x = str.str[0] - '0';
|
||||
for (i = 1; i < str.size; ++i){
|
||||
x *= 10;
|
||||
x += str.str[i] - '0';
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
hexchar_to_int(char c){
|
||||
int x;
|
||||
if (c >= '0' && c <= '9'){
|
||||
x = c-'0';
|
||||
}
|
||||
else if (c > 'F'){
|
||||
x = c+(10-'a');
|
||||
}
|
||||
else{
|
||||
x = c+(10-'A');
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
FCPP_LINK char
|
||||
int_to_hexchar(int x){
|
||||
return (x<10)?((char)x+'0'):((char)x+'a'-10);
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
hexstr_to_int(String str){
|
||||
int x, i;
|
||||
if (str.size == 0){
|
||||
x = 0;
|
||||
}
|
||||
else{
|
||||
x = hexchar_to_int(str.str[0]);
|
||||
for (i = 1; i < str.size; ++i){
|
||||
x *= 0x10;
|
||||
x += hexchar_to_int(str.str[i]);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
FCPP_LINK void
|
||||
copy_fast_unsafe(char *dest, char *src){
|
||||
int i = 0;
|
||||
while (src[i] != 0){
|
||||
dest[i] = src[i];
|
||||
++i;
|
||||
}
|
||||
dest[i] = 0;
|
||||
}
|
||||
|
||||
FCPP_LINK void
|
||||
copy_fast_unsafe(char *dest, String src){
|
||||
int i = 0;
|
||||
while (i != src.size){
|
||||
dest[i] = src.str[i];
|
||||
++i;
|
||||
}
|
||||
dest[i] = 0;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
copy_checked(String *dest, String src){
|
||||
char *dest_str;
|
||||
int i;
|
||||
if (dest->memory_size < src.size){
|
||||
return 0;
|
||||
}
|
||||
dest_str = dest->str;
|
||||
for (i = 0; i < src.size; ++i){
|
||||
dest_str[i] = src.str[i];
|
||||
}
|
||||
dest->size = src.size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
copy_partial(String *dest, char *src){
|
||||
int i = 0;
|
||||
int memory_size = dest->memory_size;
|
||||
char *dest_str = dest->str;
|
||||
while (src[i] != 0){
|
||||
if (i >= memory_size){
|
||||
return 0;
|
||||
}
|
||||
dest_str[i] = src[i];
|
||||
++i;
|
||||
}
|
||||
dest->size = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
copy_partial(String *dest, String src){
|
||||
bool result;
|
||||
int memory_size = dest->memory_size;
|
||||
char *dest_str = dest->str;
|
||||
if (memory_size < src.size){
|
||||
result = 0;
|
||||
for (int i = 0; i < memory_size; ++i){
|
||||
dest_str[i] = src.str[i];
|
||||
}
|
||||
dest->size = memory_size;
|
||||
}
|
||||
else{
|
||||
result = 1;
|
||||
for (int i = 0; i < src.size; ++i){
|
||||
dest_str[i] = src.str[i];
|
||||
}
|
||||
dest->size = src.size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
append_checked(String *dest, String src){
|
||||
String end;
|
||||
end = tailstr(*dest);
|
||||
bool result = copy_checked(&end, src);
|
||||
// NOTE(allen): This depends on end.size still being 0 if
|
||||
// the check failed and no coppy occurred.
|
||||
dest->size += end.size;
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
append_partial(String *dest, char *src){
|
||||
String end = tailstr(*dest);
|
||||
bool result = copy_partial(&end, src);
|
||||
dest->size += end.size;
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
append_partial(String *dest, String src){
|
||||
String end = tailstr(*dest);
|
||||
bool result = copy_partial(&end, src);
|
||||
dest->size += end.size;
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
append(String *dest, char c){
|
||||
bool result = 0;
|
||||
if (dest->size < dest->memory_size){
|
||||
dest->str[dest->size++] = c;
|
||||
result = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
compare(char *a, char *b){
|
||||
int i = 0;
|
||||
while (a[i] == b[i] && a[i] != 0){
|
||||
++i;
|
||||
}
|
||||
return (a[i] > b[i]) - (a[i] < b[i]);
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
compare(String a, char *b){
|
||||
int i = 0;
|
||||
while (i < a.size && a.str[i] == b[i]){
|
||||
++i;
|
||||
}
|
||||
if (i < a.size){
|
||||
return (a.str[i] > b[i]) - (a.str[i] < b[i]);
|
||||
}
|
||||
else{
|
||||
if (b[i] == 0){
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
compare(String a, String b){
|
||||
int i = 0;
|
||||
while (i < a.size && i < b.size && a.str[i] == b.str[i]){
|
||||
++i;
|
||||
}
|
||||
if (i < a.size && i < b.size){
|
||||
return (a.str[i] > b.str[i]) - (a.str[i] < b.str[i]);
|
||||
}
|
||||
else{
|
||||
return (a.size > b.size) - (a.size < b.size);
|
||||
}
|
||||
}
|
||||
|
||||
FCPP_LINK int
|
||||
reverse_seek_slash(String str){
|
||||
int i = str.size - 1;
|
||||
while (i >= 0 && char_not_slash(str.str[i])){
|
||||
--i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
set_last_folder(String *dir, char *folder_name){
|
||||
bool result = 0;
|
||||
int size = reverse_seek_slash(*dir) + 1;
|
||||
dir->size = size;
|
||||
if (append(dir, folder_name)){
|
||||
if (append(dir, (char*)"\\")){
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
if (!result){
|
||||
dir->size = size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
set_last_folder(String *dir, String folder_name){
|
||||
bool result = 0;
|
||||
int size = reverse_seek_slash(*dir) + 1;
|
||||
dir->size = size;
|
||||
if (append(dir, folder_name)){
|
||||
if (append(dir, (char*)"\\")){
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
if (!result){
|
||||
dir->size = size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FCPP_LINK String
|
||||
file_extension(String str){
|
||||
int i;
|
||||
for (i = str.size - 1; i >= 0; --i){
|
||||
if (str.str[i] == '.') break;
|
||||
}
|
||||
++i;
|
||||
return make_string(str.str+i, str.size-i);
|
||||
}
|
||||
|
||||
FCPP_LINK String
|
||||
file_extension_slowly(char *str){
|
||||
i32 s, i;
|
||||
for (s = 0; str[s]; ++s);
|
||||
for (i = s - 1; i >= 0; --i){
|
||||
if (str[i] == '.') break;
|
||||
}
|
||||
++i;
|
||||
return make_string(str+i, s-i);
|
||||
}
|
||||
|
||||
// NOTE(allen): experimental section, things below here are
|
||||
// not promoted to public API level yet.
|
||||
|
||||
struct Absolutes{
|
||||
String a[8];
|
||||
int count;
|
||||
};
|
||||
|
||||
FCPP_LINK void
|
||||
get_absolutes(String name, Absolutes *absolutes, bool implicit_first, bool implicit_last){
|
||||
int count = 0;
|
||||
int max = ArrayCount(absolutes->a) - 1;
|
||||
if (implicit_last) --max;
|
||||
|
||||
String str;
|
||||
str.str = name.str;
|
||||
str.size = 0;
|
||||
str.memory_size = 0;
|
||||
bool prev_was_wild = 0;
|
||||
|
||||
if (implicit_first){
|
||||
absolutes->a[count++] = str;
|
||||
prev_was_wild = 1;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < name.size; ++i){
|
||||
if (name.str[i] == '*' && count < max){
|
||||
if (!prev_was_wild){
|
||||
str.memory_size = str.size;
|
||||
absolutes->a[count++] = str;
|
||||
str.size = 0;
|
||||
}
|
||||
str.str = name.str + i + 1;
|
||||
prev_was_wild = 1;
|
||||
}
|
||||
else{
|
||||
++str.size;
|
||||
prev_was_wild = 0;
|
||||
}
|
||||
}
|
||||
|
||||
str.memory_size = str.size;
|
||||
absolutes->a[count++] = str;
|
||||
|
||||
if (implicit_last){
|
||||
str.size = 0;
|
||||
str.memory_size = 0;
|
||||
absolutes->a[count++] = str;
|
||||
}
|
||||
|
||||
absolutes->count = count;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
wildcard_match(Absolutes *absolutes, char *x){
|
||||
bool r = 1;
|
||||
String *a = absolutes->a;
|
||||
if (absolutes->count == 1){
|
||||
r = match(x, *a);
|
||||
}
|
||||
else{
|
||||
if (!match_part(x, *a)){
|
||||
r = 0;
|
||||
}
|
||||
else{
|
||||
String *max = a + absolutes->count - 1;
|
||||
x += a->size;
|
||||
++a;
|
||||
while (a < max){
|
||||
if (*x == 0){
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
if (match_part(x, *a)){
|
||||
x += a->size;
|
||||
++a;
|
||||
}
|
||||
else{
|
||||
++x;
|
||||
}
|
||||
}
|
||||
if (r && a->size > 0){
|
||||
r = 0;
|
||||
while (*x != 0){
|
||||
if (match_part(x, *a) && *(x + a->size) == 0){
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
else{
|
||||
++x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
FCPP_LINK bool
|
||||
wildcard_match(Absolutes *absolutes, String x){
|
||||
terminate_with_null(&x);
|
||||
return wildcard_match(absolutes, x.str);
|
||||
}
|
||||
|
||||
#undef FCPP_STRING_IMPLEMENTATION
|
||||
#endif // #ifdef FCPP_STRING_IMPLEMENTATION
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* "4cpp" Open C++ Parser v0.1: Types
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
NOTES ON USE:
|
||||
This file is used to declare 4cpp fixed width integer and float types.
|
||||
It is not meant to be used directly.
|
||||
*/
|
||||
|
||||
// TODO(allen):
|
||||
// - create non stdint.h version in case someone wants to exclude that header
|
||||
|
||||
#include "4cpp_config.h"
|
||||
|
||||
#ifndef FCPP_TYPES
|
||||
#define FCPP_TYPES
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t fcpp_u8;
|
||||
typedef uint64_t fcpp_u64;
|
||||
typedef uint32_t fcpp_u32;
|
||||
typedef uint16_t fcpp_u16;
|
||||
|
||||
typedef int8_t fcpp_i8;
|
||||
typedef int64_t fcpp_i64;
|
||||
typedef int32_t fcpp_i32;
|
||||
typedef int16_t fcpp_i16;
|
||||
|
||||
typedef fcpp_i32 fcpp_bool32;
|
||||
typedef fcpp_i8 fcpp_bool8;
|
||||
|
||||
typedef float fcpp_real32;
|
||||
typedef double fcpp_real64;
|
||||
|
||||
#define FCPP_GLOBAL static
|
||||
|
||||
#define FCPP_COUNT(a) (sizeof(a)/sizeof(*(a)))
|
||||
|
||||
#endif
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 12.12.2014
|
||||
*
|
||||
* Win32 Layer for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FRED_H
|
||||
#define FRED_H
|
||||
|
||||
struct Partition{
|
||||
u8 *base;
|
||||
i32 pos, max;
|
||||
};
|
||||
|
||||
internal Partition
|
||||
partition_open(void *memory, i32 size){
|
||||
Partition partition;
|
||||
partition.base = (u8*)memory;;
|
||||
partition.pos = 0;
|
||||
partition.max = size;
|
||||
return partition;
|
||||
}
|
||||
|
||||
internal void*
|
||||
partition_allocate(Partition *data, i32 size){
|
||||
void *ret = 0;
|
||||
if (size > 0 && data->pos + size < data->max){
|
||||
ret = data->base + data->pos;
|
||||
data->pos += size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void*
|
||||
partition_current(Partition *data){
|
||||
return data->base + data->pos;
|
||||
}
|
||||
|
||||
inline i32
|
||||
partition_remaining(Partition *data){
|
||||
return data->max - data->pos;
|
||||
}
|
||||
|
||||
#define push_struct(part, T) (T*)partition_allocate(part, sizeof(T))
|
||||
#define push_array(part, T, size) (T*)partition_allocate(part, sizeof(T)*(size))
|
||||
#define push_block(part, size) partition_allocate(part, size)
|
||||
|
||||
enum Memory_Bubble_Flag{
|
||||
MEM_BUBBLE_USED = 0x1,
|
||||
MEM_BUBBLE_DEBUG = 0xD3000000,
|
||||
MEM_BUBBLE_SYS_DEBUG = 0x5D000000,
|
||||
MEM_BUBBLE_DEBUG_MASK = 0xFF000000
|
||||
};
|
||||
struct Bubble{
|
||||
Bubble *prev;
|
||||
Bubble *next;
|
||||
u32 flags;
|
||||
i32 size;
|
||||
u32 type;
|
||||
u32 _unused_;
|
||||
};
|
||||
struct General_Memory{
|
||||
Bubble sentinel;
|
||||
};
|
||||
|
||||
inline void
|
||||
insert_bubble(Bubble *prev, Bubble *bubble){
|
||||
bubble->prev = prev;
|
||||
bubble->next = prev->next;
|
||||
bubble->prev->next = bubble;
|
||||
bubble->next->prev = bubble;
|
||||
}
|
||||
|
||||
inline void
|
||||
remove_bubble(Bubble *bubble){
|
||||
bubble->prev->next = bubble->next;
|
||||
bubble->next->prev = bubble->prev;
|
||||
}
|
||||
|
||||
#if FRED_INTERNAL
|
||||
#define MEM_BUBBLE_FLAG_INIT MEM_BUBBLE_DEBUG
|
||||
#else
|
||||
#define MEM_BUBBLE_FLAG_INIT 0
|
||||
#endif
|
||||
|
||||
internal void
|
||||
general_memory_open(General_Memory *general, void *memory, i32 size){
|
||||
general->sentinel.prev = &general->sentinel;
|
||||
general->sentinel.next = &general->sentinel;
|
||||
general->sentinel.flags = MEM_BUBBLE_USED;
|
||||
general->sentinel.size = 0;
|
||||
|
||||
Bubble *first = (Bubble*)memory;
|
||||
first->flags = (u32)MEM_BUBBLE_FLAG_INIT;
|
||||
first->size = size - sizeof(Bubble);
|
||||
insert_bubble(&general->sentinel, first);
|
||||
}
|
||||
|
||||
#define BUBBLE_MIN_SIZE 1024
|
||||
|
||||
internal void
|
||||
general_memory_attempt_split(Bubble *bubble, i32 wanted_size){
|
||||
i32 remaining_size = bubble->size - wanted_size;
|
||||
if (remaining_size >= BUBBLE_MIN_SIZE){
|
||||
bubble->size = wanted_size;
|
||||
Bubble *new_bubble = (Bubble*)((u8*)(bubble + 1) + wanted_size);
|
||||
new_bubble->flags = (u32)MEM_BUBBLE_FLAG_INIT;
|
||||
new_bubble->size = remaining_size - sizeof(Bubble);
|
||||
insert_bubble(bubble, new_bubble);
|
||||
}
|
||||
}
|
||||
|
||||
internal void*
|
||||
general_memory_allocate(General_Memory *general, i32 size, u32 type = 0){
|
||||
void *result = 0;
|
||||
if (size < Kbytes(1)){
|
||||
int x = 1; AllowLocal(x);
|
||||
}
|
||||
for (Bubble *bubble = general->sentinel.next;
|
||||
bubble != &general->sentinel;
|
||||
bubble = bubble->next){
|
||||
if (!(bubble->flags & MEM_BUBBLE_USED)){
|
||||
if (bubble->size >= size){
|
||||
result = bubble + 1;
|
||||
bubble->flags |= MEM_BUBBLE_USED;
|
||||
bubble->type = type;
|
||||
general_memory_attempt_split(bubble, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void
|
||||
general_memory_do_merge(Bubble *left, Bubble *right){
|
||||
left->size += sizeof(Bubble) + right->size;
|
||||
remove_bubble(right);
|
||||
}
|
||||
|
||||
inline void
|
||||
general_memory_attempt_merge(Bubble *left, Bubble *right){
|
||||
if (!(left->flags & MEM_BUBBLE_USED) &&
|
||||
!(right->flags & MEM_BUBBLE_USED)){
|
||||
general_memory_do_merge(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
general_memory_free(General_Memory *general, void *memory){
|
||||
Bubble *bubble = ((Bubble*)memory) - 1;
|
||||
Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG);
|
||||
bubble->flags &= ~MEM_BUBBLE_USED;
|
||||
bubble->type = 0;
|
||||
Bubble *prev, *next;
|
||||
prev = bubble->prev;
|
||||
next = bubble->next;
|
||||
general_memory_attempt_merge(bubble, next);
|
||||
general_memory_attempt_merge(prev, bubble);
|
||||
}
|
||||
|
||||
internal void*
|
||||
general_memory_reallocate(General_Memory *general, void *old, i32 old_size, i32 size, u32 type = 0){
|
||||
void *result = old;
|
||||
Bubble *bubble = ((Bubble*)old) - 1;
|
||||
bubble->type = type;
|
||||
Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG);
|
||||
i32 additional_space = size - bubble->size;
|
||||
if (additional_space > 0){
|
||||
Bubble *next = bubble->next;
|
||||
if (!(next->flags & MEM_BUBBLE_USED) &&
|
||||
next->size + sizeof(Bubble) >= additional_space){
|
||||
general_memory_do_merge(bubble, next);
|
||||
general_memory_attempt_split(bubble, size);
|
||||
}
|
||||
else{
|
||||
result = general_memory_allocate(general, size, type);
|
||||
if (old_size) memcpy(result, old, old_size);
|
||||
general_memory_free(general, old);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void*
|
||||
general_memory_reallocate_nocopy(General_Memory *general, void *old, i32 size, u32 type = 0){
|
||||
return general_memory_reallocate(general, old, 0, size, type);
|
||||
}
|
||||
|
||||
struct Temp_Memory{
|
||||
Partition *part;
|
||||
i32 pos;
|
||||
};
|
||||
|
||||
internal Temp_Memory
|
||||
begin_temp_memory(Partition *data){
|
||||
Temp_Memory result;
|
||||
result.part = data;
|
||||
result.pos = data->pos;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
end_temp_memory(Temp_Memory temp){
|
||||
temp.part->pos = temp.pos;
|
||||
}
|
||||
|
||||
struct Mem_Options{
|
||||
Partition part;
|
||||
General_Memory general;
|
||||
};
|
||||
|
||||
#if SOFTWARE_RENDER
|
||||
struct Render_Target{
|
||||
void *pixel_data;
|
||||
i32 width, height, pitch;
|
||||
};
|
||||
#else
|
||||
struct Render_Target{
|
||||
void *handle;
|
||||
void *context;
|
||||
i32_Rect clip_boxes[5];
|
||||
i32 clip_top;
|
||||
i32 width, height;
|
||||
i32 bound_texture;
|
||||
u32 color;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct Application_Memory{
|
||||
void *vars_memory;
|
||||
i32 vars_memory_size;
|
||||
|
||||
void *target_memory;
|
||||
i32 target_memory_size;
|
||||
};
|
||||
|
||||
#define KEY_INPUT_BUFFER_SIZE 4
|
||||
#define KEY_INPUT_BUFFER_DSIZE (KEY_INPUT_BUFFER_SIZE << 1)
|
||||
|
||||
enum Key_Control{
|
||||
CONTROL_KEY_SHIFT,
|
||||
CONTROL_KEY_CONTROL,
|
||||
CONTROL_KEY_ALT,
|
||||
// always last
|
||||
CONTROL_KEY_COUNT
|
||||
};
|
||||
|
||||
struct Key_Event_Data{
|
||||
u16 keycode;
|
||||
u16 loose_keycode;
|
||||
u16 character;
|
||||
u16 character_no_caps_lock;
|
||||
};
|
||||
|
||||
struct Key_Input_Data{
|
||||
// NOTE(allen): keycodes here
|
||||
Key_Event_Data press[KEY_INPUT_BUFFER_SIZE];
|
||||
Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE];
|
||||
i32 press_count;
|
||||
i32 hold_count;
|
||||
|
||||
// NOTE(allen):
|
||||
// true when the key is held down
|
||||
// false when the key is not held down
|
||||
bool8 control_keys[CONTROL_KEY_COUNT];
|
||||
bool8 caps_lock;
|
||||
};
|
||||
|
||||
struct Key_Summary{
|
||||
i32 count;
|
||||
Key_Event_Data keys[KEY_INPUT_BUFFER_DSIZE];
|
||||
bool8 modifiers[CONTROL_KEY_COUNT];
|
||||
};
|
||||
|
||||
struct Key_Single{
|
||||
Key_Event_Data key;
|
||||
bool8 *modifiers;
|
||||
};
|
||||
|
||||
inline Key_Single
|
||||
get_single_key(Key_Summary *summary, i32 index){
|
||||
Assert(index >= 0 && index < summary->count);
|
||||
Key_Single key;
|
||||
key.key = summary->keys[index];
|
||||
key.modifiers = summary->modifiers;
|
||||
return key;
|
||||
}
|
||||
|
||||
struct Mouse_State{
|
||||
bool32 out_of_window;
|
||||
bool32 left_button, right_button;
|
||||
bool32 left_button_prev, right_button_prev;
|
||||
i32 x, y;
|
||||
i16 wheel;
|
||||
};
|
||||
|
||||
struct Mouse_Summary{
|
||||
i32 mx, my;
|
||||
bool32 l, r;
|
||||
bool32 press_l, press_r;
|
||||
bool32 release_l, release_r;
|
||||
bool32 out_of_window;
|
||||
bool32 wheel_used;
|
||||
i16 wheel_amount;
|
||||
};
|
||||
|
||||
struct Input_Summary{
|
||||
Mouse_Summary mouse;
|
||||
Key_Summary keys;
|
||||
Key_Codes *codes;
|
||||
};
|
||||
|
||||
// TODO(allen): This can go, and we can just use a String for it.
|
||||
struct Clipboard_Contents{
|
||||
u8 *str;
|
||||
i32 size;
|
||||
};
|
||||
|
||||
struct Thread_Context;
|
||||
|
||||
internal bool32
|
||||
app_init(Thread_Context *thread,
|
||||
Application_Memory *memory,
|
||||
Key_Codes *lose_codes,
|
||||
Clipboard_Contents clipboard);
|
||||
|
||||
enum Application_Mouse_Cursor{
|
||||
APP_MOUSE_CURSOR_DEFAULT,
|
||||
APP_MOUSE_CURSOR_ARROW,
|
||||
APP_MOUSE_CURSOR_IBEAM,
|
||||
APP_MOUSE_CURSOR_LEFTRIGHT,
|
||||
APP_MOUSE_CURSOR_UPDOWN,
|
||||
// never below this
|
||||
APP_MOUSE_CURSOR_COUNT
|
||||
};
|
||||
|
||||
struct Application_Step_Result{
|
||||
Application_Mouse_Cursor mouse_cursor_type;
|
||||
bool32 redraw;
|
||||
};
|
||||
|
||||
internal Application_Step_Result
|
||||
app_step(Thread_Context *thread,
|
||||
Key_Codes *codes,
|
||||
Key_Input_Data *input, Mouse_State *state,
|
||||
bool32 time_step, Render_Target *target,
|
||||
Application_Memory *memory,
|
||||
Clipboard_Contents clipboard,
|
||||
bool32 first_step, bool32 force_redraw);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 19.08.2015
|
||||
*
|
||||
* Command management functions for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
typedef void (*Command_Function)(struct Command_Data *command, struct Command_Binding binding);
|
||||
|
||||
struct Command_Binding{
|
||||
Command_Function function;
|
||||
Custom_Command_Function *custom;
|
||||
i64 hash;
|
||||
};
|
||||
|
||||
struct Command_Map{
|
||||
Command_Binding vanilla_keyboard_default;
|
||||
Command_Binding commands[101];
|
||||
i32 count, max;
|
||||
};
|
||||
|
||||
internal void command_null(Command_Data *command);
|
||||
|
||||
internal i64
|
||||
map_hash(u16 event_code, u8 modifiers){
|
||||
i64 result = (event_code << 4) | modifiers;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool32
|
||||
map_add(Command_Map *map, u16 event_code, u8 modifiers, Command_Function function, Custom_Command_Function *custom = 0){
|
||||
Assert(map->count * 8 < map->max * 7);
|
||||
Command_Binding bind;
|
||||
bind.function = function;
|
||||
bind.custom = custom;
|
||||
bind.hash = map_hash(event_code, modifiers);
|
||||
|
||||
i32 max = map->max;
|
||||
i32 index = bind.hash % max;
|
||||
Command_Binding entry;
|
||||
while ((entry = map->commands[index]).function && entry.hash != -1){
|
||||
if (entry.hash == bind.hash){
|
||||
return 1;
|
||||
}
|
||||
index = (index + 1) % max;
|
||||
}
|
||||
map->commands[index] = bind;
|
||||
++map->count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal bool32
|
||||
map_find_entry(Command_Map *map, u16 event_code, u8 modifiers, i32 *index_out){
|
||||
i64 hash = map_hash(event_code, modifiers);
|
||||
i32 max = map->max;
|
||||
i32 index = hash % map->max;
|
||||
Command_Binding entry;
|
||||
while ((entry = map->commands[index]).function){
|
||||
if (entry.hash == hash){
|
||||
*index_out = index;
|
||||
return 1;
|
||||
}
|
||||
index = (index + 1) % max;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal bool32
|
||||
map_find(Command_Map *map, u16 event_code, u8 modifiers, Command_Binding *bind_out){
|
||||
bool32 result;
|
||||
i32 index;
|
||||
result = map_find_entry(map, event_code, modifiers, &index);
|
||||
if (result){
|
||||
*bind_out = map->commands[index];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool32
|
||||
map_drop(Command_Map *map, u16 event_code, u8 modifiers){
|
||||
bool32 result;
|
||||
i32 index;
|
||||
result = map_find_entry(map, event_code, modifiers, &index);
|
||||
if (result){
|
||||
map->commands[index].function = 0;
|
||||
map->commands[index].hash = -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
map_init(Command_Map *commands){
|
||||
commands->vanilla_keyboard_default = {};
|
||||
memset(commands->commands, 0, sizeof(commands->commands));
|
||||
commands->max = ArrayCount(commands->commands);
|
||||
commands->count = 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
map_get_vanilla_keyboard_default(Command_Map *map, u8 command, Command_Binding *bind_out){
|
||||
if (command == MDFR_NONE){
|
||||
*bind_out = map->vanilla_keyboard_default;
|
||||
}
|
||||
}
|
||||
|
||||
internal Command_Binding
|
||||
map_extract(Command_Map *map, Key_Single key){
|
||||
Command_Binding bind = {};
|
||||
|
||||
u8 command = MDFR_NONE;
|
||||
bool32 ctrl = key.modifiers[CONTROL_KEY_CONTROL];
|
||||
bool32 alt = key.modifiers[CONTROL_KEY_ALT];
|
||||
bool32 shift = key.modifiers[CONTROL_KEY_SHIFT] && key.key.loose_keycode;
|
||||
|
||||
if (shift) command |= MDFR_SHIFT;
|
||||
if (ctrl) command |= MDFR_CTRL;
|
||||
if (alt) command |= MDFR_ALT;
|
||||
|
||||
u16 code = key.key.character_no_caps_lock;
|
||||
if (code != 0) map_get_vanilla_keyboard_default(map, command, &bind);
|
||||
|
||||
if (bind.function == 0){
|
||||
if (code == 0) code = key.key.keycode;
|
||||
map_find(map, code, command, &bind);
|
||||
}
|
||||
|
||||
return bind;
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,527 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 13.09.2015
|
||||
*
|
||||
* Internal debug view for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
#if FRED_INTERNAL
|
||||
|
||||
enum Debug_Mode{
|
||||
DBG_MEMORY,
|
||||
DBG_OS_EVENTS,
|
||||
DBG_PROFILE
|
||||
};
|
||||
|
||||
struct Dbg_Past_Key{
|
||||
Key_Event_Data key;
|
||||
i32 frame_index;
|
||||
bool8 modifiers[3];
|
||||
};
|
||||
|
||||
struct Debug_View{
|
||||
View view_base;
|
||||
Font *font;
|
||||
Debug_Mode mode;
|
||||
Dbg_Past_Key past_keys[32];
|
||||
i32 past_key_count, past_key_pos;
|
||||
i16 prev_mouse_wheel;
|
||||
};
|
||||
|
||||
inline Debug_View*
|
||||
view_to_debug_view(View *view){
|
||||
Assert(!view || view->type == VIEW_TYPE_DEBUG);
|
||||
return (Debug_View*)view;
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_general_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 y){
|
||||
Font *font = view->font;
|
||||
i32 y_advance = font->height;
|
||||
Bubble *sentinel = &view->view_base.general->sentinel;
|
||||
|
||||
for (Bubble *bubble = sentinel->next;
|
||||
bubble != sentinel;
|
||||
bubble = bubble->next){
|
||||
bool32 used = (bubble->flags & MEM_BUBBLE_USED) != 0;
|
||||
u32 color;
|
||||
if (used) color = 0xFFFFFFFF;
|
||||
else color = 0xFF00FFFF;
|
||||
|
||||
char str[256];
|
||||
String s = make_fixed_width_string(str);
|
||||
if (used){
|
||||
switch (bubble->type){
|
||||
case BUBBLE_BUFFER: append(&s, "buffer"); break;
|
||||
case BUBBLE_STARTS: append(&s, "starts"); break;
|
||||
case BUBBLE_WIDTHS: append(&s, "widths"); break;
|
||||
case BUBBLE_WRAPS: append(&s, "wraps"); break;
|
||||
case BUBBLE_TOKENS: append(&s, "tokens"); break;
|
||||
default: append(&s, "unknown"); break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
append(&s, "unused");
|
||||
}
|
||||
append(&s, " ");
|
||||
append_int_to_str(bubble->size, &s);
|
||||
terminate_with_null(&s);
|
||||
|
||||
draw_string(target, font, str, rect.x0, y, color);
|
||||
y += y_advance;
|
||||
|
||||
Bubble *next = bubble->next;
|
||||
if (next != sentinel){
|
||||
u8 *end_ptr = (u8*)(bubble + 1) + bubble->size;
|
||||
u8 *next_ptr = (u8*)(next);
|
||||
if (end_ptr != next_ptr){
|
||||
color = 0xFFFF0000;
|
||||
s = make_fixed_width_string(str);
|
||||
append(&s, "discontinuity");
|
||||
terminate_with_null(&s);
|
||||
|
||||
draw_string(target, font, str, rect.x0, y, color);
|
||||
y += y_advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_system_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 y){
|
||||
Font *font = view->font;
|
||||
i32 y_advance = font->height;
|
||||
Bubble *sentinel = INTERNAL_system_sentinel();
|
||||
|
||||
for (Bubble *bubble = sentinel->next;
|
||||
bubble != sentinel;
|
||||
bubble = bubble->next){
|
||||
Sys_Bubble *sysb = (Sys_Bubble*)bubble;
|
||||
u32 color = 0xFFFFFFFF;
|
||||
|
||||
char str[256];
|
||||
String s = make_fixed_width_string(str);
|
||||
|
||||
append(&s, sysb->file_name);
|
||||
append(&s, " ");
|
||||
append_int_to_str(sysb->line_number, &s);
|
||||
append(&s, " ");
|
||||
append_int_to_str(bubble->size, &s);
|
||||
terminate_with_null(&s);
|
||||
|
||||
draw_string(target, font, str, rect.x0, y, color);
|
||||
|
||||
y += y_advance;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_background_threads(Debug_View *view, i32_Rect rect, Render_Target *target){
|
||||
i32 pending;
|
||||
bool8 running[4];
|
||||
INTERNAL_get_thread_states(BACKGROUND_THREADS, running, &pending);
|
||||
|
||||
i32 box_size = 30;
|
||||
|
||||
i32_Rect trect;
|
||||
trect.x0 = rect.x1 - box_size;
|
||||
trect.y0 = rect.y0;
|
||||
trect.x1 = rect.x1;
|
||||
trect.y1 = rect.y0 + box_size;
|
||||
|
||||
u32 light = 0xFF606060;
|
||||
for (i32 i = 0; i < 4; ++i){
|
||||
u32 color;
|
||||
if (running[i]) color = 0xFF9090FF;
|
||||
else color = 0xFF101010;
|
||||
draw_rectangle(target, trect, color);
|
||||
draw_rectangle_outline(target, trect, light);
|
||||
trect.x0 -= box_size;
|
||||
trect.x1 -= box_size;
|
||||
}
|
||||
|
||||
char str[256];
|
||||
String s = make_fixed_width_string(str);
|
||||
append_int_to_str(pending, &s);
|
||||
terminate_with_null(&s);
|
||||
draw_string(target, view->font, str, trect.x1, trect.y1, light);
|
||||
}
|
||||
|
||||
struct Dbg_Modifier{
|
||||
char *name;
|
||||
u8 modifier;
|
||||
};
|
||||
internal void
|
||||
draw_modifiers(Debug_View *view, Render_Target *target,
|
||||
bool8 *modifiers, u32 on_color, u32 off_color, i32 *x, i32 y){
|
||||
persist Dbg_Modifier dm[] = {
|
||||
{"CTRL", CONTROL_KEY_CONTROL},
|
||||
{"ALT", CONTROL_KEY_ALT},
|
||||
{"SHIFT", CONTROL_KEY_SHIFT}
|
||||
};
|
||||
for (i32 i = 0; i < CONTROL_KEY_COUNT; ++i){
|
||||
Dbg_Modifier m = dm[i];
|
||||
u32 color;
|
||||
|
||||
if (modifiers[m.modifier]) color = on_color;
|
||||
else color = off_color;
|
||||
|
||||
*x = draw_string(target, view->font, m.name, *x, y, color);
|
||||
*x += 5;
|
||||
}
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_key_event(Debug_View *view, Render_Target *target,
|
||||
Dbg_Past_Key *key, i32 x, i32 y, u32 on_color, u32 off_color){
|
||||
Font *font = view->font;
|
||||
draw_modifiers(view, target, key->modifiers,
|
||||
on_color, off_color, &x, y);
|
||||
|
||||
if (font->glyphs[key->key.character].exists){
|
||||
char c[2];
|
||||
c[0] = (char)key->key.character;
|
||||
c[1] = 0;
|
||||
x = draw_string(target, font, c, x, y, on_color);
|
||||
}
|
||||
else{
|
||||
char c[10] = {};
|
||||
String str = make_fixed_width_string(c);
|
||||
append(&str, "\\");
|
||||
append_int_to_str(key->key.keycode, &str);
|
||||
terminate_with_null(&str);
|
||||
x = draw_string(target, font, c, x, y, on_color);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_os_events(Debug_View *view, i32_Rect rect, Render_Target *target,
|
||||
Input_Summary *active_input){
|
||||
persist i32 max_past = ArrayCount(view->past_keys);
|
||||
|
||||
i32 x, y, max_x, max_y;
|
||||
x = rect.x0;
|
||||
y = rect.y0;
|
||||
|
||||
Font *font = view->font;
|
||||
|
||||
draw_modifiers(view, target, active_input->keys.modifiers,
|
||||
0xFFFFFFFF, 0xFF444444, &x, y);
|
||||
max_x = x;
|
||||
x = rect.x0;
|
||||
y += font->height;
|
||||
|
||||
for (i32 j = 0; j < view->past_key_count; ++j){
|
||||
Dbg_Past_Key *key = view->past_keys + j;
|
||||
u32 on_color, off_color;
|
||||
|
||||
switch ((view->past_key_pos - j - 1 + max_past*2) % max_past){
|
||||
case 0: on_color = 0xFFAAAAFF; off_color = 0xFF505088; break;
|
||||
case 1: on_color = 0xFF9999CC; off_color = 0xFF404077; break;
|
||||
case 2: on_color = 0xFF8888AA; off_color = 0xFF303066; break;
|
||||
default: on_color = 0xFF888888; off_color = 0xFF303030; break;
|
||||
}
|
||||
|
||||
x = draw_key_event(view, target, key, x, y, on_color, off_color);
|
||||
|
||||
if (max_x < x) max_x = x;
|
||||
x = rect.x0;
|
||||
y += font->height;
|
||||
}
|
||||
|
||||
i32_Rect mrect = rect;
|
||||
mrect.x0 = max_x + 1;
|
||||
|
||||
max_y = y;
|
||||
x = mrect.x0;
|
||||
y = mrect.y0;
|
||||
|
||||
{
|
||||
u32 color;
|
||||
if (active_input->mouse.out_of_window){
|
||||
color = 0xFFFF0000;
|
||||
draw_string(target, font, "OUT", x, y, color);
|
||||
}
|
||||
else{
|
||||
color = 0xFF008800;
|
||||
draw_string(target, font, "IN", x, y, color);
|
||||
}
|
||||
y += font->height;
|
||||
|
||||
char c[16];
|
||||
String s = make_fixed_width_string(c);
|
||||
append_int_to_str(active_input->mouse.mx, &s);
|
||||
append(&s, ", ");
|
||||
append_int_to_str(active_input->mouse.my, &s);
|
||||
terminate_with_null(&s);
|
||||
draw_string(target, font, c, x, y, color);
|
||||
y += font->height;
|
||||
|
||||
u32 btn_color;
|
||||
if (active_input->mouse.l) btn_color = color;
|
||||
else btn_color = 0xFF444444;
|
||||
x = draw_string(target, font, "L ", x, y, btn_color);
|
||||
|
||||
if (active_input->mouse.r) btn_color = color;
|
||||
else btn_color = 0xFF444444;
|
||||
x = draw_string(target, font, "R", x, y, btn_color);
|
||||
|
||||
x = mrect.x0;
|
||||
y += font->height;
|
||||
|
||||
s = make_fixed_width_string(c);
|
||||
append_int_to_str(view->prev_mouse_wheel, &s);
|
||||
terminate_with_null(&s);
|
||||
|
||||
if (active_input->mouse.wheel_used) btn_color = color;
|
||||
else btn_color = 0xFF444444;
|
||||
draw_string(target, font, c, x, y, btn_color);
|
||||
|
||||
y += font->height;
|
||||
}
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_profile_frame(Render_Target *target, Profile_Frame *frame,
|
||||
i32 x, i32 top, i32 bottom, i32 goal, Input_Summary *active_input){
|
||||
i32 result = -1;
|
||||
|
||||
persist u32 colors[] = {
|
||||
0x80C06000,
|
||||
0x8000C060,
|
||||
0x806000C0,
|
||||
0x8060C000,
|
||||
0x800060C0,
|
||||
0x80C00060,
|
||||
};
|
||||
|
||||
persist i32 color_max = ArrayCount(colors);
|
||||
Mouse_Summary *mouse = &active_input->mouse;
|
||||
|
||||
i32 count = frame->events.count;
|
||||
Debug_Event *events = frame->events.e;
|
||||
|
||||
i32 i;
|
||||
for (i = 0; i < count && events[i].type == DBGEV_START; ++i){
|
||||
i64 start = events[i++].time;
|
||||
i64 end = events[i].time;
|
||||
|
||||
real32 rtop = unlerp(0, (real32)end, FRAME_TIME);
|
||||
real32 rbot = unlerp(0, (real32)start, FRAME_TIME);
|
||||
|
||||
rtop = lerp((real32)bottom, rtop, (real32)goal);
|
||||
rbot = lerp((real32)bottom, rbot, (real32)goal);
|
||||
|
||||
i32_Rect r = i32R(x, (i32)rtop, x+5, (i32)rbot);
|
||||
draw_rectangle(target, r, colors[events[i].event_index % color_max]);
|
||||
if (hit_check(mouse->mx, mouse->my, r)) result = (i - 1);
|
||||
}
|
||||
|
||||
{
|
||||
real32 rtop = unlerp(0, (real32)frame->dbg_procing_end, FRAME_TIME);
|
||||
real32 rbot = unlerp(0, (real32)frame->dbg_procing_start, FRAME_TIME);
|
||||
|
||||
rtop = lerp((real32)bottom, rtop, (real32)goal);
|
||||
rbot = lerp((real32)bottom, rbot, (real32)goal);
|
||||
|
||||
i32_Rect r = i32R(x, (i32)rtop, x+5, (i32)rbot);
|
||||
draw_rectangle(target, r, 0xFF808080);
|
||||
}
|
||||
|
||||
for (; i < count; ++i){
|
||||
|
||||
Assert(events[i].type == DBGEV_MOMENT);
|
||||
|
||||
real32 ry = unlerp(0, (real32)events[i].time, FRAME_TIME);
|
||||
ry = lerp((real32)bottom, ry, (real32)goal);
|
||||
|
||||
i32_Rect r = i32R(x-1, (i32)ry, x+6, (i32)ry+1);
|
||||
draw_rectangle(target, r, 0xFFFFFFFF);
|
||||
if (hit_check(mouse->mx, mouse->my, r)) result = i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_profile(Debug_View *view, i32_Rect rect, Render_Target *target, Input_Summary *active_input){
|
||||
i32 j = (INTERNAL_frame_index % 30);
|
||||
|
||||
i32 event_index = -1;
|
||||
i32 frame_index = -1;
|
||||
|
||||
i32 target_time = (rect.y0 + rect.y1)/2;
|
||||
|
||||
i32 x = rect.x0;
|
||||
for (i32 i = 0; i < PAST_PROFILE_COUNT; ++i){
|
||||
Profile_Frame *frame = past_frames + j;
|
||||
i32 s = draw_profile_frame(target, frame, x, rect.y0, rect.y1, target_time, active_input);
|
||||
if (s != -1){
|
||||
event_index = s;
|
||||
frame_index = j;
|
||||
}
|
||||
x += 10;
|
||||
j = ((j+1) % PAST_PROFILE_COUNT);
|
||||
}
|
||||
|
||||
draw_rectangle(target, i32R(rect.x0, target_time, rect.x1, target_time + 1), 0xFFFFFFFF);
|
||||
|
||||
char c[200];
|
||||
|
||||
if (frame_index != -1){
|
||||
Profile_Frame *frame = past_frames + frame_index;
|
||||
Debug_Event *events = frame->events.e;
|
||||
Debug_Event *event = events + event_index;
|
||||
|
||||
Font *font = view->font;
|
||||
|
||||
u32 color = 0xFFFFFFFF;
|
||||
|
||||
i32 x, y;
|
||||
x = rect.x0;
|
||||
y = rect.y0;
|
||||
|
||||
String s = make_fixed_width_string(c);
|
||||
append(&s, event->name);
|
||||
append(&s, ": ");
|
||||
|
||||
Assert(event->type == DBGEV_START || event->type == DBGEV_MOMENT);
|
||||
if (event->type == DBGEV_START){
|
||||
Debug_Event *next_event = event + 1;
|
||||
Assert(next_event->type == DBGEV_END);
|
||||
append_int_to_str((i32)(next_event->time - event->time), &s);
|
||||
}
|
||||
else{
|
||||
append_int_to_str((i32)event->time, &s);
|
||||
}
|
||||
terminate_with_null(&s);
|
||||
draw_string(target, font, c, x, y, color);
|
||||
y += font->height;
|
||||
|
||||
if (frame->first_key != -1){
|
||||
Dbg_Past_Key *key = view->past_keys + frame->first_key;
|
||||
Dbg_Past_Key *end_key = view->past_keys + ArrayCount(view->past_keys);
|
||||
while (key->frame_index == frame->index){
|
||||
draw_key_event(view, target, key,
|
||||
x, y, 0xFFFFFFFF, 0xFF808080);
|
||||
y += font->height;
|
||||
++key;
|
||||
if (key == end_key) key = view->past_keys;
|
||||
}
|
||||
}
|
||||
|
||||
i32 count = frame->events.count;
|
||||
for (i32 i = 0; i < count; ++i){
|
||||
if (events[i].type == DBGEV_START) ++i;
|
||||
else{
|
||||
s = make_fixed_width_string(c);
|
||||
append(&s, events[i].name);
|
||||
append(&s, ": ");
|
||||
append_int_to_str((i32)events[i].time, &s);
|
||||
terminate_with_null(&s);
|
||||
draw_string(target, font, c, x, y, color);
|
||||
y += font->height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target,
|
||||
Input_Summary *active_input){
|
||||
i32 result = 0;
|
||||
|
||||
draw_rectangle(target, rect, 0xFF000000);
|
||||
|
||||
switch (view->mode){
|
||||
case DBG_MEMORY:
|
||||
{
|
||||
i32 y = rect.y0;
|
||||
y = draw_general_memory(view, rect, target, y);
|
||||
draw_rectangle(target, i32R(rect.x0, y, rect.x1, y+2), 0xFF222222);
|
||||
y += 2;
|
||||
y = draw_system_memory(view, rect, target, y);
|
||||
}break;
|
||||
case DBG_OS_EVENTS:
|
||||
{
|
||||
draw_os_events(view, rect, target, active_input);
|
||||
}break;
|
||||
case DBG_PROFILE:
|
||||
{
|
||||
draw_background_threads(view, rect, target);
|
||||
draw_profile(view, rect, target, active_input);
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
step_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target,
|
||||
Input_Summary *active_input){
|
||||
persist i32 max_past = ArrayCount(view->past_keys);
|
||||
|
||||
bool8 *modifiers = active_input->keys.modifiers;
|
||||
for (i32 i = 0; i < active_input->keys.count; ++i){
|
||||
i32 this_index = view->past_key_pos;
|
||||
Dbg_Past_Key *past_key = view->past_keys + view->past_key_pos;
|
||||
++view->past_key_pos;
|
||||
view->past_key_pos = view->past_key_pos % max_past;
|
||||
|
||||
past_key->key = active_input->keys.keys[i];
|
||||
past_key->modifiers[0] = modifiers[0];
|
||||
past_key->modifiers[1] = modifiers[1];
|
||||
past_key->modifiers[2] = modifiers[2];
|
||||
|
||||
if (INTERNAL_updating_profile){
|
||||
past_key->frame_index = INTERNAL_frame_index;
|
||||
if (profile_frame.first_key == -1){
|
||||
profile_frame.first_key = this_index;
|
||||
}
|
||||
}
|
||||
else{
|
||||
past_key->frame_index = -1;
|
||||
}
|
||||
|
||||
if (view->past_key_count < max_past) ++view->past_key_count;
|
||||
}
|
||||
|
||||
if (active_input->mouse.wheel_used)
|
||||
view->prev_mouse_wheel = active_input->mouse.wheel_amount;
|
||||
}
|
||||
|
||||
internal
|
||||
DO_VIEW_SIG(do_debug_view){
|
||||
view->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW;
|
||||
Debug_View *debug_view = (Debug_View*)view;
|
||||
i32 result = 0;
|
||||
|
||||
switch (message){
|
||||
case VMSG_RESIZE: break;
|
||||
case VMSG_STYLE_CHANGE: break;
|
||||
case VMSG_STEP: step_debug_view(debug_view, rect, target, active_input); result = 1; break;
|
||||
case VMSG_DRAW: draw_debug_view(debug_view, rect, target, active_input); break;
|
||||
case VMSG_FREE: break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Debug_View*
|
||||
debug_view_init(View *view){
|
||||
Debug_View *result = (Debug_View*)view;
|
||||
view->type = VIEW_TYPE_DEBUG;
|
||||
view->do_view = do_debug_view;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
// BOTTOM
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 19.09.2015
|
||||
*
|
||||
* File editing view for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
enum Action_Type{
|
||||
DACT_OPEN,
|
||||
DACT_SAVE_AS,
|
||||
DACT_NEW,
|
||||
DACT_SWITCH,
|
||||
DACT_KILL,
|
||||
DACT_CLOSE_MINOR,
|
||||
DACT_CLOSE_MAJOR,
|
||||
DACT_THEME_OPTIONS
|
||||
};
|
||||
|
||||
struct Delayed_Action{
|
||||
Action_Type type;
|
||||
String string;
|
||||
Panel *panel;
|
||||
};
|
||||
|
||||
struct Delay{
|
||||
Delayed_Action acts[8];
|
||||
i32 count, max;
|
||||
};
|
||||
|
||||
inline void
|
||||
delayed_action(Delay *delay, Action_Type type,
|
||||
String string, Panel *panel){
|
||||
Assert(delay->count < delay->max);
|
||||
Delayed_Action action;
|
||||
action.type = type;
|
||||
action.string = string;
|
||||
action.panel = panel;
|
||||
delay->acts[delay->count++] = action;
|
||||
}
|
||||
|
||||
enum Interactive_View_Action{
|
||||
INTV_OPEN,
|
||||
INTV_SAVE_AS,
|
||||
INTV_NEW,
|
||||
INTV_SWITCH,
|
||||
INTV_KILL,
|
||||
};
|
||||
|
||||
enum Interactive_View_Interaction{
|
||||
INTV_SYS_FILE_LIST,
|
||||
INTV_LIVE_FILE_LIST,
|
||||
};
|
||||
|
||||
struct Interactive_View{
|
||||
View view_base;
|
||||
Hot_Directory *hot_directory;
|
||||
Style *style;
|
||||
Working_Set *working_set;
|
||||
Delay *delay;
|
||||
UI_State state;
|
||||
Interactive_View_Interaction interaction;
|
||||
Interactive_View_Action action;
|
||||
char query_[256];
|
||||
String query;
|
||||
char dest_[256];
|
||||
String dest;
|
||||
};
|
||||
|
||||
inline Interactive_View*
|
||||
view_to_interactive_view(View *view){
|
||||
Interactive_View *result = 0;
|
||||
if (view->type == VIEW_TYPE_INTERACTIVE)
|
||||
result = (Interactive_View*)view;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
interactive_view_complete(Interactive_View *view){
|
||||
Panel *panel = view->view_base.panel;
|
||||
switch (view->action){
|
||||
case INTV_OPEN:
|
||||
delayed_action(view->delay, DACT_OPEN,
|
||||
view->hot_directory->string, panel);
|
||||
break;
|
||||
|
||||
case INTV_SAVE_AS:
|
||||
delayed_action(view->delay, DACT_SAVE_AS, view->hot_directory->string, panel);
|
||||
delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel);
|
||||
break;
|
||||
|
||||
case INTV_NEW:
|
||||
delayed_action(view->delay, DACT_NEW, view->hot_directory->string, panel);
|
||||
break;
|
||||
|
||||
case INTV_SWITCH:
|
||||
delayed_action(view->delay, DACT_SWITCH, view->dest, panel);
|
||||
break;
|
||||
|
||||
case INTV_KILL:
|
||||
delayed_action(view->delay, DACT_KILL, view->dest, panel);
|
||||
delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal i32
|
||||
step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect,
|
||||
Input_Summary *user_input, bool32 input_stage){
|
||||
i32 result = 0;
|
||||
|
||||
UI_State state =
|
||||
ui_state_init(&view->state, target, user_input, view->style, view->working_set, input_stage);
|
||||
|
||||
UI_Layout layout;
|
||||
begin_layout(&layout, rect);
|
||||
|
||||
bool32 new_dir = 0;
|
||||
bool32 file_selected = 0;
|
||||
|
||||
terminate_with_null(&view->query);
|
||||
do_label(&state, &layout, view->query.str, 1.f);
|
||||
|
||||
switch (view->interaction){
|
||||
case INTV_SYS_FILE_LIST:
|
||||
if (do_file_list_box(&state, &layout, view->hot_directory, 0,
|
||||
&new_dir, &file_selected, 0)){
|
||||
result = 1;
|
||||
}
|
||||
if (new_dir){
|
||||
hot_directory_reload(view->hot_directory, view->working_set);
|
||||
}
|
||||
break;
|
||||
|
||||
case INTV_LIVE_FILE_LIST:
|
||||
if (do_live_file_list_box(&state, &layout, view->working_set, &view->dest, &file_selected)){
|
||||
result = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (file_selected){
|
||||
interactive_view_complete(view);
|
||||
}
|
||||
|
||||
if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DO_VIEW_SIG(do_interactive_view){
|
||||
i32 result = 0;
|
||||
|
||||
Interactive_View *int_view = (Interactive_View*)view;
|
||||
switch (message){
|
||||
case VMSG_STEP: case VMSG_DRAW:
|
||||
result = step_draw_int_view(int_view, target, rect, user_input, (message == VMSG_STEP));
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Interactive_View*
|
||||
interactive_view_init(View *view, Hot_Directory *hot_dir, Style *style,
|
||||
Working_Set *working_set, Delay *delay){
|
||||
Interactive_View *result = (Interactive_View*)view;
|
||||
view->type = VIEW_TYPE_INTERACTIVE;
|
||||
view->do_view = do_interactive_view;
|
||||
result->hot_directory = hot_dir;
|
||||
hot_directory_clean_end(hot_dir);
|
||||
hot_directory_reload(hot_dir, working_set);
|
||||
result->query = make_fixed_width_string(result->query_);
|
||||
result->dest = make_fixed_width_string(result->dest_);
|
||||
result->style = style;
|
||||
result->working_set = working_set;
|
||||
result->delay = delay;
|
||||
return result;
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 16.05.2015
|
||||
*
|
||||
* Fascilities available for development but not intended for shipping.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Profiling
|
||||
*/
|
||||
|
||||
#if FRED_INTERNAL == 1
|
||||
enum Debug_Event_Type{
|
||||
DBGEV_START,
|
||||
DBGEV_END,
|
||||
DBGEV_MOMENT,
|
||||
// never below this
|
||||
DBGEV_COUNT
|
||||
};
|
||||
|
||||
struct Debug_Event{
|
||||
i64 time;
|
||||
char *name;
|
||||
Debug_Event_Type type;
|
||||
i32 which_hit;
|
||||
i32 event_index;
|
||||
i32 thread_index;
|
||||
};
|
||||
|
||||
struct Debug_Event_Array{
|
||||
volatile u32 count;
|
||||
Debug_Event e[512];
|
||||
};
|
||||
|
||||
struct Profile_Frame{
|
||||
Debug_Event_Array events;
|
||||
i32 dbg_procing_start;
|
||||
i32 dbg_procing_end;
|
||||
i32 index;
|
||||
i32 first_key;
|
||||
};
|
||||
|
||||
Profile_Frame profile_frame;
|
||||
|
||||
#define PAST_PROFILE_COUNT 30
|
||||
Profile_Frame past_frames[PAST_PROFILE_COUNT];
|
||||
|
||||
extern const i32 INTERNAL_event_index_count;
|
||||
extern u32 INTERNAL_event_hits[];
|
||||
i64 INTERNAL_frame_start_time;
|
||||
|
||||
bool32 INTERNAL_collecting_events;
|
||||
|
||||
inline u32
|
||||
post_debug_event(char *name, Debug_Event_Type type, i32 event_index, i32 thread_index, u32 which_hit){
|
||||
u32 result = 0;
|
||||
if (INTERNAL_collecting_events){
|
||||
u32 index =
|
||||
InterlockedIncrement(&profile_frame.events.count);
|
||||
--index;
|
||||
|
||||
Assert(index < ArrayCount(profile_frame.events.e));
|
||||
|
||||
Debug_Event ev;
|
||||
ev.time = system_time() - INTERNAL_frame_start_time;
|
||||
ev.name = name;
|
||||
ev.type = type;
|
||||
ev.event_index = event_index;
|
||||
ev.thread_index = thread_index;
|
||||
|
||||
if (type == DBGEV_END){
|
||||
ev.which_hit = which_hit;
|
||||
}
|
||||
else{
|
||||
ev.which_hit = InterlockedIncrement(INTERNAL_event_hits + event_index) - 1;
|
||||
}
|
||||
|
||||
profile_frame.events.e[index] = ev;
|
||||
result = ev.which_hit;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal u32
|
||||
quick_partition(Debug_Event *es, u32 start, u32 pivot){
|
||||
Debug_Event *p = es + pivot;
|
||||
|
||||
i32 m = (start + pivot) >> 1;
|
||||
Swap(*p, es[m]);
|
||||
|
||||
i32 pn = p->thread_index;
|
||||
i32 pe = p->event_index;
|
||||
i32 ph = p->which_hit;
|
||||
i32 pt = p->type;
|
||||
|
||||
for (u32 i = start; i < pivot; ++i){
|
||||
Debug_Event *e = es + i;
|
||||
|
||||
bool32 smaller = 0;
|
||||
|
||||
if (e->thread_index < pn) smaller = 1;
|
||||
else if (e->thread_index == pn){
|
||||
if (e->type != DBGEV_MOMENT && pt == DBGEV_MOMENT) smaller = 1;
|
||||
else if (e->type != DBGEV_MOMENT){
|
||||
if (e->event_index < pe) smaller = 1;
|
||||
else if (e->event_index == pe){
|
||||
if (e->which_hit < ph) smaller = 1;
|
||||
else if (e->which_hit == ph){
|
||||
if (e->type < pt) smaller = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pt == DBGEV_MOMENT){
|
||||
if (e->time < p->time) smaller = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (smaller){
|
||||
Swap(*e, es[start]);
|
||||
++start;
|
||||
}
|
||||
}
|
||||
Swap(*p, es[start]);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
internal void
|
||||
quick_sort(Debug_Event *e, u32 start, u32 pivot){
|
||||
u32 mid = quick_partition(e, start, pivot);
|
||||
if (start + 1 < mid) quick_sort(e, start, mid - 1);
|
||||
if (mid + 1 < pivot) quick_sort(e, mid + 1, pivot);
|
||||
}
|
||||
|
||||
inline void
|
||||
sort(Debug_Event_Array *events){
|
||||
quick_sort(events->e, 0, events->count - 1);
|
||||
}
|
||||
|
||||
globalvar i32 INTERNAL_frame_index;
|
||||
globalvar bool32 INTERNAL_updating_profile;
|
||||
|
||||
#define ProfileStart_(name, start, counter, hit, thread, n, c)\
|
||||
name = n; counter = c; start = system_time(); hit = post_debug_event(n, DBGEV_START, counter, thread, 0)
|
||||
#define ProfileEnd_(name, start, counter, hit, thread) post_debug_event(name, DBGEV_END, counter, thread, hit)
|
||||
#define ProfileMoment_(name, counter, thread) post_debug_event(name, DBGEV_MOMENT, counter, thread, 0)
|
||||
|
||||
struct INTERNAL_Profile_Block{
|
||||
char *name;
|
||||
i64 start;
|
||||
i32 counter;
|
||||
i32 thread;
|
||||
i32 hit;
|
||||
|
||||
INTERNAL_Profile_Block(char *n, i32 c, i32 t){
|
||||
ProfileStart_(name, start, counter, hit, t, n, c);
|
||||
thread = t;
|
||||
}
|
||||
|
||||
~INTERNAL_Profile_Block(){
|
||||
ProfileEnd_(name, start, counter, hit, thread);
|
||||
}
|
||||
};
|
||||
|
||||
#define ProfileBlock(name, thread) INTERNAL_Profile_Block name(#name, __COUNTER__, thread)
|
||||
#define ProfileBlockFunction() INTERNAL_Profile_Block name(__FUNCTION__, __COUNTER__, 0)
|
||||
|
||||
#define ProfileStart(name) char *_pname_##name; i64 _pstart_##name; i32 _pcounter_##name; u32 _phit_##name; \
|
||||
ProfileStart_(_pname_##name, _pstart_##name, _pcounter_##name, _phit_##name, system_thread_get_id(thread), #name, __COUNTER__)
|
||||
|
||||
#define ProfileEnd(name) ProfileEnd_(_pname_##name, _pstart_##name, _pcounter_##name, _phit_##name, system_thread_get_id(thread))
|
||||
|
||||
#define ProfileMoment(name, thread) ProfileMoment_(#name, __COUNTER__, thread)
|
||||
#define ProfileMomentFunction() ProfileMoment_(__FUNCTION__, __COUNTER__, 0)
|
||||
|
||||
#else
|
||||
|
||||
#define ProfileBlock(name)
|
||||
#define ProfileStart(name)
|
||||
#define ProfileEnd(name)
|
||||
#define ProfileMoment(name)
|
||||
#define ProfileMomentFunction()
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 12.17.2014
|
||||
*
|
||||
* Win32-US Keyboard layer for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
globalvar u16 keycode_lookup_table[255];
|
||||
globalvar u16 loose_keycode_lookup_table[255];
|
||||
|
||||
internal void
|
||||
keycode_init(Key_Codes *codes, Key_Codes *loose_codes){
|
||||
// NOTE(allen): Assign values to the global keycodes.
|
||||
// Skip over the ascii characters that are used as codes.
|
||||
u16 code = 1;
|
||||
u16 *codes_array = (u16*)codes;
|
||||
for (i32 i = 0; i < sizeof(Key_Codes)/2;){
|
||||
switch (code){
|
||||
case '\n': code++; break;
|
||||
case '\t': code++; break;
|
||||
case 0x20: code = 0x7F; break;
|
||||
|
||||
default:
|
||||
codes_array[i++] = code++;
|
||||
}
|
||||
}
|
||||
|
||||
code = 1;
|
||||
codes_array = (u16*)loose_codes;
|
||||
for (i32 i = 0; i < sizeof(Key_Codes)/2; ++i){
|
||||
codes_array[i] = code++;
|
||||
}
|
||||
|
||||
// NOTE(allen): lookup table for conversion from
|
||||
// win32 vk values to fred_keycode values.
|
||||
for (u8 i = 0; i < 255; ++i){
|
||||
if ((i >= '0' && i <= '9') ||
|
||||
(i >= 'A' && i <= 'Z')){
|
||||
keycode_lookup_table[i] = i;
|
||||
loose_keycode_lookup_table[i] = 0;
|
||||
}
|
||||
else{
|
||||
|
||||
u16 code, loose = 0;
|
||||
switch (i){
|
||||
case VK_SPACE: code = ' '; break;
|
||||
case VK_BACK: code = loose = codes->back; break;
|
||||
case VK_OEM_MINUS: code = '-'; break;
|
||||
case VK_OEM_PLUS: code = '='; break;
|
||||
case VK_SUBTRACT: code = '-'; break;
|
||||
case VK_ADD: code = '+'; break;
|
||||
case VK_MULTIPLY: code = '*'; break;
|
||||
case VK_DIVIDE: code = '/'; break;
|
||||
|
||||
case VK_OEM_3: code = '`'; break;
|
||||
case VK_OEM_5: code = '\\'; break;
|
||||
case VK_OEM_4: code = '['; break;
|
||||
case VK_OEM_6: code = ']'; break;
|
||||
case VK_TAB: code = '\t'; break;
|
||||
case VK_RETURN: code = '\n'; break;
|
||||
case VK_OEM_7: code = '\''; break;
|
||||
|
||||
case VK_OEM_1: code = ';'; break;
|
||||
case VK_OEM_2: code = '/'; break;
|
||||
case VK_OEM_PERIOD: code = '.'; break;
|
||||
case VK_OEM_COMMA: code = ','; break;
|
||||
case VK_UP: code = loose = codes->up; break;
|
||||
case VK_DOWN: code = loose = codes->down; break;
|
||||
case VK_LEFT: code = loose = codes->left; break;
|
||||
case VK_RIGHT: code = loose = codes->right; break;
|
||||
case VK_DELETE: code = loose = codes->del; break;
|
||||
|
||||
case VK_INSERT: code = loose = codes->insert; break;
|
||||
case VK_HOME: code = loose = codes->home; break;
|
||||
case VK_END: code = loose = codes->end; break;
|
||||
case VK_PRIOR: code = loose = codes->page_up; break;
|
||||
case VK_NEXT: code = loose = codes->page_down; break;
|
||||
case VK_ESCAPE: code = loose = codes->esc; break;
|
||||
|
||||
case VK_NUMPAD0:
|
||||
case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3:
|
||||
case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6:
|
||||
case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9:
|
||||
code = (i - VK_NUMPAD0) + '0'; break;
|
||||
|
||||
default: code = 0; break;
|
||||
}
|
||||
|
||||
keycode_lookup_table[i] = code;
|
||||
loose_keycode_lookup_table[i] = loose;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline u16
|
||||
keycode_lookup(u8 virtual_keycode){
|
||||
return keycode_lookup_table[virtual_keycode];
|
||||
}
|
||||
|
||||
inline u16
|
||||
loose_keycode_lookup(u8 virtual_keycode){
|
||||
return loose_keycode_lookup_table[virtual_keycode];
|
||||
}
|
||||
|
||||
inline bool32
|
||||
keycode_has_ascii(u16 keycode){
|
||||
return (keycode >= 0x20 && keycode < 0x7F) || keycode == '\n' || keycode == '\t';
|
||||
}
|
||||
|
||||
internal u8
|
||||
keycode_to_character_ascii(Key_Codes *codes,
|
||||
u16 keycode,
|
||||
bool32 shift,
|
||||
bool32 caps_lock){
|
||||
u8 character = 0;
|
||||
if (keycode >= 'A' && keycode <= 'Z'){
|
||||
if (caps_lock) shift = !shift;
|
||||
if (!shift) character = char_to_lower((char)keycode);
|
||||
else character = (u8)keycode;
|
||||
}
|
||||
else if (keycode >= '0' && keycode <= '9'){
|
||||
persist u8 shift_number_table[10] = {
|
||||
')', '!', '@', '#', '$', '%', '^', '&', '*', '('
|
||||
//0 1 2 3 4 5 6 7 8 9
|
||||
};
|
||||
if (shift){
|
||||
character = shift_number_table[keycode - '0'];
|
||||
}
|
||||
else{
|
||||
character = (u8)keycode;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (keycode_has_ascii(keycode)){
|
||||
character = (u8)keycode;
|
||||
u8 shift_character = character;
|
||||
switch (keycode){
|
||||
case '-': character = '-'; shift_character = '_'; break;
|
||||
case '=': character = '='; shift_character = '+'; break;
|
||||
case '`': character = '`'; shift_character = '~'; break;
|
||||
case '\\': character = '\\'; shift_character = '|'; break;
|
||||
case '[': character = '['; shift_character = '{'; break;
|
||||
case ']': character = ']'; shift_character = '}'; break;
|
||||
case '\'': character = '\''; shift_character = '"'; break;
|
||||
case ';': character = ';'; shift_character = ':'; break;
|
||||
case '/': character = '/'; shift_character = '?'; break;
|
||||
case '.': character = '.'; shift_character = '>'; break;
|
||||
case ',': character = ','; shift_character = '<'; break;
|
||||
case ' ': character = ' '; shift_character = ' '; break;
|
||||
case '\n': character = '\n'; shift_character = '\n'; break;
|
||||
case '\t': character = '\t'; shift_character = '\t'; break;
|
||||
}
|
||||
if (shift) character = shift_character;
|
||||
}
|
||||
}
|
||||
return character;
|
||||
}
|
||||
|
||||
// BOTTOM
|
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 19.08.2015
|
||||
*
|
||||
* Panel layout and general view functions for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
// TODO(allen):
|
||||
//
|
||||
// BUGS
|
||||
//
|
||||
|
||||
struct Interactive_Style{
|
||||
u32 bar_color;
|
||||
u32 bar_active_color;
|
||||
u32 base_color;
|
||||
u32 pop1_color;
|
||||
u32 pop2_color;
|
||||
};
|
||||
|
||||
struct Interactive_Bar{
|
||||
Interactive_Style style;
|
||||
real32 pos_x, pos_y;
|
||||
real32 text_shift_x, text_shift_y;
|
||||
i32_Rect rect;
|
||||
Font *font;
|
||||
};
|
||||
|
||||
enum View_Message{
|
||||
VMSG_STEP,
|
||||
VMSG_DRAW,
|
||||
VMSG_RESIZE,
|
||||
VMSG_STYLE_CHANGE,
|
||||
VMSG_FREE
|
||||
};
|
||||
|
||||
struct View;
|
||||
#define DO_VIEW_SIG(name)\
|
||||
i32 (name)(Thread_Context *thread, View *view, i32_Rect rect, View *active,\
|
||||
View_Message message, Render_Target *target, Input_Summary *user_input, Input_Summary *active_input)
|
||||
typedef DO_VIEW_SIG(Do_View_Function);
|
||||
|
||||
#define HANDLE_COMMAND_SIG(name)\
|
||||
void (name)(View *view, Command_Data *command, Command_Binding binding,\
|
||||
Key_Single key, Key_Codes *codes)
|
||||
typedef HANDLE_COMMAND_SIG(Handle_Command_Function);
|
||||
|
||||
// TODO(allen): this shouldn't exist
|
||||
enum View_Type{
|
||||
VIEW_TYPE_NONE,
|
||||
VIEW_TYPE_FILE,
|
||||
VIEW_TYPE_COLOR,
|
||||
VIEW_TYPE_DEBUG,
|
||||
VIEW_TYPE_INTERACTIVE,
|
||||
VIEW_TYPE_MENU
|
||||
};
|
||||
|
||||
struct Panel;
|
||||
struct View{
|
||||
union{
|
||||
View *next_free;
|
||||
View *major;
|
||||
View *minor;
|
||||
};
|
||||
Panel *panel;
|
||||
Command_Map *map;
|
||||
Do_View_Function *do_view;
|
||||
Handle_Command_Function *handle_command;
|
||||
General_Memory *general;
|
||||
i32 type;
|
||||
i32 block_size;
|
||||
Application_Mouse_Cursor mouse_cursor_type;
|
||||
bool32 is_active;
|
||||
bool32 is_minor;
|
||||
};
|
||||
|
||||
struct Live_Views{
|
||||
void *views;
|
||||
View *free_view;
|
||||
i32 count, max;
|
||||
i32 stride;
|
||||
};
|
||||
|
||||
struct Panel_Divider{
|
||||
Panel_Divider *next_free;
|
||||
i32 parent;
|
||||
i32 which_child;
|
||||
i32 child1, child2;
|
||||
bool32 v_divider;
|
||||
i32 pos;
|
||||
};
|
||||
|
||||
struct Screen_Region{
|
||||
i32_Rect full;
|
||||
i32_Rect inner;
|
||||
i32_Rect prev_inner;
|
||||
i32 l_margin, r_margin;
|
||||
i32 t_margin, b_margin;
|
||||
};
|
||||
|
||||
struct Panel{
|
||||
View *view;
|
||||
i32 parent;
|
||||
i32 which_child;
|
||||
union{
|
||||
struct{
|
||||
i32_Rect full;
|
||||
i32_Rect inner;
|
||||
i32_Rect prev_inner;
|
||||
i32 l_margin, r_margin;
|
||||
i32 t_margin, b_margin;
|
||||
};
|
||||
Screen_Region screen_region;
|
||||
};
|
||||
};
|
||||
|
||||
struct Editing_Layout{
|
||||
Panel *panels;
|
||||
Panel_Divider *dividers;
|
||||
Panel_Divider *free_divider;
|
||||
i32 panel_count, panel_max_count;
|
||||
i32 root;
|
||||
i32 active_panel;
|
||||
i32 full_width, full_height;
|
||||
};
|
||||
|
||||
internal void
|
||||
intbar_draw_string(Render_Target *target, Interactive_Bar *bar,
|
||||
u8 *str, u32 char_color){
|
||||
Font *font = bar->font;
|
||||
for (i32 i = 0; str[i]; ++i){
|
||||
char c = str[i];
|
||||
font_draw_glyph(target, font, c,
|
||||
bar->pos_x + bar->text_shift_x,
|
||||
bar->pos_y + bar->text_shift_y,
|
||||
char_color);
|
||||
bar->pos_x += font_get_glyph_width(font, c);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
intbar_draw_string(Render_Target *target,
|
||||
Interactive_Bar *bar, String str,
|
||||
u32 char_color){
|
||||
Font *font = bar->font;
|
||||
for (i32 i = 0; i < str.size; ++i){
|
||||
char c = str.str[i];
|
||||
font_draw_glyph(target, font, c,
|
||||
bar->pos_x + bar->text_shift_x,
|
||||
bar->pos_y + bar->text_shift_y,
|
||||
char_color);
|
||||
bar->pos_x += font_get_glyph_width(font, c);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
panel_init(Panel *panel){
|
||||
*panel = {};
|
||||
panel->parent = -1;
|
||||
panel->l_margin = 3;
|
||||
panel->r_margin = 3;
|
||||
panel->t_margin = 3;
|
||||
panel->b_margin = 3;
|
||||
}
|
||||
|
||||
internal View*
|
||||
live_set_get_view(Live_Views *live_set, i32 i){
|
||||
void *result = ((char*)live_set->views + i*live_set->stride);
|
||||
return (View*)result;
|
||||
}
|
||||
|
||||
internal View*
|
||||
live_set_alloc_view(Live_Views *live_set, General_Memory *general){
|
||||
Assert(live_set->count < live_set->max);
|
||||
View *result = 0;
|
||||
result = live_set->free_view;
|
||||
live_set->free_view = result->next_free;
|
||||
memset(result, 0, live_set->stride);
|
||||
++live_set->count;
|
||||
result->is_active = 1;
|
||||
result->general = general;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void
|
||||
live_set_free_view(Live_Views *live_set, View *view){
|
||||
Assert(live_set->count > 0);
|
||||
view->do_view(0, view, {}, 0, VMSG_FREE, 0, {}, 0);
|
||||
view->next_free = live_set->free_view;
|
||||
live_set->free_view = view;
|
||||
--live_set->count;
|
||||
view->is_active = 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
view_replace_major(View *new_view, Panel *panel, Live_Views *live_set){
|
||||
View *view = panel->view;
|
||||
if (view){
|
||||
if (view->is_minor && view->major){
|
||||
live_set_free_view(live_set, view->major);
|
||||
}
|
||||
live_set_free_view(live_set, view);
|
||||
}
|
||||
new_view->panel = panel;
|
||||
new_view->minor = 0;
|
||||
panel->view = new_view;
|
||||
}
|
||||
|
||||
inline void
|
||||
view_replace_minor(View *new_view, Panel *panel, Live_Views *live_set){
|
||||
View *view = panel->view;
|
||||
new_view->is_minor = 1;
|
||||
if (view){
|
||||
if (view->is_minor){
|
||||
new_view->major = view->major;
|
||||
live_set_free_view(live_set, view);
|
||||
}
|
||||
else{
|
||||
new_view->major = view;
|
||||
view->is_active = 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
new_view->major = 0;
|
||||
}
|
||||
new_view->panel = panel;
|
||||
panel->view = new_view;
|
||||
}
|
||||
|
||||
inline void
|
||||
view_remove_major(Panel *panel, Live_Views *live_set){
|
||||
View *view = panel->view;
|
||||
if (view){
|
||||
if (view->is_minor && view->major){
|
||||
live_set_free_view(live_set, view->major);
|
||||
}
|
||||
live_set_free_view(live_set, view);
|
||||
}
|
||||
panel->view = 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
view_remove_major_leave_minor(Panel *panel, Live_Views *live_set){
|
||||
View *view = panel->view;
|
||||
if (view){
|
||||
if (view->is_minor && view->major){
|
||||
live_set_free_view(live_set, view->major);
|
||||
view->major = 0;
|
||||
}
|
||||
else{
|
||||
live_set_free_view(live_set, view);
|
||||
panel->view = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
view_remove_minor(Panel *panel, Live_Views *live_set){
|
||||
View *view = panel->view;
|
||||
View *major = 0;
|
||||
if (view){
|
||||
if (view->is_minor){
|
||||
major = view->major;
|
||||
live_set_free_view(live_set, view);
|
||||
}
|
||||
}
|
||||
panel->view = major;
|
||||
if (major) major->is_active = 1;
|
||||
}
|
||||
|
||||
inline void
|
||||
view_remove(Panel *panel, Live_Views *live_set){
|
||||
View *view = panel->view;
|
||||
if (view->is_minor) view_remove_minor(panel, live_set);
|
||||
else view_remove_major(panel, live_set);
|
||||
}
|
||||
|
||||
struct Divider_And_ID{
|
||||
Panel_Divider* divider;
|
||||
i32 id;
|
||||
};
|
||||
|
||||
internal Divider_And_ID
|
||||
layout_alloc_divider(Editing_Layout *layout){
|
||||
Assert(layout->free_divider);
|
||||
Divider_And_ID result;
|
||||
result.divider = layout->free_divider;
|
||||
layout->free_divider = result.divider->next_free;
|
||||
*result.divider = {};
|
||||
result.divider->parent = -1;
|
||||
result.divider->child1 = -1;
|
||||
result.divider->child2 = -1;
|
||||
result.id = (i32)(result.divider - layout->dividers);
|
||||
if (layout->panel_count == 1){
|
||||
layout->root = result.id;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Divider_And_ID
|
||||
layout_get_divider(Editing_Layout *layout, i32 id){
|
||||
Assert(id >= 0 && id < layout->panel_max_count-1);
|
||||
Divider_And_ID result;
|
||||
result.id = id;
|
||||
result.divider = layout->dividers + id;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Panel*
|
||||
layout_alloc_panel(Editing_Layout *layout){
|
||||
Assert(layout->panel_count < layout->panel_max_count);
|
||||
Panel *result = layout->panels + layout->panel_count;
|
||||
*result = {};
|
||||
++layout->panel_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_free_divider(Editing_Layout *layout, Panel_Divider *divider){
|
||||
divider->next_free = layout->free_divider;
|
||||
layout->free_divider = divider;
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_free_panel(Editing_Layout *layout, Panel *panel){
|
||||
Panel *panels = layout->panels;
|
||||
i32 panel_count = --layout->panel_count;
|
||||
i32 panel_i = (i32)(panel - layout->panels);
|
||||
for (i32 i = panel_i; i < panel_count; ++i){
|
||||
Panel *p = panels + i;
|
||||
*p = panels[i+1];
|
||||
if (p->view){
|
||||
p->view->panel = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal Divider_And_ID
|
||||
layout_calc_divider_id(Editing_Layout *layout, Panel_Divider *divider){
|
||||
Divider_And_ID result;
|
||||
result.divider = divider;
|
||||
result.id = (i32)(divider - layout->dividers);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Split_Result{
|
||||
Panel_Divider *divider;
|
||||
Panel *panel;
|
||||
};
|
||||
|
||||
internal Split_Result
|
||||
layout_split_panel(Editing_Layout *layout, Panel *panel, bool32 vertical){
|
||||
Divider_And_ID div = layout_alloc_divider(layout);
|
||||
if (panel->parent != -1){
|
||||
Divider_And_ID pdiv = layout_get_divider(layout, panel->parent);
|
||||
if (panel->which_child == -1){
|
||||
pdiv.divider->child1 = div.id;
|
||||
}
|
||||
else{
|
||||
pdiv.divider->child2 = div.id;
|
||||
}
|
||||
}
|
||||
|
||||
div.divider->parent = panel->parent;
|
||||
div.divider->which_child = panel->which_child;
|
||||
if (vertical){
|
||||
div.divider->v_divider = 1;
|
||||
div.divider->pos = (panel->full.x0 + panel->full.x1) / 2;
|
||||
}
|
||||
else{
|
||||
div.divider->v_divider = 0;
|
||||
div.divider->pos = (panel->full.y0 + panel->full.y1) / 2;
|
||||
}
|
||||
|
||||
Panel *new_panel = layout_alloc_panel(layout);
|
||||
panel->parent = div.id;
|
||||
panel->which_child = -1;
|
||||
new_panel->parent = div.id;
|
||||
new_panel->which_child = 1;
|
||||
|
||||
Split_Result result;
|
||||
result.divider = div.divider;
|
||||
result.panel = new_panel;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
panel_fix_internal_area(Panel *panel){
|
||||
i32 left, right, top, bottom;
|
||||
left = panel->l_margin;
|
||||
right = panel->r_margin;
|
||||
top = panel->t_margin;
|
||||
bottom = panel->b_margin;
|
||||
|
||||
panel->inner.x0 = panel->full.x0 + left;
|
||||
panel->inner.x1 = panel->full.x1 - right;
|
||||
panel->inner.y0 = panel->full.y0 + top;
|
||||
panel->inner.y1 = panel->full.y1 - bottom;
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_fix_all_panels(Editing_Layout *layout){
|
||||
Panel *panels = layout->panels;
|
||||
if (layout->panel_count > 1){
|
||||
Panel_Divider *dividers = layout->dividers;
|
||||
int panel_count = layout->panel_count;
|
||||
|
||||
Panel *panel = panels;
|
||||
for (i32 i = 0; i < panel_count; ++i){
|
||||
i32 x0, x1, y0, y1;
|
||||
x0 = 0;
|
||||
x1 = x0 + layout->full_width;
|
||||
y0 = 0;
|
||||
y1 = y0 + layout->full_height;
|
||||
|
||||
i32 pos;
|
||||
i32 which_child = panel->which_child;
|
||||
Divider_And_ID div;
|
||||
div.id = panel->parent;
|
||||
|
||||
for (;;){
|
||||
div.divider = dividers + div.id;
|
||||
pos = div.divider->pos;
|
||||
div.divider = dividers + div.id;
|
||||
// NOTE(allen): sorry if this is hard to read through, there are
|
||||
// two binary conditionals that combine into four possible cases.
|
||||
// Why am I appologizing to you? IF YOU CANT HANDLE MY CODE GET OUT!
|
||||
i32 action = (div.divider->v_divider << 1) | (which_child > 0);
|
||||
switch (action){
|
||||
case 0: // v_divider : 0, which_child : -1
|
||||
if (pos < y1) y1 = pos;
|
||||
break;
|
||||
case 1: // v_divider : 0, which_child : 1
|
||||
if (pos > y0) y0 = pos;
|
||||
break;
|
||||
case 2: // v_divider : 1, which_child : -1
|
||||
if (pos < x1) x1 = pos;
|
||||
break;
|
||||
case 3: // v_divider : 1, which_child : 1
|
||||
if (pos > x0) x0 = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (div.id != layout->root){
|
||||
div.id = div.divider->parent;
|
||||
which_child = div.divider->which_child;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
panel->full.x0 = x0;
|
||||
panel->full.y0 = y0;
|
||||
panel->full.x1 = x1;
|
||||
panel->full.y1 = y1;
|
||||
panel_fix_internal_area(panel);
|
||||
++panel;
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
panels[0].full.x0 = 0;
|
||||
panels[0].full.y0 = 0;
|
||||
panels[0].full.x1 = layout->full_width;
|
||||
panels[0].full.y1 = layout->full_height;
|
||||
panel_fix_internal_area(panels);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
layout_refit(Editing_Layout *layout,
|
||||
i32 prev_x_off, i32 prev_y_off,
|
||||
i32 prev_width, i32 prev_height){
|
||||
Panel_Divider *dividers = layout->dividers;
|
||||
i32 divider_max_count = layout->panel_max_count - 1;
|
||||
|
||||
i32 x_off = 0;
|
||||
i32 y_off = 0;
|
||||
|
||||
real32 h_ratio = ((real32)layout->full_width) / prev_width;
|
||||
real32 v_ratio = ((real32)layout->full_height) / prev_height;
|
||||
|
||||
for (i32 divider_id = 0; divider_id < divider_max_count; ++divider_id){
|
||||
Panel_Divider *divider = dividers + divider_id;
|
||||
if (divider->v_divider){
|
||||
divider->pos = x_off + ROUND32((divider->pos - prev_x_off) * h_ratio);
|
||||
}
|
||||
else{
|
||||
divider->pos = y_off + ROUND32((divider->pos - prev_y_off) * v_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
layout_fix_all_panels(layout);
|
||||
}
|
||||
|
||||
inline real32
|
||||
view_base_compute_width(View *view){
|
||||
Panel *panel = view->panel;
|
||||
return (real32)(panel->inner.x1 - panel->inner.x0);
|
||||
}
|
||||
|
||||
inline real32
|
||||
view_base_compute_height(View *view){
|
||||
Panel *panel = view->panel;
|
||||
return (real32)(panel->inner.y1 - panel->inner.y0);
|
||||
}
|
||||
|
||||
#define view_compute_width(view) (view_base_compute_width(&(view)->view_base))
|
||||
#define view_compute_height(view) (view_base_compute_height(&(view)->view_base))
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,749 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 15.05.2015
|
||||
*
|
||||
* Math functions for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
/*
|
||||
* Scalar operators
|
||||
*/
|
||||
|
||||
#define C_MATH 1
|
||||
|
||||
#define DEG_TO_RAD 0.0174533f
|
||||
|
||||
#if C_MATH
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
inline real32
|
||||
ABS(real32 x){
|
||||
#if C_MATH
|
||||
return abs(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline real32
|
||||
MOD(real32 x, i32 m){
|
||||
#if C_MATH
|
||||
real32 whole, frac;
|
||||
frac = modf(x, &whole);
|
||||
return ((i32)(whole) % m) + frac;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline real32
|
||||
SQRT(real32 x){
|
||||
#if C_MATH
|
||||
return sqrt(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline real32
|
||||
SIN(real32 x_degrees){
|
||||
#if C_MATH
|
||||
return sinf(x_degrees * DEG_TO_RAD);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline real32
|
||||
COS(real32 x_degrees){
|
||||
#if C_MATH
|
||||
return cosf(x_degrees * DEG_TO_RAD);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Rounding
|
||||
*/
|
||||
|
||||
inline i32
|
||||
TRUNC32(real32 x) { return (i32)x; }
|
||||
|
||||
inline i32
|
||||
FLOOR32(real32 x) { return (i32)(x)-((x!=(i32)(x) && x<0)?1:0); }
|
||||
|
||||
inline i32
|
||||
CEIL32(real32 x) { return (i32)(x)+((x!=(i32)(x) && x>0)?1:0); }
|
||||
|
||||
inline i32
|
||||
ROUND32(real32 x) { return FLOOR32(x + .5f); }
|
||||
|
||||
inline i32
|
||||
DIVCEIL32(i32 n, i32 d) {
|
||||
i32 q = (n/d);
|
||||
return q + (q*d < n);
|
||||
}
|
||||
|
||||
inline real32
|
||||
FRACPART32(real32 x) { return x - (i32)x; }
|
||||
|
||||
/*
|
||||
* Rectangles
|
||||
*/
|
||||
|
||||
struct i32_Rect{
|
||||
i32 x0, y0;
|
||||
i32 x1, y1;
|
||||
};
|
||||
|
||||
struct real32_Rect{
|
||||
real32 x0, y0;
|
||||
real32 x1, y1;
|
||||
};
|
||||
|
||||
inline i32_Rect
|
||||
i32R(i32 l, i32 t, i32 r, i32 b){
|
||||
i32_Rect rect;
|
||||
rect.x0 = l; rect.y0 = t;
|
||||
rect.x1 = r; rect.y1 = b;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
i32R(real32_Rect r){
|
||||
i32_Rect rect;
|
||||
rect.x0 = (i32)r.x0;
|
||||
rect.y0 = (i32)r.y0;
|
||||
rect.x1 = (i32)r.x1;
|
||||
rect.y1 = (i32)r.y1;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
i32XYWH(i32 x, i32 y, i32 w, i32 h){
|
||||
i32_Rect rect;
|
||||
rect.x0 = x; rect.y0 = y;
|
||||
rect.x1 = x+w; rect.y1 = y+h;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline real32_Rect
|
||||
real32R(real32 l, real32 t, real32 r, real32 b){
|
||||
real32_Rect rect;
|
||||
rect.x0 = l; rect.y0 = t;
|
||||
rect.x1 = r; rect.y1 = b;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline real32_Rect
|
||||
real32R(i32_Rect r){
|
||||
real32_Rect rect;
|
||||
rect.x0 = (real32)r.x0;
|
||||
rect.y0 = (real32)r.y0;
|
||||
rect.x1 = (real32)r.x1;
|
||||
rect.y1 = (real32)r.y1;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline real32_Rect
|
||||
real32XYWH(real32 x, real32 y, real32 w, real32 h){
|
||||
real32_Rect rect;
|
||||
rect.x0 = x; rect.y0 = y;
|
||||
rect.x1 = x+w; rect.y1 = y+h;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline bool32
|
||||
hit_check(i32 x, i32 y, i32 x0, i32 y0, i32 x1, i32 y1){
|
||||
return (x >= x0 && x < x1 && y >= y0 && y < y1);
|
||||
}
|
||||
|
||||
inline bool32
|
||||
hit_check(i32 x, i32 y, i32_Rect rect){
|
||||
return (hit_check(x, y, rect.x0, rect.y0, rect.x1, rect.y1));
|
||||
}
|
||||
|
||||
inline bool32
|
||||
hit_check(i32 x, i32 y, real32 x0, real32 y0, real32 x1, real32 y1){
|
||||
return (x >= x0 && x < x1 && y >= y0 && y < y1);
|
||||
}
|
||||
|
||||
inline bool32
|
||||
hit_check(i32 x, i32 y, real32_Rect rect){
|
||||
return (hit_check(x, y, rect.x0, rect.y0, rect.x1, rect.y1));
|
||||
}
|
||||
|
||||
inline bool32
|
||||
positive_area(i32_Rect rect){
|
||||
return (rect.x0 < rect.x1 && rect.y0 < rect.y1);
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
get_inner_rect(i32_Rect outer, i32 margin){
|
||||
i32_Rect r;
|
||||
r.x0 = outer.x0 + margin;
|
||||
r.y0 = outer.y0 + margin;
|
||||
r.x1 = outer.x1 - margin;
|
||||
r.y1 = outer.y1 - margin;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline bool32
|
||||
fits_inside(i32_Rect rect, i32_Rect outer){
|
||||
return (rect.x0 >= outer.x0 && rect.x1 <= outer.x1 &&
|
||||
rect.y0 >= outer.y0 && rect.y1 <= outer.y1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vectors
|
||||
*/
|
||||
|
||||
struct Vec2{
|
||||
union{
|
||||
struct{
|
||||
real32 x, y;
|
||||
};
|
||||
struct{
|
||||
real32 v[2];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct Vec3{
|
||||
union{
|
||||
struct{
|
||||
real32 x, y, z;
|
||||
};
|
||||
struct{
|
||||
real32 r, g, b;
|
||||
};
|
||||
struct{
|
||||
Vec2 xy;
|
||||
real32 _z;
|
||||
};
|
||||
struct{
|
||||
real32 _x;
|
||||
Vec2 yz;
|
||||
};
|
||||
struct{
|
||||
real32 v[3];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct Vec4{
|
||||
union{
|
||||
struct{
|
||||
real32 r, g, b, a;
|
||||
};
|
||||
|
||||
struct{
|
||||
real32 h, s, l, __a;
|
||||
};
|
||||
struct{
|
||||
real32 x, y, z, w;
|
||||
};
|
||||
struct{
|
||||
Vec3 rgb;
|
||||
real32 _a;
|
||||
};
|
||||
struct{
|
||||
Vec3 xyz;
|
||||
real32 _w;
|
||||
};
|
||||
struct{
|
||||
real32 _x;
|
||||
Vec3 yzw;
|
||||
};
|
||||
struct{
|
||||
real32 v[4];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inline internal Vec2
|
||||
V2(real32 x, real32 y){
|
||||
Vec2 result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
V3(real32 x, real32 y, real32 z){
|
||||
Vec3 result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
result.z = z;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec4
|
||||
V4(real32 x, real32 y, real32 z, real32 w){
|
||||
Vec4 result;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
result.z = z;
|
||||
result.w = w;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2
|
||||
operator+(Vec2 a, Vec2 b){
|
||||
Vec2 result;
|
||||
result.x = a.x + b.x;
|
||||
result.y = a.y + b.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
operator+(Vec3 a, Vec3 b){
|
||||
Vec3 result;
|
||||
result.x = a.x + b.x;
|
||||
result.y = a.y + b.y;
|
||||
result.z = a.z + b.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec4
|
||||
operator+(Vec4 a, Vec4 b){
|
||||
Vec4 result;
|
||||
result.x = a.x + b.x;
|
||||
result.y = a.y + b.y;
|
||||
result.z = a.z + b.z;
|
||||
result.w = a.w + b.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2
|
||||
operator-(Vec2 a, Vec2 b){
|
||||
Vec2 result;
|
||||
result.x = a.x - b.x;
|
||||
result.y = a.y - b.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
operator-(Vec3 a, Vec3 b){
|
||||
Vec3 result;
|
||||
result.x = a.x - b.x;
|
||||
result.y = a.y - b.y;
|
||||
result.z = a.z - b.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec4
|
||||
operator-(Vec4 a, Vec4 b){
|
||||
Vec4 result;
|
||||
result.x = a.x - b.x;
|
||||
result.y = a.y - b.y;
|
||||
result.z = a.z - b.z;
|
||||
result.w = a.w - b.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2
|
||||
operator*(Vec2 a, real32 k){
|
||||
Vec2 result;
|
||||
result.x = a.x * k;
|
||||
result.y = a.y * k;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
operator*(Vec3 a, real32 k){
|
||||
Vec3 result;
|
||||
result.x = a.x * k;
|
||||
result.y = a.y * k;
|
||||
result.z = a.z * k;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec4
|
||||
operator*(Vec4 a, real32 k){
|
||||
Vec4 result;
|
||||
result.x = a.x * k;
|
||||
result.y = a.y * k;
|
||||
result.z = a.z * k;
|
||||
result.w = a.w * k;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2
|
||||
operator*(real32 k, Vec2 a){
|
||||
Vec2 result;
|
||||
result.x = a.x * k;
|
||||
result.y = a.y * k;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
operator*(real32 k, Vec3 a){
|
||||
Vec3 result;
|
||||
result.x = a.x * k;
|
||||
result.y = a.y * k;
|
||||
result.z = a.z * k;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec4
|
||||
operator*(real32 k, Vec4 a){
|
||||
Vec4 result;
|
||||
result.x = a.x * k;
|
||||
result.y = a.y * k;
|
||||
result.z = a.z * k;
|
||||
result.w = a.w * k;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2&
|
||||
operator+=(Vec2 &a, Vec2 b){
|
||||
a = (a + b);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec3&
|
||||
operator+=(Vec3 &a, Vec3 b){
|
||||
a = (a + b);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec4&
|
||||
operator+=(Vec4 &a, Vec4 b){
|
||||
a = (a + b);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec2&
|
||||
operator-=(Vec2 &a, Vec2 b){
|
||||
a = (a - b);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec3&
|
||||
operator-=(Vec3 &a, Vec3 b){
|
||||
a = (a - b);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec4&
|
||||
operator-=(Vec4 &a, Vec4 b){
|
||||
a = (a - b);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec2&
|
||||
operator*=(Vec2 &a, real32 k){
|
||||
a = (a * k);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec3&
|
||||
operator*=(Vec3 &a, real32 k){
|
||||
a = (a * k);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal Vec4&
|
||||
operator*=(Vec4 &a, real32 k){
|
||||
a = (a * k);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline internal real32
|
||||
dot(Vec2 a, Vec2 b){
|
||||
real32 result;
|
||||
result = a.x*b.x + a.y*b.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal real32
|
||||
dot(Vec3 a, Vec3 b){
|
||||
real32 result;
|
||||
result = a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal real32
|
||||
dot(Vec4 a, Vec4 b){
|
||||
real32 result;
|
||||
result = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
cross(Vec3 a, Vec3 b){
|
||||
Vec3 result;
|
||||
result.x = a.y*b.z - b.y*a.z;
|
||||
result.y = a.z*b.x - b.z*a.x;
|
||||
result.z = a.x*b.y - b.x*a.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2
|
||||
hadamard(Vec2 a, Vec2 b){
|
||||
Vec2 result;
|
||||
result.x = a.x*b.x;
|
||||
result.y = a.y*b.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec3
|
||||
hadamard(Vec3 a, Vec3 b){
|
||||
Vec3 result;
|
||||
result.x = a.x*b.x;
|
||||
result.y = a.y*b.y;
|
||||
result.z = a.z*b.z;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec4
|
||||
hadamard(Vec4 a, Vec4 b){
|
||||
Vec4 result;
|
||||
result.x = a.x*b.x;
|
||||
result.y = a.y*b.y;
|
||||
result.z = a.z*b.z;
|
||||
result.w = a.w*b.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline internal Vec2
|
||||
perp(Vec2 v){
|
||||
Vec2 result;
|
||||
result.x = -v.y;
|
||||
result.y = v.x;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec2
|
||||
polar_to_cartesian(real32 theta_degrees, real32 length){
|
||||
Vec2 result;
|
||||
result.x = COS(theta_degrees)*length;
|
||||
result.y = SIN(theta_degrees)*length;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Vec2
|
||||
rotate(Vec2 v, real32 theta_degrees){
|
||||
Vec2 result;
|
||||
real32 c, s;
|
||||
c = COS(theta_degrees);
|
||||
s = SIN(theta_degrees);
|
||||
result.x = v.x*c - v.y*s;
|
||||
result.y = v.x*s + v.y*c;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Coordinates
|
||||
*/
|
||||
|
||||
struct Matrix2{
|
||||
Vec2 x_axis;
|
||||
Vec2 y_axis;
|
||||
};
|
||||
|
||||
internal Matrix2
|
||||
invert(Vec2 x_axis, Vec2 y_axis){
|
||||
Matrix2 result = {};
|
||||
real32 det = 1.f / (x_axis.x*y_axis.y - x_axis.y*y_axis.x);
|
||||
result.x_axis.x = y_axis.y*det;
|
||||
result.y_axis.x = -y_axis.x*det;
|
||||
result.x_axis.y = -x_axis.y*det;
|
||||
result.y_axis.y = x_axis.x*det;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Matrix2
|
||||
invert(Matrix2 m){
|
||||
Matrix2 result = {};
|
||||
real32 det = 1.f / (m.x_axis.x*m.y_axis.y - m.x_axis.y*m.y_axis.x);
|
||||
result.x_axis.x = m.y_axis.y*det;
|
||||
result.y_axis.x = -m.y_axis.x*det;
|
||||
result.x_axis.y = -m.x_axis.y*det;
|
||||
result.y_axis.y = m.x_axis.x*det;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lerps, Clamps, Thresholds, Etc
|
||||
*/
|
||||
|
||||
inline real32
|
||||
lerp(real32 a, real32 t, real32 b){
|
||||
return a + (b-a)*t;
|
||||
}
|
||||
|
||||
inline Vec2
|
||||
lerp(Vec2 a, real32 t, Vec2 b){
|
||||
return a + (b-a)*t;
|
||||
}
|
||||
|
||||
inline Vec3
|
||||
lerp(Vec3 a, real32 t, Vec3 b){
|
||||
return a + (b-a)*t;
|
||||
}
|
||||
|
||||
inline Vec4
|
||||
lerp(Vec4 a, real32 t, Vec4 b){
|
||||
return a + (b-a)*t;
|
||||
}
|
||||
|
||||
inline real32
|
||||
unlerp(real32 a, real32 x, real32 b){
|
||||
return (x - a) / (b - a);
|
||||
}
|
||||
|
||||
inline real32
|
||||
clamp(real32 a, real32 n, real32 z){
|
||||
return (n<a)?(a):((n>z)?(z):n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Color
|
||||
*/
|
||||
|
||||
// TODO(allen): Convert colors to Vec4
|
||||
inline internal u32
|
||||
color_blend(u32 a, real32 t, u32 b){
|
||||
union{
|
||||
u8 byte[4];
|
||||
u32 comp;
|
||||
} A, B, R;
|
||||
|
||||
A.comp = a;
|
||||
B.comp = b;
|
||||
|
||||
R.byte[0] = (u8)lerp(A.byte[0], t, B.byte[0]);
|
||||
R.byte[1] = (u8)lerp(A.byte[1], t, B.byte[1]);
|
||||
R.byte[2] = (u8)lerp(A.byte[2], t, B.byte[2]);
|
||||
R.byte[3] = (u8)lerp(A.byte[3], t, B.byte[3]);
|
||||
|
||||
return R.comp;
|
||||
}
|
||||
|
||||
internal Vec3
|
||||
unpack_color3(u32 color){
|
||||
Vec3 result;
|
||||
result.r = ((color >> 16) & 0xFF) / 255.f;
|
||||
result.g = ((color >> 8) & 0xFF) / 255.f;
|
||||
result.b = ((color >> 0) & 0xFF) / 255.f;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Vec4
|
||||
unpack_color4(u32 color){
|
||||
Vec4 result;
|
||||
result.a = ((color >> 24) & 0xFF) / 255.f;
|
||||
result.r = ((color >> 16) & 0xFF) / 255.f;
|
||||
result.g = ((color >> 8) & 0xFF) / 255.f;
|
||||
result.b = ((color >> 0) & 0xFF) / 255.f;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal u32
|
||||
pack_color4(Vec4 color){
|
||||
u32 result =
|
||||
((u8)(color.a * 255) << 24) |
|
||||
((u8)(color.r * 255) << 16) |
|
||||
((u8)(color.g * 255) << 8) |
|
||||
((u8)(color.b * 255) << 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Vec4
|
||||
rgba_to_hsla(Vec4 rgba){
|
||||
Vec4 hsla = {};
|
||||
real32 max, min, delta;
|
||||
i32 maxc;
|
||||
hsla.a = rgba.a;
|
||||
max = rgba.r; min = rgba.r;
|
||||
maxc = 0;
|
||||
if (rgba.r < rgba.g){
|
||||
max = rgba.g;
|
||||
maxc = 1;
|
||||
}
|
||||
if (rgba.b > max){
|
||||
max = rgba.b;
|
||||
maxc = 2;
|
||||
}
|
||||
if (rgba.r > rgba.g){
|
||||
min = rgba.g;
|
||||
}
|
||||
if (rgba.b < min){
|
||||
min = rgba.b;
|
||||
}
|
||||
delta = max - min;
|
||||
|
||||
hsla.z = (max + min) * .5f;
|
||||
if (delta == 0){
|
||||
hsla.x = 0.f;
|
||||
hsla.y = 0.f;
|
||||
}
|
||||
else{
|
||||
switch (maxc){
|
||||
case 0:
|
||||
{
|
||||
hsla.x = (rgba.g - rgba.b) / delta;
|
||||
hsla.x += (rgba.g < rgba.b) * 6.f;
|
||||
}break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
hsla.x = (rgba.b - rgba.r) / delta;
|
||||
hsla.x += 2.f;
|
||||
}break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
hsla.x = (rgba.r - rgba.g) / delta;
|
||||
hsla.x += 4.f;
|
||||
}break;
|
||||
}
|
||||
hsla.x *= (1/6.f); // * 60 / 360
|
||||
hsla.y = delta / (1.f - ABS(2.f*hsla.z - 1.f));
|
||||
}
|
||||
|
||||
return hsla;
|
||||
}
|
||||
|
||||
internal Vec4
|
||||
hsla_to_rgba(Vec4 hsla){
|
||||
if (hsla.h >= 1.f) hsla.h = 0.f;
|
||||
Vec4 rgba = {};
|
||||
real32 C, X, m;
|
||||
i32 H;
|
||||
rgba.a = hsla.a;
|
||||
C = (1.f - ABS(2*hsla.z - 1.f)) * hsla.y;
|
||||
X = C * (1.f-ABS(MOD(hsla.x*6.f, 2)-1.f));
|
||||
m = hsla.z - C*.5f;
|
||||
H = FLOOR32(hsla.x * 6.f);
|
||||
switch (H){
|
||||
case 0:
|
||||
rgba.r = C; rgba.g = X; rgba.b = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
rgba.r = X; rgba.g = C; rgba.b = 0;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rgba.r = 0; rgba.g = C; rgba.b = X;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
rgba.r = 0; rgba.g = X; rgba.b = C;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
rgba.r = X; rgba.g = 0; rgba.b = C;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
rgba.r = C; rgba.g = 0; rgba.b = X;
|
||||
break;
|
||||
}
|
||||
rgba.r += m;
|
||||
rgba.g += m;
|
||||
rgba.b += m;
|
||||
return rgba;
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 26.09.2015
|
||||
*
|
||||
* File editing view for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
struct Menu_View{
|
||||
View view_base;
|
||||
Style *style;
|
||||
Working_Set *working_set;
|
||||
Delay *delay;
|
||||
UI_State state;
|
||||
};
|
||||
|
||||
inline Menu_View*
|
||||
view_to_menu_view(View *view){
|
||||
Menu_View *result = 0;
|
||||
if (view->type == VIEW_TYPE_MENU){
|
||||
result = (Menu_View*)view;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal i32
|
||||
step_draw_menu_view(Menu_View *view, Render_Target *target, i32_Rect rect,
|
||||
Input_Summary *user_input, bool32 input_stage){
|
||||
i32 result = 0;
|
||||
|
||||
UI_State state =
|
||||
ui_state_init(&view->state, target, user_input,
|
||||
view->style, view->working_set, input_stage);
|
||||
|
||||
UI_Layout layout;
|
||||
begin_layout(&layout, rect);
|
||||
|
||||
i32 id = 0;
|
||||
|
||||
do_label(&state, &layout, "Menu", 2.f);
|
||||
|
||||
if (do_list_option_lit(++id, &state, &layout, "Theme Options")){
|
||||
delayed_action(view->delay, DACT_THEME_OPTIONS, {}, view->view_base.panel);
|
||||
}
|
||||
|
||||
if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DO_VIEW_SIG(do_menu_view){
|
||||
i32 result = 0;
|
||||
|
||||
Menu_View *menu_view = (Menu_View*)view;
|
||||
switch (message){
|
||||
case VMSG_STEP: case VMSG_DRAW:
|
||||
result = step_draw_menu_view(menu_view, target, rect, user_input, (message == VMSG_STEP));
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Menu_View*
|
||||
menu_view_init(View *view, Style *style, Working_Set *working_set, Delay *delay){
|
||||
view->type = VIEW_TYPE_INTERACTIVE;
|
||||
view->do_view = do_menu_view;
|
||||
|
||||
Menu_View *result;
|
||||
result = (Menu_View*)view;
|
||||
result->style = style;
|
||||
result->working_set = working_set;
|
||||
result->delay = delay;
|
||||
return result;
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 12.12.2014
|
||||
*
|
||||
* Meta setup for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FRED_META_H
|
||||
#define FRED_META_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
|
||||
typedef int8_t i8;
|
||||
typedef int64_t i64;
|
||||
typedef int32_t i32;
|
||||
typedef int16_t i16;
|
||||
|
||||
typedef i32 bool32;
|
||||
typedef i8 bool8;
|
||||
|
||||
typedef float real32;
|
||||
typedef double real64;
|
||||
|
||||
#define internal static
|
||||
#define globalvar static
|
||||
#define persist static
|
||||
|
||||
#define globalconst static const
|
||||
|
||||
inline i32
|
||||
raw_ptr_dif(void *a, void *b) { return (i32)((u8*)a - (u8*)b); }
|
||||
|
||||
#define COMP_ID_(a,b,c,d) (d << 24) | (c << 16) | (b << 8) | a
|
||||
#define COMPOSE_ID(a,b,c,d) (COMP_ID_((a),(b),(c),(d)))
|
||||
|
||||
#define S(X) #X
|
||||
#define S_(X) S(X)
|
||||
#define S__LINE__ S_(__LINE__)
|
||||
|
||||
#if FRED_PRINT_DEBUG == 1
|
||||
internal void
|
||||
_OutDbgStr(u8*);
|
||||
# include <stdio.h>
|
||||
# if FRED_PRINT_DEBUG_FILE_LINE
|
||||
# define FredDbg(con, size, ...) {_OutDbgStr((u8*)("FILE:"__FILE__"LINE:"S__LINE__"\n")); char msg[size]; sprintf(msg, __VA_ARGS__); _OutDbgStr((u8*)msg);}
|
||||
# else
|
||||
# define FredDbg(con, size, ...) {char msg[size]; sprintf(msg, __VA_ARGS__); _OutDbgStr((u8*)msg);}
|
||||
# endif
|
||||
#elif FRED_PRINT_DEBUG == 2
|
||||
# include <stdio.h>
|
||||
# if FRED_PRINT_DEBUG_FILE_LINE
|
||||
# define FredDbg(con, size, ...) {fprintf((con)->log, ("FILE:"__FILE__"LINE:"S__LINE__"\n")); fprintf(__VA_ARGS__);}
|
||||
# else
|
||||
# define FredDbg(con, size, ...) {fprintf((con)->log, __VA_ARGS__);}
|
||||
# endif
|
||||
#else
|
||||
# define FredDbg(con, size, ...)
|
||||
#endif
|
||||
|
||||
#if FRED_INTERNAL && FRED_FULL_ERRORS
|
||||
# include <stdio.h>
|
||||
# define FatalErrorFormat(alt, size, ...) {char msg[size]; sprintf(msg, __VA_ARGS__); FatalError(msg);}
|
||||
#else
|
||||
# define FatalErrorFormat(alt, size, ...) {FatalError(alt);}
|
||||
#endif
|
||||
|
||||
#if FRED_SLOW
|
||||
# define Assert(c) if(!(c)){*(int*)0 = 0;}
|
||||
#else
|
||||
# define Assert(c)
|
||||
#endif
|
||||
|
||||
#define TentativeAssert(c) Assert(c)
|
||||
|
||||
#define FatalError(message) system_fatal_error((u8*)message)
|
||||
|
||||
#define AllowLocal(name) (void)name
|
||||
#define ArrayCount(array) (sizeof(array)/sizeof(array[0]))
|
||||
|
||||
#define Swap(a,b) {auto t = a; a = b; b = t;}
|
||||
|
||||
#define Min(a,b) (((a)<(b))?(a):(b))
|
||||
#define Max(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
#define TMax(t,v) globalconst t max_##t = v
|
||||
TMax(u8, 255);
|
||||
TMax(u16, 65535);
|
||||
TMax(u32, 4294967295);
|
||||
TMax(u64, 18446744073709551615);
|
||||
|
||||
TMax(i8, 127);
|
||||
TMax(i16, 32767);
|
||||
TMax(i32, 2147483647);
|
||||
TMax(i64, 9223372036854775807);
|
||||
#undef TMax
|
||||
|
||||
#define TMin(t) globalconst t min_##t = 0
|
||||
TMin(u8);
|
||||
TMin(u16);
|
||||
TMin(u32);
|
||||
TMin(u64);
|
||||
#undef TMin
|
||||
|
||||
#define TMin(t,v) globalconst t min_##t = ((t)v)
|
||||
TMin(i8, -0xF0);
|
||||
TMin(i16, -0xF000);
|
||||
TMin(i32, -0xF00000);
|
||||
TMin(i64, -0xF0000000LL);
|
||||
#undef TMin
|
||||
|
||||
internal i32
|
||||
LargeRoundUp(i32 x, i32 granularity){
|
||||
i32 original_x = x;
|
||||
x /= granularity;
|
||||
x *= granularity;
|
||||
if (x < original_x){
|
||||
x += granularity;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#define Bit_0 (1 << 0)
|
||||
#define Bit_1 (1 << 1)
|
||||
#define Bit_2 (1 << 2)
|
||||
#define Bit_3 (1 << 3)
|
||||
#define Bit_4 (1 << 4)
|
||||
#define Bit_5 (1 << 5)
|
||||
#define Bit_6 (1 << 6)
|
||||
#define Bit_7 (1 << 7)
|
||||
|
||||
#define Bit_8 (1 << 8)
|
||||
#define Bit_9 (1 << 9)
|
||||
#define Bit_10 (1 << 10)
|
||||
#define Bit_11 (1 << 11)
|
||||
#define Bit_12 (1 << 12)
|
||||
#define Bit_13 (1 << 13)
|
||||
#define Bit_14 (1 << 14)
|
||||
#define Bit_15 (1 << 15)
|
||||
|
||||
#define Bit_16 (1 << 16)
|
||||
#define Bit_17 (1 << 17)
|
||||
#define Bit_18 (1 << 18)
|
||||
#define Bit_19 (1 << 19)
|
||||
#define Bit_20 (1 << 20)
|
||||
#define Bit_21 (1 << 21)
|
||||
#define Bit_22 (1 << 22)
|
||||
#define Bit_23 (1 << 23)
|
||||
|
||||
#define Bit_24 (1 << 24)
|
||||
#define Bit_25 (1 << 25)
|
||||
#define Bit_26 (1 << 26)
|
||||
#define Bit_27 (1 << 27)
|
||||
#define Bit_28 (1 << 28)
|
||||
#define Bit_29 (1 << 29)
|
||||
#define Bit_30 (1 << 30)
|
||||
#define Bit_31 (1 << 31)
|
||||
|
||||
#define Byte_0 (0xFFU)
|
||||
#define Byte_1 (0xFFU << 8)
|
||||
#define Byte_2 (0xFFU << 16)
|
||||
#define Byte_3 (0xFFU << 24)
|
||||
#define Byte_4 (0xFFU << 32)
|
||||
#define Byte_5 (0xFFU << 40)
|
||||
#define Byte_6 (0xFFU << 48)
|
||||
#define Byte_7 (0xFFU << 56)
|
||||
|
||||
#define bytes(n) (n)
|
||||
#define Kbytes(n) (bytes(n) * 1024)
|
||||
#define Mbytes(n) (Kbytes(n) * 1024)
|
||||
#define Gbytes(n) (Mbytes((u64)n) * 1024)
|
||||
#define Tbytes(n) (Gbytes((u64)n) * 1024)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,898 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 12.17.2014
|
||||
*
|
||||
* Rendering layer for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
internal i32_Rect
|
||||
rect_clamp_to_rect(i32_Rect rect, i32_Rect clamp_box){
|
||||
if (rect.x0 < clamp_box.x0) rect.x0 = clamp_box.x0;
|
||||
if (rect.y0 < clamp_box.y0) rect.y0 = clamp_box.y0;
|
||||
if (rect.x1 > clamp_box.x1) rect.x1 = clamp_box.x1;
|
||||
if (rect.y1 > clamp_box.y1) rect.y1 = clamp_box.y1;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
rect_clamp_to_rect(i32 left, i32 top, i32 right, i32 bottom, i32_Rect clamp_box){
|
||||
return rect_clamp_to_rect(i32R(left, top, right, bottom), clamp_box);
|
||||
}
|
||||
|
||||
inline i32_Rect
|
||||
rect_from_target(Render_Target *target){
|
||||
return i32R(0, 0, target->width, target->height);
|
||||
}
|
||||
|
||||
#if SOFTWARE_RENDER
|
||||
internal void
|
||||
draw_clear(Render_Target *target, u32 color){
|
||||
u8 *pixel_line = (u8*)target->pixel_data;
|
||||
for (i32 pixel_y = 0; pixel_y < target->height; ++pixel_y){
|
||||
u32 *pixel = (u32*)pixel_line;
|
||||
for (i32 pixel_x = 0; pixel_x < target->width; ++pixel_x){
|
||||
*pixel++ = color;
|
||||
}
|
||||
pixel_line += target->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_vertical_line(Render_Target *target,
|
||||
i32 x, i32 top, i32 bottom,
|
||||
u32 color){
|
||||
if (x >= 0 && x < target->width){
|
||||
if (top < 0){
|
||||
top = 0;
|
||||
}
|
||||
if (bottom >= target->height){
|
||||
bottom = target->height - 1;
|
||||
}
|
||||
|
||||
if (top <= bottom){
|
||||
i32 y_range = bottom - top;
|
||||
u8 *pixel_line = (u8*)target->pixel_data + top*target->pitch;
|
||||
for (i32 pixel_y = 0; pixel_y <= y_range; ++pixel_y){
|
||||
u32 *pixel = (u32*)pixel_line + x;
|
||||
*pixel = color;
|
||||
pixel_line += target->pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_horizontal_line(Render_Target *target,
|
||||
i32 y, i32 left, i32 right,
|
||||
u32 color){
|
||||
if (y >= 0 && y < target->height){
|
||||
if (left < 0){
|
||||
left = 0;
|
||||
}
|
||||
if (right >= target->width){
|
||||
right = target->width - 1;
|
||||
}
|
||||
|
||||
if (left <= right){
|
||||
i32 x_range = right - left;
|
||||
u8 *pixel_line = (u8*)target->pixel_data + y*target->pitch;
|
||||
u32 *pixel = (u32*)pixel_line + left;
|
||||
for (i32 pixel_x = 0; pixel_x <= x_range; ++pixel_x){
|
||||
*pixel = color;
|
||||
++pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle_blend_2corner_unclamped(Render_Target *target,
|
||||
Blit_Rect rect, u32 color){
|
||||
if (rect.x_start < rect.x_end && rect.y_start < rect.y_end){
|
||||
i32 y_range = rect.y_end - rect.y_start;
|
||||
i32 x_range = rect.x_end - rect.x_start;
|
||||
|
||||
u8 a,r,g,b;
|
||||
a = (u8)(color >> 24);
|
||||
r = (u8)(color >> 16);
|
||||
g = (u8)(color >> 8);
|
||||
b = (u8)(color >> 0);
|
||||
|
||||
real32 blend = (a/255.f);
|
||||
real32 pr, pg, pb;
|
||||
pr = r*blend;
|
||||
pg = g*blend;
|
||||
pb = b*blend;
|
||||
|
||||
real32 inv_blend = 1.f - blend;
|
||||
|
||||
u8 *pixel_line = (u8*)target->pixel_data + rect.y_start*target->pitch;
|
||||
for (i32 pixel_y = 0; pixel_y < y_range; ++pixel_y){
|
||||
u32 *pixel = (u32*)pixel_line + rect.x_start;
|
||||
for (i32 pixel_x = 0; pixel_x < x_range; ++pixel_x){
|
||||
u8 dr,dg,db;
|
||||
dr = (u8)(*pixel >> 16);
|
||||
dg = (u8)(*pixel >> 8);
|
||||
db = (u8)(*pixel >> 0);
|
||||
|
||||
dr = (u8)(dr*inv_blend + pr);
|
||||
dg = (u8)(dg*inv_blend + pg);
|
||||
db = (u8)(db*inv_blend + pb);
|
||||
|
||||
*pixel = (dr << 16) | (dg << 8) | (db);
|
||||
++pixel;
|
||||
}
|
||||
pixel_line += target->pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle_noblend_2corner_unclamped(Render_Target *target,
|
||||
Blit_Rect rect, u32 color){
|
||||
if (rect.x_start < rect.x_end && rect.y_start < rect.y_end){
|
||||
i32 y_range = rect.y_end - rect.y_start;
|
||||
i32 x_range = rect.x_end - rect.x_start;
|
||||
|
||||
u8 *pixel_line = (u8*)target->pixel_data + rect.y_start*target->pitch;
|
||||
for (i32 pixel_y = 0; pixel_y < y_range; ++pixel_y){
|
||||
u32 *pixel = (u32*)pixel_line + rect.x_start;
|
||||
for (i32 pixel_x = 0; pixel_x < x_range; ++pixel_x){
|
||||
*pixel++ = color;
|
||||
}
|
||||
pixel_line += target->pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen): uses of this can be replaced with draw_rectangle_2corner_unclamped
|
||||
// if it is guaranteed that clip_box will be within the target area.
|
||||
inline void
|
||||
draw_rectangle_2corner_clipped(Render_Target *target,
|
||||
i32 left, i32 top, i32 right, i32 bottom,
|
||||
u32 color, Blit_Rect clip_box){
|
||||
clip_box = rect_clamp_to_rect(clip_box, rect_from_target(target));
|
||||
Blit_Rect rect = rect_clamp_to_rect(left, top, right, bottom, clip_box);
|
||||
draw_rectangle_noblend_2corner_unclamped(target, rect, color);
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_rectangle_2corner(Render_Target *target,
|
||||
i32 left, i32 top, i32 right, i32 bottom,
|
||||
u32 color){
|
||||
Blit_Rect rect = rect_clamp_to_rect(left, top, right, bottom, rect_from_target(target));
|
||||
draw_rectangle_noblend_2corner_unclamped(target, rect, color);
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_rectangle_clipped(Render_Target *target,
|
||||
i32 x, i32 y, i32 w, i32 h,
|
||||
u32 color, Blit_Rect clip_box){
|
||||
draw_rectangle_2corner_clipped(target, x, y, x+w, y+h, color, clip_box);
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_rectangle(Render_Target *target,
|
||||
i32 x, i32 y, i32 w, i32 h,
|
||||
u32 color){
|
||||
draw_rectangle_2corner(target, x, y, x+w, y+h, color);
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle_outline_unclamped(Render_Target *target,
|
||||
i32 x, i32 y, i32 w, i32 h,
|
||||
u32 color, Blit_Rect rect){
|
||||
if (rect.x_start <= rect.x_end && rect.y_start <= rect.y_end){
|
||||
if (rect.y_start == y){
|
||||
draw_horizontal_line(target,
|
||||
rect.y_start, rect.x_start, rect.x_end-1,
|
||||
color);
|
||||
}
|
||||
|
||||
if (rect.y_end == y+h){
|
||||
draw_horizontal_line(target,
|
||||
rect.y_end-1, rect.x_start, rect.x_end-1,
|
||||
color);
|
||||
}
|
||||
|
||||
if (rect.x_start == x){
|
||||
draw_vertical_line(target,
|
||||
rect.x_start, rect.y_start, rect.y_end-1,
|
||||
color);
|
||||
}
|
||||
|
||||
if (rect.x_end == x+w){
|
||||
draw_vertical_line(target,
|
||||
rect.x_end-1, rect.y_start, rect.y_end-1,
|
||||
color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle_outline_clipped(Render_Target *target,
|
||||
i32 x, i32 y, i32 w, i32 h,
|
||||
u32 color, Blit_Rect clip_box){
|
||||
clip_box = rect_clamp_to_rect(clip_box, rect_from_target(target));
|
||||
Blit_Rect rect = rect_clamp_to_rect(x, y, x+w, y+h, clip_box);
|
||||
draw_rectangle_outline_unclamped(target, x, y, w, h, color, rect);
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle_outline(Render_Target *target,
|
||||
i32 x, i32 y, i32 w, i32 h,
|
||||
u32 color){
|
||||
Blit_Rect rect = rect_clamp_to_rect(x, y, x+w, y+h, rect_from_target(target));
|
||||
draw_rectangle_outline_unclamped(target, x, y, w, h, color, rect);
|
||||
}
|
||||
|
||||
// TODO(allen): eliminate this?
|
||||
internal i32
|
||||
font_init(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline internal i32
|
||||
font_predict_size(i32 pt_size){
|
||||
return pt_size*pt_size*128;
|
||||
}
|
||||
|
||||
internal i32
|
||||
font_load(Font *font_out, i32 pt_size,
|
||||
void *font_block, i32 font_block_size,
|
||||
i32 *memory_used_out){
|
||||
i32 result = 1;
|
||||
File_Data file;
|
||||
file = system_load_file((u8*)"liberation-mono.ttf");
|
||||
|
||||
if (!file.data){
|
||||
result = 0;
|
||||
}
|
||||
|
||||
else{
|
||||
stbtt_fontinfo font;
|
||||
if (!stbtt_InitFont(&font, (u8*)file.data, 0)){
|
||||
result = 0;
|
||||
}
|
||||
else{
|
||||
i32 ascent, descent, line_gap;
|
||||
real32 scale;
|
||||
|
||||
stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap);
|
||||
scale = stbtt_ScaleForPixelHeight(&font, (real32)pt_size);
|
||||
|
||||
real32 scaled_ascent, scaled_descent, scaled_line_gap;
|
||||
|
||||
scaled_ascent = scale*ascent;
|
||||
scaled_descent = scale*descent;
|
||||
scaled_line_gap = scale*line_gap;
|
||||
|
||||
font_out->height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap);
|
||||
font_out->ascent = (i32)(scaled_ascent);
|
||||
font_out->descent = (i32)(scaled_descent);
|
||||
font_out->line_skip = (i32)(scaled_line_gap);
|
||||
|
||||
i32 max_advance = 0;
|
||||
|
||||
bool32 block_full = 0, block_overfull = 0;
|
||||
u8 *memory_cursor = (u8*)font_block;
|
||||
for (u16 code_point = 0; code_point < 128; ++code_point){
|
||||
i32 glyph_index;
|
||||
|
||||
if (block_full){
|
||||
block_overfull = 1;
|
||||
font_out->glyphs[code_point] = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
else{
|
||||
glyph_index = stbtt_FindGlyphIndex(&font, code_point);
|
||||
if (glyph_index != 0){
|
||||
font_out->glyphs[code_point].exists = 1;
|
||||
|
||||
i32 left, right, top, bottom;
|
||||
stbtt_GetGlyphBitmapBox(&font, glyph_index, scale, scale, &left, &top, &right, &bottom);
|
||||
|
||||
i32 glyph_width, glyph_height;
|
||||
i32 data_width, data_height;
|
||||
glyph_width = right - left;
|
||||
glyph_height = bottom - top;
|
||||
data_width = glyph_width + 2;
|
||||
data_height = glyph_height + 2;
|
||||
|
||||
font_out->glyphs[code_point].minx = left;
|
||||
font_out->glyphs[code_point].maxx = right;
|
||||
font_out->glyphs[code_point].miny = top;
|
||||
font_out->glyphs[code_point].maxy = bottom;
|
||||
font_out->glyphs[code_point].width = data_width;
|
||||
font_out->glyphs[code_point].height = data_height;
|
||||
|
||||
i32 advance, left_bearing;
|
||||
stbtt_GetGlyphHMetrics(&font, glyph_index, &advance, &left_bearing);
|
||||
|
||||
font_out->glyphs[code_point].left_shift = (i32)(scale*left_bearing);
|
||||
|
||||
if (advance > max_advance){
|
||||
max_advance = advance;
|
||||
}
|
||||
|
||||
u8 *data = memory_cursor;
|
||||
memory_cursor = memory_cursor + data_width*data_height;
|
||||
|
||||
i32 size_after_glyph = (i32)((u8*)memory_cursor - (u8*)font_block);
|
||||
if (size_after_glyph >= font_block_size){
|
||||
block_full = 1;
|
||||
if (size_after_glyph > font_block_size){
|
||||
block_overfull = 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
font_out->glyphs[code_point].data = data;
|
||||
u8 *data_start = data + data_width + 1;
|
||||
stbtt_MakeGlyphBitmap(&font, data_start,
|
||||
glyph_width, glyph_height, data_width,
|
||||
scale, scale,
|
||||
glyph_index);
|
||||
}
|
||||
}
|
||||
else{
|
||||
font_out->glyphs[code_point] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font_out->advance = Ceil(max_advance*scale);
|
||||
}
|
||||
system_free_file(file);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
font_draw_glyph_subpixel(Render_Target *target,
|
||||
Font *font, u16 character,
|
||||
real32 x, real32 y, u32 color,
|
||||
Blit_Rect clip){
|
||||
if (clip.x_start <= clip.x_end && clip.y_start <= clip.y_end){
|
||||
Glyph_Data glyph = font->glyphs[character];
|
||||
|
||||
Vec2 s_origin = V2(x - 1.f, y - 1.f);
|
||||
|
||||
i32 left_most = (i32)(x);
|
||||
i32 top_most = (i32)(y);
|
||||
|
||||
real32 xe = x + glyph.width - 2;
|
||||
real32 ye = y + glyph.height - 2;
|
||||
i32 right_most = (i32)(xe)+(xe>0)*((i32)xe != xe);
|
||||
i32 bottom_most = (i32)(ye)+(ye>0)*((i32)ye != ye);
|
||||
|
||||
if (left_most < clip.x_start){
|
||||
left_most = clip.x_start;
|
||||
}
|
||||
|
||||
if (top_most < clip.y_start){
|
||||
top_most = clip.y_start;
|
||||
}
|
||||
|
||||
if (right_most >= clip.x_end){
|
||||
right_most = clip.x_end - 1;
|
||||
}
|
||||
|
||||
if (bottom_most >= clip.y_end){
|
||||
bottom_most = clip.y_end - 1;
|
||||
}
|
||||
|
||||
u8 *dest_data = (u8*)target->pixel_data;
|
||||
u8 *src_data = (u8*)glyph.data;
|
||||
|
||||
i32 width = glyph.width;
|
||||
i32 target_pitch = target->pitch;
|
||||
|
||||
real32 inv_255 = 1.f / 255.f;
|
||||
|
||||
real32 cr,cg,cb,ca;
|
||||
cb = (real32)((color) & 0xFF);
|
||||
cg = (real32)((color >> 8) & 0xFF);
|
||||
cr = (real32)((color >> 16) & 0xFF);
|
||||
ca = (real32)((color >> 24) & 0xFF);
|
||||
|
||||
i32 lox_start = (i32)(left_most - s_origin.x);
|
||||
i32 loy_start = (i32)(top_most - s_origin.y);
|
||||
|
||||
real32 lX = left_most - s_origin.x - lox_start;
|
||||
real32 lY = top_most - s_origin.y - loy_start;
|
||||
|
||||
real32 inv_lX = 1.f - lX;
|
||||
real32 inv_lY = 1.f - lY;
|
||||
|
||||
i32 loy = loy_start * width;
|
||||
|
||||
u8 *dest_line = (dest_data + top_most*target_pitch);
|
||||
for (i32 y = top_most; y <= bottom_most; ++y){
|
||||
u8 src_a[4];
|
||||
|
||||
i32 lox_loy = lox_start + loy;
|
||||
src_a[0] = *(src_data + (lox_loy));
|
||||
src_a[2] = *(src_data + (lox_loy + width));
|
||||
|
||||
u32 *dest_pixel = (u32*)(dest_line) + left_most;
|
||||
|
||||
for (i32 x = left_most; x <= right_most; ++x){
|
||||
src_a[1] = *(src_data + (lox_loy + 1));
|
||||
src_a[3] = *(src_data + (lox_loy + 1 + width));
|
||||
|
||||
real32 alpha = (src_a[0]*(inv_lX) + src_a[1]*(lX))*(inv_lY) +
|
||||
(src_a[2]*(inv_lX) + src_a[3]*(lX))*(lY);
|
||||
alpha *= inv_255;
|
||||
|
||||
u32 dp = *dest_pixel;
|
||||
|
||||
real32 dr,dg,db,da;
|
||||
db = (real32)((dp) & 0xFF);
|
||||
dg = (real32)((dp >> 8) & 0xFF);
|
||||
dr = (real32)((dp >> 16) & 0xFF);
|
||||
da = (real32)((dp >> 24) & 0xFF);
|
||||
|
||||
db = db + (cb - db)*alpha;
|
||||
dg = dg + (cg - dg)*alpha;
|
||||
dr = dr + (cr - dr)*alpha;
|
||||
da = da + (ca - da)*alpha;
|
||||
|
||||
*dest_pixel = ((u8)db) | (((u8)dg) << 8) | (((u8)dr) << 16) | (((u8)da) << 24);
|
||||
|
||||
++dest_pixel;
|
||||
++lox_loy;
|
||||
|
||||
src_a[0] = src_a[1];
|
||||
src_a[2] = src_a[3];
|
||||
}
|
||||
loy += width;
|
||||
dest_line += target_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
font_draw_glyph(Render_Target *target, Font *font, u16 character,
|
||||
real32 x, real32 y, u32 color){
|
||||
Glyph_Data glyph = font->glyphs[character];
|
||||
|
||||
i32 left = glyph.minx;
|
||||
i32 right = glyph.maxx;
|
||||
i32 width = right - left;
|
||||
|
||||
real32 x_shift, y_shift;
|
||||
x_shift = glyph.left_shift + (real32)width / font->advance;
|
||||
y_shift = (real32)font->ascent + glyph.miny;
|
||||
|
||||
x += x_shift;
|
||||
y += y_shift;
|
||||
|
||||
i32 xi, yi;
|
||||
xi = (i32)(x);
|
||||
yi = (i32)(y);
|
||||
|
||||
Blit_Rect rect = rect_clamp_to_rect(xi, yi, xi+glyph.width-1, yi+glyph.height-1, rect_from_target(target));
|
||||
font_draw_glyph_subpixel(target, font, character, x, y, color, rect);
|
||||
}
|
||||
|
||||
internal void
|
||||
font_draw_glyph_clipped(Render_Target *target,
|
||||
Font *font, u16 character,
|
||||
real32 x, real32 y, u32 color,
|
||||
Blit_Rect clip_box){
|
||||
Glyph_Data glyph = font->glyphs[character];
|
||||
|
||||
i32 left = glyph.minx;
|
||||
i32 right = glyph.maxx;
|
||||
i32 width = right - left;
|
||||
|
||||
real32 x_shift, y_shift;
|
||||
x_shift = glyph.left_shift + (real32)width / font->advance;
|
||||
y_shift = (real32)font->ascent + glyph.miny;
|
||||
|
||||
x += x_shift;
|
||||
y += y_shift;
|
||||
|
||||
i32 xi, yi;
|
||||
xi = (i32)(x);
|
||||
yi = (i32)(y);
|
||||
|
||||
clip_box = rect_clamp_to_rect(clip_box, rect_from_target(target));
|
||||
Blit_Rect rect = rect_clamp_to_rect(xi, yi, xi+glyph.width-1, yi+glyph.height-1, clip_box);
|
||||
font_draw_glyph_subpixel(target, font, character, x, y, color, rect);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void
|
||||
draw_set_clip(Render_Target *target, i32_Rect clip_box){
|
||||
glScissor(clip_box.x0,
|
||||
target->height - clip_box.y1,
|
||||
clip_box.x1 - clip_box.x0,
|
||||
clip_box.y1 - clip_box.y0);
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_push_clip(Render_Target *target, i32_Rect clip_box){
|
||||
Assert(target->clip_top == -1 ||
|
||||
fits_inside(clip_box, target->clip_boxes[target->clip_top]));
|
||||
Assert(target->clip_top+1 < ArrayCount(target->clip_boxes));
|
||||
target->clip_boxes[++target->clip_top] = clip_box;
|
||||
draw_set_clip(target, clip_box);
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_pop_clip(Render_Target *target){
|
||||
Assert(target->clip_top > 0);
|
||||
--target->clip_top;
|
||||
draw_set_clip(target, target->clip_boxes[target->clip_top]);
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_bind_texture(Render_Target *target, i32 texid){
|
||||
if (target->bound_texture != texid){
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
target->bound_texture = texid;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_set_color(Render_Target *target, u32 color){
|
||||
if (target->color != color){
|
||||
target->color = color;
|
||||
Vec4 c = unpack_color4(color);
|
||||
glColor4f(c.r, c.g, c.b, c.a);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle(Render_Target *target, i32_Rect rect, u32 color){
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, 0);
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glVertex2i(rect.x0, rect.y0);
|
||||
glVertex2i(rect.x0, rect.y1);
|
||||
glVertex2i(rect.x1, rect.y1);
|
||||
glVertex2i(rect.x1, rect.y0);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle(Render_Target *target, real32_Rect rect, u32 color){
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, 0);
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glVertex2f(rect.x0, rect.y0);
|
||||
glVertex2f(rect.x0, rect.y1);
|
||||
glVertex2f(rect.x1, rect.y1);
|
||||
glVertex2f(rect.x1, rect.y0);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_triangle_3corner(Render_Target *target,
|
||||
real32 x0, real32 y0,
|
||||
real32 x1, real32 y1,
|
||||
real32 x2, real32 y2,
|
||||
u32 color){
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, 0);
|
||||
glBegin(GL_TRIANGLES);
|
||||
{
|
||||
glVertex2f(x0, y0);
|
||||
glVertex2f(x1, y1);
|
||||
glVertex2f(x2, y2);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_gradient_2corner_clipped(Render_Target *target, real32_Rect rect,
|
||||
Vec4 color_left, Vec4 color_right){
|
||||
Vec4 cl = color_left;
|
||||
Vec4 cr = color_right;
|
||||
|
||||
draw_bind_texture(target, 0);
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glColor4f(cl.r, cl.g, cl.b, cl.a);
|
||||
glVertex2f(rect.x0, rect.y0);
|
||||
glVertex2f(rect.x0, rect.y1);
|
||||
|
||||
glColor4f(cr.r, cr.g, cr.b, cr.a);
|
||||
glVertex2f(rect.x1, rect.y1);
|
||||
glVertex2f(rect.x1, rect.y0);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_gradient_2corner_clipped(Render_Target *target, real32 l, real32 t, real32 r, real32 b,
|
||||
Vec4 color_left, Vec4 color_right){
|
||||
draw_gradient_2corner_clipped(target, real32R(l,t,r,b), color_left, color_right);
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_rectangle_outline(Render_Target *target, real32_Rect rect, u32 color){
|
||||
real32_Rect r;
|
||||
r.x0 = rect.x0 + .5f;
|
||||
r.y0 = rect.y0 + .5f;
|
||||
r.x1 = rect.x1 - .5f;
|
||||
r.y1 = rect.y1 - .5f;
|
||||
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, 0);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
{
|
||||
glVertex2f(r.x0, r.y0);
|
||||
glVertex2f(r.x1, r.y0);
|
||||
glVertex2f(r.x1, r.y1);
|
||||
glVertex2f(r.x0, r.y1);
|
||||
glVertex2f(r.x0, r.y0);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
inline void
|
||||
draw_rectangle_outline(Render_Target *target, i32_Rect rect, u32 color){
|
||||
draw_rectangle_outline(target, real32R(rect), color);
|
||||
}
|
||||
|
||||
internal void
|
||||
draw_margin(Render_Target *target, i32_Rect outer, i32_Rect inner, u32 color){
|
||||
draw_rectangle(target, i32R(outer.x0, outer.y0, outer.x1, inner.y0), color);
|
||||
draw_rectangle(target, i32R(outer.x0, inner.y1, outer.x1, outer.y1), color);
|
||||
draw_rectangle(target, i32R(outer.x0, inner.y0, inner.x0, inner.y1), color);
|
||||
draw_rectangle(target, i32R(inner.x1, inner.y0, outer.x1, inner.y1), color);
|
||||
}
|
||||
|
||||
// TODO(allen): eliminate this?
|
||||
internal i32
|
||||
font_init(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline internal i32
|
||||
font_predict_size(i32 pt_size){
|
||||
return pt_size*pt_size*128;
|
||||
}
|
||||
|
||||
internal i32
|
||||
font_load(Font *font_out, char *filename, i32 pt_size,
|
||||
void *font_block, i32 font_block_size,
|
||||
i32 *memory_used_out, i32 tab_width){
|
||||
i32 result = 1;
|
||||
File_Data file;
|
||||
file = system_load_file((u8*)filename);
|
||||
|
||||
if (!file.data){
|
||||
result = 0;
|
||||
}
|
||||
|
||||
else{
|
||||
stbtt_fontinfo font;
|
||||
if (!stbtt_InitFont(&font, (u8*)file.data, 0)){
|
||||
result = 0;
|
||||
}
|
||||
else{
|
||||
i32 ascent, descent, line_gap;
|
||||
real32 scale;
|
||||
|
||||
stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap);
|
||||
scale = stbtt_ScaleForPixelHeight(&font, (real32)pt_size);
|
||||
|
||||
real32 scaled_ascent, scaled_descent, scaled_line_gap;
|
||||
|
||||
scaled_ascent = scale*ascent;
|
||||
scaled_descent = scale*descent;
|
||||
scaled_line_gap = scale*line_gap;
|
||||
|
||||
font_out->height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap);
|
||||
font_out->ascent = (i32)(scaled_ascent);
|
||||
font_out->descent = (i32)(scaled_descent);
|
||||
font_out->line_skip = (i32)(scaled_line_gap);
|
||||
|
||||
u8 *memory_cursor = (u8*)font_block;
|
||||
Assert(pt_size*pt_size*128 <= font_block_size);
|
||||
|
||||
i32 tex_width, tex_height;
|
||||
tex_width = pt_size*128;
|
||||
tex_height = pt_size*2;
|
||||
|
||||
font_out->tex_width = tex_width;
|
||||
font_out->tex_height = tex_height;
|
||||
|
||||
if (stbtt_BakeFontBitmap((u8*)file.data, 0, (real32)pt_size,
|
||||
memory_cursor, tex_width, tex_height, 0, 128, font_out->chardata) <= 0){
|
||||
result = 0;
|
||||
}
|
||||
|
||||
else{
|
||||
GLuint font_tex;
|
||||
glGenTextures(1, &font_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, font_tex);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, memory_cursor);
|
||||
|
||||
font_out->tex = font_tex;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
font_out->chardata['\r'] = font_out->chardata[' '];
|
||||
font_out->chardata['\n'] = font_out->chardata[' '];
|
||||
font_out->chardata['\t'] = font_out->chardata[' '];
|
||||
font_out->chardata['\t'].xadvance *= tab_width;
|
||||
|
||||
i32 max_advance = 0;
|
||||
for (u16 code_point = 0; code_point < 128; ++code_point){
|
||||
if (stbtt_FindGlyphIndex(&font, code_point) != 0){
|
||||
font_out->glyphs[code_point].exists = 1;
|
||||
i32 advance = CEIL32(font_out->chardata[code_point].xadvance);
|
||||
if (max_advance < advance){
|
||||
max_advance = advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
font_out->advance = max_advance - 1;
|
||||
}
|
||||
system_free_file(file);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
font_set_tabwidth(Font *font, i32 tab_width){
|
||||
font->chardata['\t'].xadvance *= font->chardata[' '].xadvance * tab_width;
|
||||
}
|
||||
|
||||
internal void
|
||||
font_draw_glyph_mono(Render_Target *target, Font *font, u16 character,
|
||||
real32 x, real32 y, real32 advance, u32 color){
|
||||
real32 x_shift, y_shift;
|
||||
i32 left = font->chardata[character].x0;
|
||||
i32 right = font->chardata[character].x1;
|
||||
i32 width = (right - left);
|
||||
x_shift = (real32)(advance - width) * .5f - font->chardata[character].xoff;
|
||||
y_shift = (real32)font->ascent;
|
||||
|
||||
x += x_shift;
|
||||
y += y_shift;
|
||||
|
||||
stbtt_aligned_quad q;
|
||||
stbtt_GetBakedQuadUnrounded(font->chardata, font->tex_width, font->tex_height, character, &x, &y, &q, 1);
|
||||
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, font->tex);
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1);
|
||||
glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1);
|
||||
glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0);
|
||||
glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
inline void
|
||||
font_draw_glyph_mono(Render_Target *target, Font *font, u16 character,
|
||||
real32 x, real32 y, u32 color){
|
||||
font_draw_glyph_mono(target, font, character, x, y, (real32)font->advance, color);
|
||||
}
|
||||
|
||||
internal void
|
||||
font_draw_glyph(Render_Target *target, Font *font, u16 character,
|
||||
real32 x, real32 y, u32 color){
|
||||
real32 x_shift, y_shift;
|
||||
x_shift = 0;
|
||||
y_shift = (real32)font->ascent;
|
||||
|
||||
x += x_shift;
|
||||
y += y_shift;
|
||||
|
||||
stbtt_aligned_quad q;
|
||||
stbtt_GetBakedQuadUnrounded(font->chardata, font->tex_width, font->tex_height, character, &x, &y, &q, 1);
|
||||
|
||||
draw_set_color(target, color);
|
||||
draw_bind_texture(target, font->tex);
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1);
|
||||
glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1);
|
||||
glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0);
|
||||
glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
inline real32
|
||||
font_get_glyph_width(Font *font, u16 character){
|
||||
return font->chardata[character].xadvance;
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_string(Render_Target *target, Font *font, char *str,
|
||||
i32 x_, i32 y, u32 color){
|
||||
real32 x = (real32)x_;
|
||||
for (i32 i = 0; str[i]; ++i){
|
||||
char c = str[i];
|
||||
font_draw_glyph(target, font, c,
|
||||
x, (real32)y, color);
|
||||
x += font_get_glyph_width(font, c);
|
||||
}
|
||||
return CEIL32(x);
|
||||
}
|
||||
|
||||
internal real32
|
||||
draw_string_mono(Render_Target *target, Font *font, char *str,
|
||||
real32 x, real32 y, real32 advance, u32 color){
|
||||
for (i32 i = 0; str[i]; ++i){
|
||||
font_draw_glyph_mono(target, font, str[i],
|
||||
x, y, advance, color);
|
||||
x += advance;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
internal i32
|
||||
draw_string(Render_Target *target, Font *font, String str,
|
||||
i32 x_, i32 y, u32 color){
|
||||
real32 x = (real32)x_;
|
||||
for (i32 i = 0; i < str.size; ++i){
|
||||
char c = str.str[i];
|
||||
font_draw_glyph(target, font, c,
|
||||
x, (real32)y, color);
|
||||
x += font_get_glyph_width(font, c);
|
||||
}
|
||||
return CEIL32(x);
|
||||
}
|
||||
|
||||
internal real32
|
||||
draw_string_mono(Render_Target *target, Font *font, String str,
|
||||
real32 x, real32 y, real32 advance, u32 color){
|
||||
for (i32 i = 0; i < str.size; ++i){
|
||||
font_draw_glyph_mono(target, font, str.str[i],
|
||||
x, y, advance, color);
|
||||
x += advance;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
internal real32
|
||||
font_get_max_width(Font *font, char *characters){
|
||||
stbtt_bakedchar *chardata = font->chardata;
|
||||
real32 cx, x = 0;
|
||||
for (i32 i = 0; characters[i]; ++i){
|
||||
cx = chardata[characters[i]].xadvance;
|
||||
if (x < cx) x = cx;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
internal real32
|
||||
font_get_string_width(Font *font, String string){
|
||||
real32 result = 0;
|
||||
for (i32 i = 0; i < string.size; ++i){
|
||||
font_get_glyph_width(font, string.str[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 12.17.2014
|
||||
*
|
||||
* Rendering layer for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FRED_RENDERING_H
|
||||
#define FRED_RENDERING_H
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
|
||||
#if SOFTWARE_RENDER
|
||||
struct Glyph_Data{
|
||||
void *data;
|
||||
i32 width, height;
|
||||
i32 minx, maxx, miny, maxy;
|
||||
i32 left_shift;
|
||||
bool32 exists;
|
||||
};
|
||||
|
||||
struct Font{
|
||||
Glyph_Data glyphs[128];
|
||||
i32 height, ascent, descent, line_skip;
|
||||
i32 advance;
|
||||
};
|
||||
#else
|
||||
struct Glyph_Data{
|
||||
#if 0
|
||||
i32 width, height;
|
||||
i32 minx, maxx, miny, maxy;
|
||||
i32 left_shift;
|
||||
#endif
|
||||
bool32 exists;
|
||||
};
|
||||
|
||||
struct Font{
|
||||
char name_[24];
|
||||
String name;
|
||||
bool32 loaded;
|
||||
|
||||
Glyph_Data glyphs[128];
|
||||
stbtt_bakedchar chardata[128];
|
||||
i32 height, ascent, descent, line_skip;
|
||||
i32 advance;
|
||||
u32 tex;
|
||||
i32 tex_width, tex_height;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 28.08.2015
|
||||
*
|
||||
* Styles for 4coder
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
struct P4C_Page_Header{
|
||||
i32 size;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
#define P4C_STYLE_ID COMPOSE_ID('s', 't', 'y', 'l')
|
||||
|
||||
struct Style_Page_Header{
|
||||
i32 version;
|
||||
i32 count;
|
||||
};
|
||||
|
||||
struct Style_Main_Data_v1{
|
||||
u32 back_color;
|
||||
u32 margin_color;
|
||||
u32 margin_active_color;
|
||||
u32 cursor_color;
|
||||
u32 at_cursor_color;
|
||||
u32 highlight_color;
|
||||
u32 at_highlight_color;
|
||||
u32 mark_color;
|
||||
u32 default_color;
|
||||
u32 comment_color;
|
||||
u32 keyword_color;
|
||||
u32 constant_color;
|
||||
u32 special_character_color;
|
||||
u32 highlight_junk_color;
|
||||
u32 highlight_white_color;
|
||||
u32 paste_color;
|
||||
Interactive_Style file_info_style;
|
||||
};
|
||||
|
||||
struct Style_File_Format_v1{
|
||||
i32 name_size;
|
||||
char name[24];
|
||||
i32 font_name_size;
|
||||
char font_name[24];
|
||||
Style_Main_Data_v1 main;
|
||||
};
|
||||
|
||||
struct Style_Main_Data_v2{
|
||||
u32 back_color;
|
||||
u32 margin_color;
|
||||
u32 margin_active_color;
|
||||
u32 cursor_color;
|
||||
u32 at_cursor_color;
|
||||
u32 highlight_color;
|
||||
u32 at_highlight_color;
|
||||
u32 mark_color;
|
||||
u32 default_color;
|
||||
u32 comment_color;
|
||||
u32 keyword_color;
|
||||
u32 str_constant_color;
|
||||
u32 char_constant_color;
|
||||
u32 int_constant_color;
|
||||
u32 float_constant_color;
|
||||
u32 bool_constant_color;
|
||||
u32 preproc_color;
|
||||
u32 include_color;
|
||||
u32 special_character_color;
|
||||
u32 highlight_junk_color;
|
||||
u32 highlight_white_color;
|
||||
u32 paste_color;
|
||||
Interactive_Style file_info_style;
|
||||
};
|
||||
|
||||
struct Style_File_Format_v2{
|
||||
i32 name_size;
|
||||
char name[24];
|
||||
i32 font_name_size;
|
||||
char font_name[24];
|
||||
Style_Main_Data_v2 main;
|
||||
};
|
||||
|
||||
struct Style_Main_Data_v3{
|
||||
u32 back_color;
|
||||
u32 margin_color;
|
||||
u32 margin_hover_color;
|
||||
u32 margin_active_color;
|
||||
u32 cursor_color;
|
||||
u32 at_cursor_color;
|
||||
u32 highlight_color;
|
||||
u32 at_highlight_color;
|
||||
u32 mark_color;
|
||||
u32 default_color;
|
||||
u32 comment_color;
|
||||
u32 keyword_color;
|
||||
u32 str_constant_color;
|
||||
u32 char_constant_color;
|
||||
u32 int_constant_color;
|
||||
u32 float_constant_color;
|
||||
u32 bool_constant_color;
|
||||
u32 preproc_color;
|
||||
u32 include_color;
|
||||
u32 special_character_color;
|
||||
u32 highlight_junk_color;
|
||||
u32 highlight_white_color;
|
||||
u32 paste_color;
|
||||
Interactive_Style file_info_style;
|
||||
};
|
||||
|
||||
struct Style_File_Format_v3{
|
||||
i32 name_size;
|
||||
char name[24];
|
||||
i32 font_name_size;
|
||||
char font_name[24];
|
||||
Style_Main_Data_v3 main;
|
||||
};
|
||||
|
||||
struct Style{
|
||||
char name_[24];
|
||||
String name;
|
||||
Font *font;
|
||||
Style_Main_Data_v3 main;
|
||||
bool32 font_changed;
|
||||
};
|
||||
|
||||
struct Style_Library{
|
||||
Style styles[64];
|
||||
i32 count, max;
|
||||
};
|
||||
|
||||
struct Font_Set{
|
||||
Font *fonts;
|
||||
i32 count, max;
|
||||
};
|
||||
|
||||
internal void
|
||||
style_copy(Style *dst, Style *src){
|
||||
*dst = *src;
|
||||
dst->name.str = dst->name_;
|
||||
}
|
||||
|
||||
internal void
|
||||
style_set_name(Style *style, String name){
|
||||
i32 count = ArrayCount(style->name_);
|
||||
style->name_[count - 1] = 0;
|
||||
style->name = make_string(style->name_, 0, count - 1);
|
||||
copy(&style->name, name);
|
||||
}
|
||||
|
||||
internal Font*
|
||||
font_set_extract(Font_Set *fonts, char *name, i32 size){
|
||||
String n = make_string(name, size);
|
||||
i32 count = fonts->count;
|
||||
Font *result = 0;
|
||||
Font *font = fonts->fonts;
|
||||
for (i32 i = 0; i < count; ++i, ++font){
|
||||
if (match(n, font->name)){
|
||||
result = font;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
style_form_convert(Style_File_Format_v2 *o, Style_File_Format_v1 *i){
|
||||
o->name_size = i->name_size;
|
||||
memcpy(o->name, i->name, i->name_size);
|
||||
o->font_name_size = i->font_name_size;
|
||||
memcpy(o->font_name, i->font_name, i->font_name_size);
|
||||
|
||||
o->main.back_color = i->main.back_color;
|
||||
o->main.margin_color = i->main.margin_color;
|
||||
o->main.margin_active_color = i->main.margin_active_color;
|
||||
o->main.cursor_color = i->main.cursor_color;
|
||||
o->main.at_cursor_color = i->main.at_cursor_color;
|
||||
o->main.highlight_color = i->main.highlight_color;
|
||||
o->main.at_highlight_color = i->main.at_highlight_color;
|
||||
o->main.mark_color = i->main.mark_color;
|
||||
o->main.default_color = i->main.default_color;
|
||||
o->main.comment_color = i->main.comment_color;
|
||||
o->main.keyword_color = i->main.keyword_color;
|
||||
o->main.str_constant_color = i->main.constant_color;
|
||||
o->main.char_constant_color = i->main.constant_color;
|
||||
o->main.int_constant_color = i->main.constant_color;
|
||||
o->main.float_constant_color = i->main.constant_color;
|
||||
o->main.bool_constant_color = i->main.constant_color;
|
||||
o->main.include_color = i->main.constant_color;
|
||||
o->main.preproc_color = i->main.default_color;
|
||||
o->main.special_character_color = i->main.special_character_color;
|
||||
o->main.highlight_junk_color = i->main.highlight_junk_color;
|
||||
o->main.highlight_white_color = i->main.highlight_white_color;
|
||||
o->main.paste_color = i->main.paste_color;
|
||||
o->main.file_info_style = i->main.file_info_style;
|
||||
}
|
||||
|
||||
internal void
|
||||
style_form_convert(Style_File_Format_v3 *o, Style_File_Format_v2 *i){
|
||||
o->name_size = i->name_size;
|
||||
memcpy(o->name, i->name, i->name_size);
|
||||
o->font_name_size = i->font_name_size;
|
||||
memcpy(o->font_name, i->font_name, i->font_name_size);
|
||||
|
||||
o->main.back_color = i->main.back_color;
|
||||
o->main.margin_color = i->main.margin_color;
|
||||
o->main.margin_active_color = i->main.margin_active_color;
|
||||
|
||||
o->main.margin_hover_color = color_blend(i->main.margin_color, .5f, i->main.margin_active_color);
|
||||
|
||||
o->main.cursor_color = i->main.cursor_color;
|
||||
o->main.at_cursor_color = i->main.at_cursor_color;
|
||||
o->main.highlight_color = i->main.highlight_color;
|
||||
o->main.at_highlight_color = i->main.at_highlight_color;
|
||||
o->main.mark_color = i->main.mark_color;
|
||||
o->main.default_color = i->main.default_color;
|
||||
o->main.comment_color = i->main.comment_color;
|
||||
o->main.keyword_color = i->main.keyword_color;
|
||||
o->main.str_constant_color = i->main.str_constant_color;
|
||||
o->main.char_constant_color = i->main.char_constant_color;
|
||||
o->main.int_constant_color = i->main.int_constant_color;
|
||||
o->main.float_constant_color = i->main.float_constant_color;
|
||||
o->main.bool_constant_color = i->main.bool_constant_color;
|
||||
o->main.include_color = i->main.include_color;
|
||||
o->main.preproc_color = i->main.preproc_color;
|
||||
o->main.special_character_color = i->main.special_character_color;
|
||||
o->main.highlight_junk_color = i->main.highlight_junk_color;
|
||||
o->main.highlight_white_color = i->main.highlight_white_color;
|
||||
o->main.paste_color = i->main.paste_color;
|
||||
o->main.file_info_style = i->main.file_info_style;
|
||||
}
|
||||
|
||||
typedef Style_Main_Data_v3 Style_Main_Data;
|
||||
typedef Style_File_Format_v3 Style_File_Format;
|
||||
|
||||
internal void
|
||||
style_format_for_use(Font_Set *fonts, Style *out, Style_File_Format *style){
|
||||
out->name = make_string(out->name_, 0, ArrayCount(out->name_) - 1);
|
||||
out->name_[ArrayCount(out->name_) - 1] = 0;
|
||||
copy(&out->name, style->name);
|
||||
out->font = font_set_extract(fonts, style->font_name, style->font_name_size);
|
||||
out->main = style->main;
|
||||
}
|
||||
|
||||
inline void
|
||||
style_format_for_use(Font_Set *fonts, Style *out, Style_File_Format_v1 *style){
|
||||
Style_File_Format_v2 form2;
|
||||
Style_File_Format form;
|
||||
style_form_convert(&form2, style);
|
||||
style_form_convert(&form, &form2);
|
||||
style_format_for_use(fonts, out, &form);
|
||||
}
|
||||
|
||||
inline void
|
||||
style_format_for_use(Font_Set *fonts, Style *out, Style_File_Format_v2 *style){
|
||||
Style_File_Format form;
|
||||
style_form_convert(&form, style);
|
||||
style_format_for_use(fonts, out, &form);
|
||||
}
|
||||
|
||||
internal bool32
|
||||
style_library_import(u8 *filename, Font_Set *fonts, Style *out, i32 max,
|
||||
i32 *count_opt, i32 *total_opt = 0){
|
||||
bool32 result = 1;
|
||||
File_Data file = system_load_file(filename);
|
||||
if (!file.data){
|
||||
result = 0;
|
||||
}
|
||||
else{
|
||||
void *cursor = file.data;
|
||||
i32 to_read = 0;
|
||||
|
||||
{
|
||||
P4C_Page_Header *h = (P4C_Page_Header*)cursor;
|
||||
if (h->id != P4C_STYLE_ID){
|
||||
result = 0;
|
||||
goto early_exit;
|
||||
}
|
||||
cursor = h+1;
|
||||
}
|
||||
|
||||
Style_Page_Header *h = (Style_Page_Header*)cursor;
|
||||
to_read = h->count;
|
||||
cursor = h+1;
|
||||
|
||||
if (total_opt) *total_opt = to_read;
|
||||
if (to_read > max) to_read = max;
|
||||
if (count_opt) *count_opt = to_read;
|
||||
|
||||
switch (h->version){
|
||||
case 1:
|
||||
{
|
||||
Style_File_Format_v1 *in = (Style_File_Format_v1*)cursor;
|
||||
for (i32 i = 0; i < to_read; ++i){
|
||||
style_format_for_use(fonts, out++, in++);
|
||||
}
|
||||
}break;
|
||||
case 2:
|
||||
{
|
||||
Style_File_Format_v2 *in = (Style_File_Format_v2*)cursor;
|
||||
for (i32 i = 0; i < to_read; ++i){
|
||||
style_format_for_use(fonts, out++, in++);
|
||||
}
|
||||
}break;
|
||||
case 3:
|
||||
{
|
||||
Style_File_Format_v3 *in = (Style_File_Format_v3*)cursor;
|
||||
for (i32 i = 0; i < to_read; ++i){
|
||||
style_format_for_use(fonts, out++, in++);
|
||||
}
|
||||
}break;
|
||||
default: result = 0; break;
|
||||
}
|
||||
|
||||
early_exit:
|
||||
system_free_file(file);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool32
|
||||
style_library_add(Style_Library *library, Style *style){
|
||||
bool32 result = 0;
|
||||
i32 count = library->count;
|
||||
String my_name = style->name;
|
||||
Style *ostyle = library->styles;
|
||||
Style *out = 0;
|
||||
// TODO(allen): hashtable for name lookup?
|
||||
for (i32 i = 0; i < count; ++i, ++ostyle){
|
||||
if (match(my_name, ostyle->name)){
|
||||
out = ostyle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!out && count < library->max){
|
||||
out = library->styles + library->count++;
|
||||
}
|
||||
if (out){
|
||||
style_copy(out, style);
|
||||
result = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Style_File_Format
|
||||
style_format_for_file(Style *style){
|
||||
Style_File_Format result;
|
||||
Font *font = style->font;
|
||||
result.name_size = style->name.size;
|
||||
memcpy(result.name, style->name.str, ArrayCount(result.name));
|
||||
result.font_name_size = font->name.size;
|
||||
memcpy(result.font_name, font->name.str, ArrayCount(result.font_name));
|
||||
result.main = style->main;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
style_library_export(u8 *filename, Style **styles, i32 count){
|
||||
i32 size = count*sizeof(Style_File_Format) +
|
||||
sizeof(P4C_Page_Header) + sizeof(Style_Page_Header);
|
||||
void *data = system_get_memory(size);
|
||||
void *cursor = data;
|
||||
|
||||
{
|
||||
P4C_Page_Header *h = (P4C_Page_Header*)cursor;
|
||||
h->size = size - sizeof(P4C_Page_Header);
|
||||
h->id = P4C_STYLE_ID;
|
||||
cursor = h+1;
|
||||
}
|
||||
|
||||
{
|
||||
Style_Page_Header *h = (Style_Page_Header*)cursor;
|
||||
h->version = 1;
|
||||
h->count = count;
|
||||
cursor = h+1;
|
||||
}
|
||||
|
||||
Style_File_Format *out = (Style_File_Format*)cursor;
|
||||
Style **in = styles;
|
||||
for (i32 i = 0; i < count; ++i){
|
||||
*out++ = style_format_for_file(*in++);
|
||||
}
|
||||
system_save_file(filename, data, size);
|
||||
system_free_memory(data);
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 21.01.2014
|
||||
*
|
||||
* System functions for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
// TODO(allen): This should either be a String or it should be improved
|
||||
// to handle 64-bit sized files. Staying in this state, however, is unacceptable.
|
||||
struct File_Data{
|
||||
void *data;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct Time_Stamp{
|
||||
u64 time;
|
||||
bool32 success;
|
||||
};
|
||||
|
||||
internal File_Data
|
||||
system_load_file(u8 *filename);
|
||||
|
||||
internal bool32
|
||||
system_save_file(u8 *filename, void *data, i32 size);
|
||||
|
||||
internal Time_Stamp
|
||||
system_file_time_stamp(u8 *filename);
|
||||
|
||||
internal u64
|
||||
system_get_now();
|
||||
|
||||
internal void
|
||||
system_free_file(File_Data data);
|
||||
|
||||
internal void
|
||||
system_fatal_error(u8 *message);
|
||||
|
||||
internal i32
|
||||
system_get_working_directory(u8 *destination, i32 max_size);
|
||||
|
||||
internal i32
|
||||
system_get_easy_directory(u8 *destination);
|
||||
|
||||
struct File_Info{
|
||||
String filename;
|
||||
bool32 folder;
|
||||
//bool32 loaded;
|
||||
};
|
||||
|
||||
struct File_List{
|
||||
File_Info *infos;
|
||||
i32 count;
|
||||
|
||||
void *block;
|
||||
};
|
||||
|
||||
internal File_List
|
||||
system_get_files(String directory);
|
||||
|
||||
internal void
|
||||
system_free_file_list(File_List list);
|
||||
|
||||
internal void*
|
||||
system_get_memory_(i32 size, i32 line_number, char *file_name);
|
||||
|
||||
#define system_get_memory(size) system_get_memory_(size, __LINE__, __FILE__)
|
||||
|
||||
internal void
|
||||
system_free_memory(void *block);
|
||||
|
||||
internal void
|
||||
system_post_clipboard(String str);
|
||||
|
||||
internal i64
|
||||
system_time();
|
||||
|
||||
struct Thread_Context;
|
||||
|
||||
struct Thread_Memory{
|
||||
void *data;
|
||||
i32 size;
|
||||
i32 id;
|
||||
};
|
||||
|
||||
internal u32
|
||||
system_thread_get_id(Thread_Context *thread);
|
||||
|
||||
internal u32
|
||||
system_thread_current_job_id(Thread_Context *thread);
|
||||
|
||||
enum Thread_Group_ID{
|
||||
BACKGROUND_THREADS,
|
||||
THREAD_GROUP_COUNT
|
||||
};
|
||||
|
||||
#define JOB_CALLBACK(name) void name(Thread_Context *thread, Thread_Memory *memory, void *data[2])
|
||||
typedef JOB_CALLBACK(Job_Callback);
|
||||
|
||||
struct Job_Data{
|
||||
Job_Callback *callback;
|
||||
void *data[2];
|
||||
i32 memory_request;
|
||||
};
|
||||
|
||||
internal u32
|
||||
system_post_job(Thread_Group_ID group_id, Job_Data job);
|
||||
|
||||
internal void
|
||||
system_cancel_job(Thread_Group_ID group_id, u32 job_id);
|
||||
|
||||
internal bool32
|
||||
system_job_is_pending(Thread_Group_ID group_id, u32 job_id);
|
||||
|
||||
enum Lock_ID{
|
||||
FRAME_LOCK,
|
||||
CANCEL_LOCK0,
|
||||
CANCEL_LOCK1,
|
||||
CANCEL_LOCK2,
|
||||
CANCEL_LOCK3,
|
||||
CANCEL_LOCK4,
|
||||
CANCEL_LOCK5,
|
||||
CANCEL_LOCK6,
|
||||
CANCEL_LOCK7,
|
||||
LOCK_COUNT
|
||||
};
|
||||
|
||||
internal void
|
||||
system_aquire_lock(Lock_ID id);
|
||||
|
||||
internal void
|
||||
system_release_lock(Lock_ID id);
|
||||
|
||||
internal void
|
||||
system_aquire_lock(i32 id);
|
||||
|
||||
internal void
|
||||
system_release_lock(i32 id);
|
||||
|
||||
internal void
|
||||
system_grow_thread_memory(Thread_Memory *memory);
|
||||
|
||||
internal void
|
||||
system_force_redraw();
|
||||
|
||||
#if FRED_INTERNAL
|
||||
internal Bubble*
|
||||
INTERNAL_system_sentinel();
|
||||
|
||||
internal void
|
||||
INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Mr. 4th Dimention - Allen Webster
|
||||
*
|
||||
* 1.21.2015
|
||||
*
|
||||
* Test for CPP lexer & parser layer for project codename "4ed"
|
||||
*
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
// HOLY GRAIL
|
||||
#if 0
|
||||
int main(){
|
||||
Parse_Context context;
|
||||
Parse_Definitions definitions;
|
||||
Cpp_Parse_Preprocessor_State state;
|
||||
|
||||
cpp_default_context(&context, COMPILER_MSVC, PLATFORM_WIN32);
|
||||
cpp_default_definitions(&definitions, COMPILER_MSVC, PLATFORM_WIN32);
|
||||
cpp_set_target_file(&definitions, &state, "TARGET.cpp");
|
||||
|
||||
cpp_parse(&context, &definitions, &state);
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "../4ed_meta.h"
|
||||
|
||||
#include "../4cpp_types.h"
|
||||
#define FCPP_STRING_IMPLEMENTATION
|
||||
#include "../4cpp_string.h"
|
||||
#define FCPP_LEXER_IMPLEMENTATION
|
||||
#include "../4cpp_lexer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define FCPP_PREPROCESSOR_DBG_LEVEL 1
|
||||
|
||||
internal bool
|
||||
system_is_absoute_path(char *path){
|
||||
bool is_absolute = 0;
|
||||
char c = 1;
|
||||
while (c){
|
||||
c = *path++;
|
||||
if (c == ':'){
|
||||
is_absolute = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_absolute;
|
||||
}
|
||||
|
||||
#undef Assert
|
||||
#undef TentativeAssert
|
||||
|
||||
#define Assert assert
|
||||
#define TentativeAssert assert
|
||||
|
||||
#include "../4cpp_preprocessor.cpp"
|
||||
|
||||
Cpp_File
|
||||
quickie_file(char *filename){
|
||||
Cpp_File result;
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
TentativeAssert(file);
|
||||
fseek(file, 0, SEEK_END);
|
||||
result.size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
result.data = (char*)malloc(result.size);
|
||||
fread(result.data, 1, result.size, file);
|
||||
fclose(file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Cpp_File
|
||||
quickie_file(String filename){
|
||||
assert(filename.size < 511);
|
||||
char buffer[512];
|
||||
memcpy(buffer, filename.str, filename.size);
|
||||
buffer[filename.size] = 0;
|
||||
return quickie_file(buffer);
|
||||
}
|
||||
|
||||
#define STRICT_MEM_TEST 1
|
||||
|
||||
#if 1
|
||||
int main(){
|
||||
char TEST_FILE[] = "parser_test6.cpp";
|
||||
|
||||
Cpp_File target_file;
|
||||
target_file = quickie_file(TEST_FILE);
|
||||
|
||||
Cpp_Token_Stack target_tokens = {};
|
||||
cpp_lex_file(target_file, &target_tokens);
|
||||
|
||||
Cpp_Parse_Context context = {};
|
||||
Cpp_Parse_Definitions definitions = {};
|
||||
Cpp_Preproc_State state = {};
|
||||
|
||||
context.preserve_chunk_size = (200 << 10);
|
||||
|
||||
definitions.table.size = 0;
|
||||
#if STRICT_MEM_TEST
|
||||
definitions.table.max_size = 16;
|
||||
#else
|
||||
definitions.table.max_size = 100;
|
||||
#endif
|
||||
definitions.table.table = (Table_Entry*)malloc(sizeof(Table_Entry)*definitions.table.max_size);
|
||||
memset(definitions.table.table, 0, sizeof(Table_Entry)*definitions.table.max_size);
|
||||
|
||||
definitions.count = 0;
|
||||
#if STRICT_MEM_TEST
|
||||
definitions.max = 16;
|
||||
#else
|
||||
definitions.max = 100;
|
||||
#endif
|
||||
definitions.slots = (Cpp_Def_Slot*)malloc(sizeof(Cpp_Def_Slot)*definitions.max);
|
||||
|
||||
{
|
||||
String string_filename = make_lit_string("~ string space");
|
||||
Cpp_File string_file;
|
||||
#if STRICT_MEM_TEST
|
||||
string_file.size = 100;
|
||||
#else
|
||||
string_file.size = (128 << 10);
|
||||
#endif
|
||||
string_file.data = (char*)malloc(string_file.size);
|
||||
Cpp_Token_Stack string_tokens;
|
||||
string_tokens.count = 0;
|
||||
#if STRICT_MEM_TEST
|
||||
string_tokens.max_count = 2;
|
||||
#else
|
||||
string_tokens.max_count = (128 << 10)/sizeof(Cpp_Token);
|
||||
#endif
|
||||
string_tokens.tokens = (Cpp_Token*)malloc(sizeof(Cpp_Token)*string_tokens.max_count);
|
||||
|
||||
Cpp_Parse_File string_parse_file;
|
||||
string_parse_file.file = string_file;
|
||||
string_parse_file.tokens = string_tokens;
|
||||
string_parse_file.filename = string_filename;
|
||||
|
||||
int string_index = cpp_defs_add(&definitions, {}, CPP_DEFTYPE_FILE);
|
||||
cpp_set_parse_file(&definitions, string_index, string_parse_file);
|
||||
|
||||
definitions.string_file_index = string_index;
|
||||
definitions.string_write_pos = 0;
|
||||
|
||||
{
|
||||
Cpp_Token eof_token = {};
|
||||
eof_token.type = CPP_TOKEN_EOF;
|
||||
definitions.eof_token = cpp__preserve_token(&definitions, eof_token);
|
||||
}
|
||||
|
||||
{
|
||||
String string_va_args = make_lit_string("__VA_ARGS__");
|
||||
Cpp_Token va_args_token;
|
||||
va_args_token.type = CPP_TOKEN_IDENTIFIER;
|
||||
va_args_token.start = definitions.string_write_pos;
|
||||
va_args_token.size = string_va_args.size;
|
||||
cpp__preserve_string(&definitions, string_va_args);
|
||||
definitions.va_args_token = cpp__preserve_token(&definitions, va_args_token);
|
||||
}
|
||||
}
|
||||
|
||||
state.tokens.count = 0;
|
||||
#if STRICT_MEM_TEST
|
||||
state.tokens.max = 5;
|
||||
#else
|
||||
state.tokens.max = 100;
|
||||
#endif
|
||||
state.tokens.tokens = (Cpp_Loose_Token*)malloc(sizeof(Cpp_Loose_Token)*state.tokens.max);
|
||||
|
||||
state.spare_string_write_pos = 0;
|
||||
#if STRICT_MEM_TEST
|
||||
state.spare_string_size = 1;
|
||||
#else
|
||||
state.spare_string_size = (10 << 10);
|
||||
#endif
|
||||
state.spare_string = (char*)malloc(state.spare_string_size);
|
||||
|
||||
String target_filename = make_lit_string(TEST_FILE);
|
||||
cpp_set_target(&state, &definitions, target_file, target_tokens, target_filename);
|
||||
|
||||
while (!state.finished){
|
||||
Cpp_Preproc_Result result;
|
||||
result = cpp_preproc_step_nonalloc(&state, &definitions, &context);
|
||||
|
||||
if (result.memory_request){
|
||||
Cpp_Memory_Request request = cpp_get_memory_request(&state, &definitions, result);
|
||||
void *memory = malloc(request.size);
|
||||
void *old_memory = cpp_provide_memory(request, memory);
|
||||
free(old_memory);
|
||||
}
|
||||
|
||||
if (result.file_request){
|
||||
Cpp_File_Request request = cpp_get_file_request(&state, result);
|
||||
for (; cpp_has_more_files(&request); cpp_get_next_file(&request)){
|
||||
if (!cpp_try_reuse_file(&request)){
|
||||
Cpp_File new_file = quickie_file(request.filename);
|
||||
Cpp_Token_Stack new_tokens = {};
|
||||
cpp_lex_file(new_file, &new_tokens);
|
||||
cpp_provide_file(&request, new_file, new_tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.error_code){
|
||||
String error_message = cpp_get_error(result.error_code);
|
||||
Cpp_Parse_File file = *cpp_get_parse_file(&definitions, result.file_index);
|
||||
Cpp_Token token = file.tokens.tokens[result.token_index];
|
||||
bool terminate = cpp_recommend_termination(result.error_code);
|
||||
|
||||
if (terminate){
|
||||
printf("FATAL ");
|
||||
}
|
||||
|
||||
printf("ERROR IN %.*s AT %.*s\n%.*s\n",
|
||||
file.filename.size, file.filename.str,
|
||||
token.size, file.file.data + token.start,
|
||||
error_message.size, error_message.str);
|
||||
|
||||
if (terminate){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.emit){
|
||||
Cpp_Parse_File file = *cpp_get_parse_file(&definitions, result.file_index);
|
||||
Cpp_Token token = file.tokens.tokens[result.token_index];
|
||||
|
||||
if (result.from_macro){
|
||||
Cpp_Parse_File file = *cpp_get_parse_file(&definitions, result.invoking_file_index);
|
||||
Cpp_Token token = file.tokens.tokens[result.invoking_token_index];
|
||||
|
||||
printf("EXPANDING %.*s => ", token.size, file.file.data + token.start);
|
||||
}
|
||||
|
||||
printf("TOKEN %.*s\n", token.size, file.file.data + token.start);
|
||||
}
|
||||
}
|
||||
|
||||
assert(state.finished == 0 || state.expansion_level == 0);
|
||||
assert(state.finished == 0 || state.param_info_used == 0);
|
||||
assert(state.finished == 0 || state.state == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue