This commit is contained in:
Allen Webster 2015-09-28 19:34:55 -04:00
commit fb91a10918
27 changed files with 20357 additions and 0 deletions

221
4coder_custom.cpp Normal file
View File

@ -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;
}

176
4coder_custom.h Normal file
View File

@ -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;
};
};

54
4cpp_clear_config.h Normal file
View File

@ -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

81
4cpp_config.h Normal file
View File

@ -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

1912
4cpp_lexer.h Normal file

File diff suppressed because it is too large Load Diff

2058
4cpp_preprocessor.cpp Normal file

File diff suppressed because it is too large Load Diff

997
4cpp_string.h Normal file
View File

@ -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

39
4cpp_types.h Normal file
View File

@ -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

3164
4ed.cpp Normal file

File diff suppressed because it is too large Load Diff

355
4ed.h Normal file
View File

@ -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

2247
4ed_color_view.cpp Normal file

File diff suppressed because it is too large Load Diff

135
4ed_command.cpp Normal file
View File

@ -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

527
4ed_debug_view.cpp Normal file
View File

@ -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

3244
4ed_file_view.cpp Normal file

File diff suppressed because it is too large Load Diff

187
4ed_interactive_view.cpp Normal file
View File

@ -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

188
4ed_internal.h Normal file
View File

@ -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

163
4ed_keyboard.cpp Normal file
View File

@ -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

516
4ed_layout.cpp Normal file
View File

@ -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

749
4ed_math.cpp Normal file
View File

@ -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

84
4ed_menu_view.cpp Normal file
View File

@ -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

182
4ed_meta.h Normal file
View File

@ -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

898
4ed_rendering.cpp Normal file
View File

@ -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

54
4ed_rendering.h Normal file
View File

@ -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

391
4ed_style.cpp Normal file
View File

@ -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

154
4ed_system.h Normal file
View File

@ -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

255
test/experiment.cpp Normal file
View File

@ -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

1326
win32_4ed.cpp Normal file

File diff suppressed because it is too large Load Diff