int cvar_fti(float f) { return *((int*)&f); } float cvar_itf(int i) { return *((float*)&i); } void cvar_fnc_void(cvar_t *cv, int value) { ; } void cvar_fnc_bool(cvar_t *cv, int value) { *((byte*)cv->data) = (byte)value; } void cvar_fnc_int(cvar_t *cv, int value) { *((int*)cv->data) = value; } void cvar_fnc_float(cvar_t *cv, int value) { *((float*)cv->data) = cvar_itf(value); } void cvar_fnc_double(cvar_t *cv, int value) { *((double*)cv->data) = (double)cvar_itf(value); } void cvar_fnc_color(cvar_t *cv, int value) { *((uint*)cv->data) = (uint)value; } void cvar_fnc_fcolor(cvar_t *cv, int value) { ((float*)cv->data)[0] = ((float)((uint)((value >> 16) & 0xff))) * 255.0f; ((float*)cv->data)[1] = ((float)((uint)((value >> 8) & 0xff))) * 255.0f; ((float*)cv->data)[2] = ((float)((uint)(value & 0xff))) * 255.0f; } void cvar_fnc_scolor(cvar_t *cv, int value) { *((uint*)cv->data) = ((uint)value) | 0xff000000; } void cvar_fnc_ccolor(cvar_t *cv, int value) { *((uint*)cv->data) = ((uint)value) | ((*((uint*)cv->data)) & 0xff000000); } void cvar_fnc_acolor(cvar_t *cv, int value) { *((uint*)cv->data) = ((uint)(float)(cvar_itf(value) * 255.0f)) | ((*((uint*)cv->data)) & 0x00ffffff); } void cvar_fnc_bind(cvar_t *cv, int value) { ((bind_t*)cv->data)->key = value; } cvar_t *cvar_add(const char *name, cvar_func *func, void *data, void *aux_data, int def, int min, int max, byte type, byte category, byte readonly, byte startup) { cvar_t *cv = &sys.cvars[sys.n_cvars]; cv->func = func; cv->data = data; cv->aux_data = aux_data; cv->value = cv->def = def; cv->min = min; cv->max = max; cv->id = sys.n_cvars; cv->readonly = readonly; cv->startup = startup; cv->type = type; cv->category = category; cv->name = name; sys.n_cvars += 1; return cv; } cvar_t *cvar_add_bool(const char *name, byte category, byte *data, byte def) { cvar_t *cv = cvar_add(name, cvar_fnc_bool, data, NULL, (int)def, 0, 0, CVAR_BOOL, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_sbool(const char *name, byte category, cvar_func *func, byte *data, byte def, byte startup) { cvar_t *cv = cvar_add(name, func, data, NULL, (int)def, 0, 0, CVAR_BOOL, category, 0, startup); if(data) *data = def; return cv; } cvar_t *cvar_add_wbool(const char *name, byte category, cvar_func *func, byte def) { return cvar_add(name, func, NULL, NULL, (int)def, 0, 0, CVAR_BOOL, category, 0, 0); } cvar_t *cvar_add_int(const char *name, byte category, int *data, int def, int min, int max) { cvar_t *cv = cvar_add(name, cvar_fnc_int, data, NULL, def, min, max, CVAR_INT, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_sint(const char *name, byte category, cvar_func *func, int *data, int def, int min, int max, byte startup) { cvar_t *cv = cvar_add(name, func, data, NULL, def, min, max, CVAR_INT, category, 0, startup); if(data) *data = def; return cv; } cvar_t *cvar_add_byte(const char *name, byte category, byte *data, byte def, byte min, byte max) { cvar_t *cv = cvar_add(name, cvar_fnc_bool, data, NULL, (int)def, (int)min, (int)max, CVAR_INT, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_rint(const char *name, byte category, int def, int min, int max) { return cvar_add(name, cvar_fnc_void, NULL, NULL, def, min, max, CVAR_INT, category, 1, 0); } cvar_t *cvar_add_wint(const char *name, byte category, cvar_func *func, int def, int min, int max) { return cvar_add(name, func, NULL, NULL, def, min, max, CVAR_INT, category, 0, 0); } cvar_t *cvar_add_float(const char *name, byte category, float *data, float def, float min, float max) { cvar_t *cv = cvar_add(name, cvar_fnc_float, data, NULL, cvar_fti(def), cvar_fti(min), cvar_fti(max), CVAR_FLOAT, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_sfloat(const char *name, byte category, cvar_func *func, float *data, float def, float min, float max, byte startup) { cvar_t *cv = cvar_add(name, func, data, NULL, cvar_fti(def), cvar_fti(min), cvar_fti(max), CVAR_FLOAT, category, 0, startup); if(data) *data = def; return cv; } cvar_t *cvar_add_double(const char *name, byte category, double *data, float def, float min, float max) { cvar_t *cv = cvar_add(name, cvar_fnc_double, data, NULL, cvar_fti(def), cvar_fti(min), cvar_fti(max), CVAR_FLOAT, category, 0, 1); if(data) *data = (double)def; return cv; } cvar_t *cvar_add_benum(const char *name, byte category, byte *data, const char **names, byte def, int states) { cvar_t *cv = cvar_add(name, cvar_fnc_bool, data, names, (int)def, 0, states, CVAR_ENUM, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_sbenum(const char *name, byte category, cvar_func *func, byte *data, const char **names, byte def, int states, byte startup) { cvar_t *cv = cvar_add(name, func, data, names, (int)def, 0, states, CVAR_ENUM, category, 0, startup); if(data) *data = def; return cv; } cvar_t *cvar_add_ienum(const char *name, byte category, int *data, const char **names, int def, int states) { cvar_t *cv = cvar_add(name, cvar_fnc_int, data, names, def, 0, states, CVAR_ENUM, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_color(const char *name, byte category, uint *data, uint def) { cvar_t *cv = cvar_add(name, cvar_fnc_scolor, data, NULL, (int)def, 0, 0, CVAR_COLOR, category, 0, 1); if(data) *data = def | 0xff000000; return cv; } cvar_t *cvar_add_scolor(const char *name, byte category, cvar_func *func, uint *data, uint def, byte startup) { cvar_t *cv = cvar_add(name, func, data, NULL, (int)def, 0, 0, CVAR_COLOR, category, 0, startup); if(data) *data = def | 0xff000000; return cv; } cvar_t *cvar_add_acolor(const char *name, byte category, uint *data, uint def) { cvar_t *cv = cvar_add(name, cvar_fnc_color, data, NULL, (int)def, 0, 0, CVAR_COLOR_ALPHA, category, 0, 1); if(data) *data = def; return cv; } cvar_t *cvar_add_key(const char *name, byte bind, int def) { cvar_t *cv = cvar_add(name, cvar_fnc_bind, &sys.binds[bind], NULL, def, 0, 0, CVAR_KEY, CVAR_BIND, 0, 1); sys.binds[bind].key = def; return cv; } void cvar_fmt_bool(char *str, int value) { sprintf(str, value ? "true" : "false"); } void cvar_fmt_int(char *str, int value) { sprintf(str, "%d", value); } void cvar_fmt_float(char *str, int value) { sprintf(str, "%.3f", cvar_itf(value)); } void cvar_fmt_color(char *str, int value) { sprintf(str, "%06x", (uint)value); } void cvar_fmt_acolor(char *str, int value) { sprintf(str, "%08x", (uint)value); } void cvar_fmt_key(char *str, int value) { if(value == 0) { sprintf(str, "none"); } else if(value >= -SCROLL_RIGHT && value <= -MOUSE_LEFT) { sprintf(str, key_names[KEY_MOUSE_OFFSET - (value + MOUSE_LEFT)]); } else if(value >= KEYSYM_0 && value <= KEYSYM_9) { sprintf(str, "%d", value - KEYSYM_0); } else if(value >= KEYSYM_A && value <= KEYSYM_Z) { sprintf(str, "%c", 'a' + (char)(value - KEYSYM_A)); } else if(value >= KEYSYM_F1 && value <= KEYSYM_F12) { sprintf(str, "f%d", 1 + value - KEYSYM_F1); } else if(value >= KEYSYM_KP_0 && value <= KEYSYM_KP_9) { sprintf(str, "kp%d", value - KEYSYM_KP_0); } else if(value >= KEYSYM_FIRST && value <= KEYSYM_LAST) { sprintf(str, key_names[value - KEYSYM_FIRST]); } else { sprintf(str, "#%d", value); } } static const cvar_fmt_func cvar_fmt[] = {cvar_fmt_bool, cvar_fmt_int, cvar_fmt_float, NULL, cvar_fmt_color, cvar_fmt_acolor, cvar_fmt_key}; byte cvar_parse_bool(const char *str, int *value) { if(str_eq_lower("1", str) || str_eq_lower("true", str) || str_eq_lower("on", str) || str_eq_lower("yes", str) || str_eq_lower("y", str)) { *value = 1; return 1; } else if(str_eq_lower("0", str) || str_eq_lower("false", str) || str_eq_lower("off", str) || str_eq_lower("no", str) || str_eq_lower("n", str)) { *value = 0; return 1; } return 0; } byte cvar_parse_int(const char *str, int *value) { return str_parse_int(str, value, 0); } byte cvar_parse_float(const char *str, int *value) { errno = 0; float f = strtof(str, NULL); if(errno) return 0; *value = cvar_fti(f); return 1; } byte cvar_parse_color(const char *str, int *value) { int c; if((!str_parse_int(str, &c, -16)) || (c & 0xff000000)) return 0; *value = c; return 1; } byte cvar_parse_acolor(const char *str, int *value) { return str_parse_int(str, value, -16); } byte cvar_parse_key(const char *str, int *value) { int comp; int max = 0; int best = 0; if(str[0] >= '0' && str[0] <= '9' && !(str[1])) { *value = (str[0] - '0') + KEYSYM_0; return 1; } else if(str[0] >= 'a' && str[0] <= 'z' && !(str[1])) { *value = (str[0] - 'a') + KEYSYM_A; return 1; } else if(str[0] >= 'A' && str[0] <= 'Z' && !(str[1])) { *value = (str[0] - 'A') + KEYSYM_A; return 1; } else if((str[0] == '#') && str[1] && str_parse_int(str+1, value, 10)) { return 1; } else if((str_lower(str[0]) == 'f') && str[1] && str_parse_int(str+1, &comp, 10) && (comp >= 1) && (comp <= 25)) { *value = (comp - 1) + KEYSYM_F1; return 1; } else if((str_lower(str[0]) == 'k') && (str_lower(str[1]) == 'p') && (str[2] >= '0') && (str[2] <= '9') && !(str[3])) { *value = (str[2] - '0') + KEYSYM_KP_0; return 1; } else if(str_eq_lower("none", str)) { *value = 0; return 1; } for(int z = 0; z < KEY_MOUSE_OFFSET + SCROLL_RIGHT; z++) { if((comp = str_cmp_lower(key_names[z], str)) > best) { max = comp; best = z; } } if(max) { *value = (best >= KEY_MOUSE_OFFSET) ? -(MOUSE_LEFT + best - KEY_MOUSE_OFFSET) : (KEYSYM_FIRST + best); return 1; } return 0; } static const cvar_parse_func cvar_parse[] = {cvar_parse_bool, cvar_parse_int, cvar_parse_float, NULL, cvar_parse_color, cvar_parse_acolor, cvar_parse_key}; cvar_t *cvar_get(const char *key) { return (cvar_t*)smap_get(&sys.cvar_map, key); } byte cvar_set(cvar_t *cv, const char *str, byte startup) { if((cv->type == CVAR_ENUM) ? str_parse_enum(str, (const char**)cv->aux_data, cv->max, &cv->value) : cvar_parse[cv->type](str, &cv->value)) { if(cv->type == CVAR_INT) cv->value = CLAMP_VALUE(cv->value, cv->min, cv->max); else if(cv->type == CVAR_FLOAT) cv->value = cvar_fti(CLAMP_VALUE(cvar_itf(cv->value), cvar_itf(cv->min), cvar_itf(cv->max))); if((!startup) || cv->startup) cv->func(cv, cv->value); sys.cfg_dirty |= startup ^ 1; return 1; } else { sys.cfg_dirty |= startup; return 0; } } void cvar_format(cvar_t *cv, char *str) { if(cv->type == CVAR_ENUM) { sprintf(str, "%s", ((const char**)cv->aux_data)[cv->value]); } else { cvar_fmt[cv->type](str, cv->value); } } byte cvar_byte(const char *name) { return (byte)cvar_get(name)->value; } int cvar_int(const char *name) { return cvar_get(name)->value; } float cvar_float(const char *name) { return cvar_itf(cvar_get(name)->value); } uint cvar_color(const char *name) { return (uint)cvar_get(name)->value; } int cvar_key(byte bind) { return sys.cvars[bind].value; } int cvar_defkey(byte bind) { return sys.cvars[bind].def; } void cvar_sdef(cvar_t *cv) { cv->value = cv->def; cv->func(cv, cv->value); sys.cfg_dirty = 1; } void cvar_setdef(const char *name) { cvar_sdef(cvar_get(name)); } void cvar_str(const char *name, char *str) { cvar_format(cvar_get(name), str); } void cvar_sbool(cvar_t *cv, byte value) { cv->value = (int)value; cv->func(cv, cv->value); sys.cfg_dirty = 1; } void cvar_setbool(const char *name, byte value) { cvar_sbool(cvar_get(name), value); } void cvar_toggle(const char *name) { cvar_t *cv = cvar_get(name); cv->value ^= 1; cv->func(cv, cv->value); sys.cfg_dirty = 1; } void cvar_sint(cvar_t *cv, int value) { cv->value = value; cv->func(cv, cv->value); sys.cfg_dirty = 1; } void cvar_setint(const char *name, int value) { cvar_sint(cvar_get(name), value); } void cvar_sfloat(cvar_t *cv, float value) { cv->value = cvar_fti(value); cv->func(cv, cv->value); sys.cfg_dirty = 1; } void cvar_setfloat(const char *name, float value) { cvar_sfloat(cvar_get(name), value); } void cvar_scolor(cvar_t *cv, uint value) { cv->value = (int)value; cv->func(cv, cv->value); sys.cfg_dirty = 1; } void cvar_skey(byte bind, int value) { cvar_t *cv = &sys.cvars[bind]; cv->value = (int)value; cv->func(cv, cv->value); sys.cfg_dirty = 1; } byte cvar_sstr(cvar_t *cv, const char *value) { return cvar_set(cv, value, 0); } // void win_full(byte full); // void cvar_fnc_full(cvar_t *cv, int value) { // win_full(value); // } void win_sync(int sync); void cvar_fnc_sync(cvar_t *cv, int value) { win_sync(value); } void cvar_fnc_dlight(cvar_t *cv, int value) { light_setup(value); } void tick_target(float tps); void cvar_fnc_ticktarget(cvar_t *cv, int value) { tick_target(cvar_itf(value)); } void cvar_fnc_tex(cvar_t *cv, int value) { cvar_fnc_bool(cv, value); tex_config(); } void cvar_fnc_ftex(cvar_t *cv, int value) { cvar_fnc_float(cv, value); tex_config(); } void con_resize(int size); void cvar_fnc_consize(cvar_t *cv, int value) { con_resize(value); } void plr_debug(byte debug); void plr_volume(byte channel, ushort volume); void cvar_fnc_middebug(cvar_t *cv, int value) { plr_debug((byte)value); } void cvar_fnc_volume(cvar_t *cv, int value) { plr_volume((byte)(int)(cv->id - cvar_get(snd_cvar_volume[0])->id), (ushort)(cvar_itf(value) * 32767.0f)); } void cvar_fnc_sound(cvar_t *cv, int value) { } void gfx_back_color(uint color); void cvar_fnc_clight(cvar_t *cv, int value) { gfx_back_color(0xff000000 | (uint)value); } void cvar_reg() { #include "vars.h" } void theme_reg() { style_t *style; #define theme_add(str) \ style = (style_t*)tbl_push(&sys.themes);\ style->name = str; #define theme_window(bdrtop, bdrbtm, top, btm, text) \ style->wbrdr_top = bdrtop;\ style->wbrdr_btm = bdrbtm;\ style->win_top = top;\ style->win_btm = btm;\ style->text_win = text; #define theme_border(top, btm, size) \ style->brdr_top = top;\ style->brdr_btm = btm;\ style->border = size; #define theme_background(top, btm) \ style->bg_top = top;\ style->bg_btm = btm; #define theme_base(top, btm, text, label) \ style->fill_top = top;\ style->fill_btm = btm;\ style->text_base = text;\ style->text_label = label; #define theme_field(top, btm, text) \ style->field_top = top;\ style->field_btm = btm;\ style->text_field = text; #define theme_slider(handle) \ style->slider_width = handle; #define theme_select(presstop, pressbtm, hovertop, hoverbtm, sel, cur) \ style->press_top = presstop;\ style->press_btm = pressbtm;\ style->hover_top = hovertop;\ style->hover_btm = hoverbtm;\ style->select = sel;\ style->cursor = cur; #include "themes.h" #undef theme_add #undef theme_window #undef theme_border #undef theme_background #undef theme_base #undef theme_field #undef theme_slider #undef theme_select sys.style_def = style; } byte cvar_load() { char str[64]; char *lines; char *line = NULL; cvar_t *cv; int pos; if(!file_sread(&lines, sys.cfg_file)) { return 0; } while(line = strtok(line ? NULL : lines, "\n")) { for(pos = 0; line[pos]; pos++) { if(line[pos] == '=') break; } if(line[pos]) { line[pos++] = 0; if(!(cv = cvar_get(line))) { loge(LOG_SYS, STR_CVAR_UNKNOWN, line); continue; } if(sys.log_set != 0xff && cv->data == &sys.log_level) { if(str_parse_enum(line+pos, (const char**)cv->aux_data, cv->max, &cv->value)) sys.log_set = (byte)cv->value; else loge(LOG_SYS, STR_CVAR_INVALID, cv->name, line+pos); cv->value = (int)sys.log_level; continue; } if(cvar_set(cv, line+pos, 1)) { cvar_format(cv, str); logt(LOG_SYS, "%s = %s", cv->name, str); } else { loge(LOG_SYS, STR_CVAR_INVALID, cv->name, line+pos); } } } mem_free(lines); return 1; } byte cvar_save() { char str[64]; cvar_t *cv; FILE *fd; int err; if(!(fd = fopen(sys.cfg_file, "wb"))) { err = errno; loge(LOG_IO, STR_CVAR_EWOPEN, sys.cfg_file, strerror(err), err); return 0; } for(int z = 0; z < sys.n_cvars; z++) { cv = &sys.cvars[z]; if(sys.log_set != 0xff && cv->data == &sys.log_level) sprintf(str, "%s", ((const char**)cv->aux_data)[sys.log_set]); else cvar_format(cv, str); fprintf(fd, "%s=%s\n", cv->name, str); } fclose(fd); return 1; } void cvar_init() { cvar_t *cv; tbl_init(&sys.themes, 32, 1, sizeof(style_t), MEM_SYSTEM); theme_reg(); cvar_reg(); smap_init(&sys.cvar_map, 1, MEM_SYSTEM); for(int z = 0; z < sys.n_cvars; z++) { cv = &sys.cvars[z]; smap_put(&sys.cvar_map, cv->name, cv); } cvar_load(); } void cvar_end() { cvar_save(); smap_clear(&sys.cvar_map); tbl_clear(&sys.themes); } const char *cvar_getbind(byte bind) { return STR_BIND_QUIT + (LOCALE_ELEM * bind); } const char *cvar_getkey(int key, char *buf) { if(key == 0) { return "---"; } else if(key >= -SCROLL_RIGHT && key <= -MOUSE_LEFT) { return STR_KEY_MOUSE_LEFT + (LOCALE_ELEM * -(key + MOUSE_LEFT)); } else if(key >= KEYSYM_0 && key <= KEYSYM_9) { sprintf(buf, "<%d>", key - KEYSYM_0); return buf; } else if(key >= KEYSYM_A && key <= KEYSYM_Z) { sprintf(buf, "<%c>", 'A' + (char)(key - KEYSYM_A)); return buf; } else if(key >= KEYSYM_F1 && key <= KEYSYM_F12) { sprintf(buf, "F%d", 1 + key - KEYSYM_F1); return buf; } else if(key >= KEYSYM_KP_0 && key <= KEYSYM_KP_9) { sprintf(buf, "#%d", key - KEYSYM_KP_0); return buf; } else if(key >= KEYSYM_FIRST && key <= KEYSYM_LAST) { return STR_KEY_SPACE + (LOCALE_ELEM * (key - KEYSYM_FIRST)); } else { sprintf(buf, "[%d]", key); return buf; } }