Improved texture handling

This commit is contained in:
John Alanbrook 2022-08-25 20:48:15 +00:00
parent 3040dc1f7f
commit ff4168d279
11 changed files with 227 additions and 142 deletions

View file

@ -61,12 +61,10 @@ void asset_srch_cb(GLFWwindow *win, unsigned int codepoint)
static const char *editor_filename = "editor.ini"; static const char *editor_filename = "editor.ini";
struct asset { static struct {
char *key; char *key;
struct fileasset *value; struct fileasset *value;
}; } *assets = NULL;
static struct asset *assets = NULL;
static char asset_search_buffer[100] = {'\0'}; static char asset_search_buffer[100] = {'\0'};
@ -99,31 +97,6 @@ static const char *get_extension(const char *filepath) {
return strrchr(filepath, '.'); return strrchr(filepath, '.');
} }
static int check_if_resource(const char *fpath, const struct stat *sb, int typeflag) {
if (typeflag != FTW_F)
return 0;
const char *ext = get_extension(fpath);
if (ext && is_allowed_extension(ext)) {
struct fileasset *newasset = calloc(1, sizeof(struct fileasset));
newasset->filename = malloc(sizeof(char) * strlen(fpath) + 1);
strcpy(newasset->filename, fpath);
newasset->extension_len = strlen(ext);
newasset->searched = true;
shput(assets, newasset->filename, newasset);
}
return 0;
}
static void print_files_in_directory(const char *dirpath) {
shfree(assets);
ftw(dirpath, check_if_resource, 10);
}
static void get_all_files() { print_files_in_directory("."); }
size_t asset_side_size(struct fileasset *asset) { size_t asset_side_size(struct fileasset *asset) {
if (asset->type == ASSET_TYPE_IMAGE) if (asset->type == ASSET_TYPE_IMAGE)
return sizeof(struct Texture); return sizeof(struct Texture);
@ -131,38 +104,89 @@ size_t asset_side_size(struct fileasset *asset) {
return 0; return 0;
} }
void save_asset() { void save_asset(struct fileasset *asset) {
if (selected_asset == NULL) { if (asset == NULL) {
YughWarn("No asset to save.", 0); YughWarn("No asset to save.", 0);
return; return;
} }
if (selected_asset->type != ASSET_TYPE_IMAGE) return; if (asset->type != ASSET_TYPE_IMAGE) return;
FILE *f = res_open(str_replace_ext(selected_asset->filename, EXT_ASSET), "w"); FILE *f = res_open(str_replace_ext(asset->filename, EXT_ASSET), "w");
fwrite(selected_asset->data, asset_side_size(selected_asset), 1, f); fwrite(asset->data, asset_side_size(asset), 1, f);
fclose(f); fclose(f);
} }
void load_asset() { void load_asset(struct fileasset *asset) {
if (selected_asset == NULL) { if (asset == NULL) {
YughWarn("No asset to load.", 0); YughWarn("No asset to load.", 0);
return; return;
} }
if (selected_asset->type != ASSET_TYPE_IMAGE) return; if (asset->type != ASSET_TYPE_IMAGE)
return;
if (selected_asset->data == NULL) if (asset->data == NULL)
selected_asset->data = malloc(asset_side_size(selected_asset)); asset->data = malloc(asset_side_size(asset));
FILE *f = res_open(str_replace_ext(selected_asset->filename, EXT_ASSET), "r"); FILE *f = res_open(str_replace_ext(asset->filename, EXT_ASSET), "r");
if (f == NULL) if (f == NULL)
return; return;
fread(selected_asset->data, asset_side_size(selected_asset), 1, f); struct Texture tex;
struct Texture *asset_tex = asset->data;
fread(&tex, asset_side_size(asset), 1, f);
asset_tex->opts = tex.opts;
asset_tex->anim = tex.anim;
fclose(f); fclose(f);
} }
static int check_if_resource(const char *fpath, const struct stat *sb, int typeflag) {
if (typeflag != FTW_F)
return 0;
const char *ext = get_extension(fpath);
if (ext && is_allowed_extension(ext)) {
struct fileasset *newasset = calloc(1, sizeof(struct fileasset));
newasset->searched = true;
if (!strcmp(ext+1, "png") || !strcmp(ext+1, "jpg"))
newasset->type = ASSET_TYPE_IMAGE;
else if (!strcmp(ext+1, "rb"))
newasset->type = ASSET_TYPE_TEXT;
else if (!strcmp(ext+1, "wav") || !strcmp(ext+1, "mp3"))
newasset->type = ASSET_TYPE_SOUND;
else
newasset->type = ASSET_TYPE_NULL;
newasset->filename = strdup(fpath);
shput(assets, newasset->filename, newasset);
}
return 0;
}
static void print_files_in_directory(const char *dirpath) {
struct fileasset *n = NULL;
for (int i = 0; i < shlen(assets); i++) {
free(assets[i].key);
free(assets[i].value);
}
shfree(assets);
ftw(dirpath, check_if_resource, 10);
}
static void get_all_files() { print_files_in_directory("."); }
static int *compute_prefix_function(const char *str) { static int *compute_prefix_function(const char *str) {
int str_len = strlen(str); int str_len = strlen(str);
int *pi = (int *)malloc(sizeof(int) * str_len); int *pi = (int *)malloc(sizeof(int) * str_len);
@ -422,6 +446,8 @@ void editor_init(struct mSDLWindow *window) {
//glfwSetCharCallback(window->window, text_ed_cb); //glfwSetCharCallback(window->window, text_ed_cb);
//glfwSetCharCallback(window->window, asset_srch_cb); //glfwSetCharCallback(window->window, asset_srch_cb);
get_all_files();
} }
int editor_wantkeyboard() { int editor_wantkeyboard() {
@ -495,17 +521,14 @@ void editor_project_gui() {
vec_walk(levels, editor_level_btn); vec_walk(levels, editor_level_btn);
NK_MENU_END() NK_MENU_END()
if (editor.export.show) { NK_MENU_START(export)
nk_begin(ctx, "Export and Bake", editor.export.rect, nuk_std);
nk_layout_row_dynamic(ctx, 25,2); nk_layout_row_dynamic(ctx, 25,2);
if (nk_button_label(ctx, "Bake")) { if (nk_button_label(ctx, "Bake")) {
} }
if (nk_button_label(ctx, "Build")) { if (nk_button_label(ctx, "Build")) {
} }
nk_end(ctx); NK_MENU_END()
}
// Shadow map vars // Shadow map vars
NK_MENU_START(lighting) NK_MENU_START(lighting)
@ -645,8 +668,8 @@ void editor_project_gui() {
if (!assets[i].value->searched) if (!assets[i].value->searched)
continue; continue;
if (nk_button_label(ctx, assets[i].value->filename + stemlen)) { if (nk_button_label(ctx, assets[i].key)) {
editor_selectasset(assets[i].value); editor_selectasset_str(assets[i].key);
} }
} }
@ -712,8 +735,18 @@ startobjectgui:
object_gui(selectedobject); object_gui(selectedobject);
// nuke_label("Components");
nk_layout_row_dynamic(ctx,25,3);
for (int i = 0; i < ncomponent; i++) {
if (nk_button_label(ctx, components[i].name)) {
gameobject_addcomponent(selectedobject, &components[i]);
}
}
NK_FORCE_END() NK_FORCE_END()
/*
NK_FORCE(components) NK_FORCE(components)
nk_layout_row_dynamic(ctx,25,1); nk_layout_row_dynamic(ctx,25,1);
for (int i = 0; i < ncomponent; i++) { for (int i = 0; i < ncomponent; i++) {
@ -723,6 +756,7 @@ startobjectgui:
} }
NK_FORCE_END() NK_FORCE_END()
*/
} }
} }
@ -754,43 +788,62 @@ void editor_level_btn(char *level) {
} }
} }
void editor_selectasset(struct fileasset *asset) { struct fileasset *asset_from_path(const char *p)
const char *ext = get_extension(asset->filename); {
return shget(assets, p);
if (!strcmp(ext + 1, "png") || !strcmp(ext + 1, "jpg")) {
asset->data = texture_loadfromfile(asset->filename);
tex_gui_anim.tex = asset->data;
asset->type = ASSET_TYPE_IMAGE;
tex_anim_set(&tex_gui_anim);
float tex_scale = (float) ASSET_WIN_SIZE / (float)tex_gui_anim.tex->width;
if (tex_scale >= 10.f)
tex_scale = 10.f;
} else if (!strcmp(ext + 1, "rb")) {
asset->type = ASSET_TYPE_TEXT;
FILE *fasset = fopen(asset->filename, "rb");
fseek(fasset, 0, SEEK_END);
long length = ftell(fasset);
fseek(fasset, 0, SEEK_SET);
asset->data = malloc(ASSET_TEXT_BUF);
fread(asset->data, 1, length, fasset);
fclose(fasset);
}
if (selected_asset != NULL)
save_asset();
selected_asset = asset;
load_asset();
} }
void editor_selectasset_str(char *path) { void editor_selectasset_str(const char *path) {
struct fileasset *asset = shget(assets, path); struct fileasset *asset = asset_from_path(path);
FILE *fasset;
switch (asset->type) {
case ASSET_TYPE_IMAGE:
if (asset->data == NULL) {
asset->data = texture_loadfromfile(path);
load_asset(asset);
}
else
tex_pull(asset->data);
tex_gui_anim.tex = asset->data;
tex_anim_set(&tex_gui_anim);
anim_setframe(&tex_gui_anim, 0);
float tex_scale = (float) ASSET_WIN_SIZE / (float)tex_gui_anim.tex->width;
if (tex_scale >= 10.f) {
tex_scale = 10.f;
}
break;
case ASSET_TYPE_TEXT:
fasset = fopen(asset->filename, "rb");
fseek(fasset, 0, SEEK_END);
long length = ftell(fasset);
fseek(fasset, 0, SEEK_SET);
asset->data = malloc(ASSET_TEXT_BUF);
fread(asset->data, 1, length, fasset);
fclose(fasset);
break;
case ASSET_TYPE_SOUND:
break;
default:
break;
}
load_asset(asset);
if (selected_asset != NULL)
save_asset(selected_asset);
selected_asset = asset;
if (asset)
editor_selectasset(asset);
} }
void editor_asset_tex_gui(struct Texture *tex) { void editor_asset_tex_gui(struct Texture *tex) {
@ -803,16 +856,19 @@ void editor_asset_tex_gui(struct Texture *tex) {
if (old_sprite != tex->opts.sprite) if (old_sprite != tex->opts.sprite)
tex_gpu_load(tex); tex_gpu_load(tex);
nuke_nel(4);
nuke_radio_btn("Raw", &tex_view, 0); nuke_radio_btn("Raw", &tex_view, 0);
nuke_radio_btn("View 1", &tex_view, 1); nuke_radio_btn("View 1", &tex_view, 1);
nuke_radio_btn("View 2", &tex_view, 2); nuke_radio_btn("View 2", &tex_view, 2);
nuke_checkbox("Animation", &tex->opts.animation); nuke_checkbox("Animation", &tex->opts.animation);
if (tex->opts.animation) { if (tex->opts.animation) {
int old_frames = tex->anim.frames; int old_frames = tex->anim.frames;
int old_ms = tex->anim.ms; int old_ms = tex->anim.ms;
nuke_nel(2);
nuke_property_int("Frames", 1, &tex->anim.frames, 20, 1); nuke_property_int("Frames", 1, &tex->anim.frames, 20, 1);
nuke_property_int("FPS", 1, &tex->anim.ms, 24, 1); nuke_property_int("FPS", 1, &tex->anim.ms, 24, 1);
@ -822,6 +878,7 @@ void editor_asset_tex_gui(struct Texture *tex) {
if (tex_gui_anim.playing && nuke_btn("Stop")) if (tex_gui_anim.playing && nuke_btn("Stop"))
anim_stop(&tex_gui_anim); anim_stop(&tex_gui_anim);
} else { } else {
nuke_nel(3);
if (nuke_btn("Play")) if (nuke_btn("Play"))
anim_play(&tex_gui_anim); anim_play(&tex_gui_anim);
@ -832,6 +889,7 @@ void editor_asset_tex_gui(struct Texture *tex) {
anim_fwd(&tex_gui_anim); anim_fwd(&tex_gui_anim);
} }
nuke_nel(1);
nuke_labelf("Frame %d/%d", tex_gui_anim.frame+1, tex_gui_anim.tex->anim.frames); nuke_labelf("Frame %d/%d", tex_gui_anim.frame+1, tex_gui_anim.tex->anim.frames);
if (old_frames != tex->anim.frames || old_ms != tex->anim.ms) if (old_frames != tex->anim.frames || old_ms != tex->anim.ms)
@ -876,6 +934,11 @@ void editor_asset_text_gui(char *text) {
/* TODO: Nicer formatting for text input. Auto indent. */ /* TODO: Nicer formatting for text input. Auto indent. */
} }
void editor_asset_sound_gui(struct wav *wav)
{
}
void editor_asset_gui(struct fileasset *asset) { void editor_asset_gui(struct fileasset *asset) {
NK_FORCE(asset) NK_FORCE(asset)
@ -898,6 +961,10 @@ void editor_asset_gui(struct fileasset *asset) {
case ASSET_TYPE_TEXT: case ASSET_TYPE_TEXT:
editor_asset_text_gui(asset->data); editor_asset_text_gui(asset->data);
break; break;
case ASSET_TYPE_SOUND:
editor_asset_sound_gui(asset->data);
break;
} }
NK_FORCE_END() NK_FORCE_END()

View file

@ -10,11 +10,10 @@
#define ASSET_TYPE_NULL 0 #define ASSET_TYPE_NULL 0
#define ASSET_TYPE_IMAGE 1 #define ASSET_TYPE_IMAGE 1
#define ASSET_TYPE_TEXT 2 #define ASSET_TYPE_TEXT 2
#define ASSET_TYPE_SOUND 3
struct fileasset { struct fileasset {
char *filename; char *filename;
short extension_len;
short filename_len;
bool searched; bool searched;
short type; short type;
void *data; // Struct of the underlying asset - Texture struct, etc void *data; // Struct of the underlying asset - Texture struct, etc
@ -88,7 +87,7 @@ void editor_makenewobject();
void editor_project_gui(); void editor_project_gui();
void editor_selectasset(struct fileasset *asset); void editor_selectasset(struct fileasset *asset);
void editor_selectasset_str(char *path); void editor_selectasset_str(const char *path);
void editor_asset_gui(struct fileasset *asset); void editor_asset_gui(struct fileasset *asset);
void editor_asset_tex_gui(struct Texture *tex); void editor_asset_tex_gui(struct Texture *tex);
void editor_asset_text_gui(char *text); void editor_asset_text_gui(char *text);

View file

@ -62,7 +62,6 @@ void engine_init()
script_init(); script_init();
registry_init(); registry_init();
init_gameobjects(); init_gameobjects();
timer_init();
prefabs = vec_make(MAXNAME, 25); prefabs = vec_make(MAXNAME, 25);
stbi_set_flip_vertically_on_load(1); stbi_set_flip_vertically_on_load(1);

View file

@ -243,21 +243,25 @@ void object_gui(struct mGameObject *go)
int n = -1; int n = -1;
for (int i = 0; i < go->components->len; i++) { for (int i = 0; i < go->components->len; i++) {
struct component *c = vec_get(go->components, i); struct component *c = vec_get(go->components, i);
if (c->draw_debug) if (c->draw_debug)
c->draw_debug(c->data); c->draw_debug(c->data);
if (nk_tree_push(ctx, NK_TREE_NODE, c->name, NK_MINIMIZED)) {
if (nk_button_label(ctx, "Del")) { nuke_nel(5);
n = i; if (nk_button_label(ctx, "Del")) n = i;
} if (nk_tree_push_id(ctx, NK_TREE_NODE, c->name, NK_MINIMIZED, i)) {
c->draw_gui(c->data); c->draw_gui(c->data);
nk_tree_pop(ctx); nk_tree_pop(ctx);
} }
} }
if (n >= 0) if (n >= 0)

View file

@ -69,11 +69,12 @@ void nuke_property_int(const char *lbl, int min, int *val, int max, int step) {
} }
void nk_radio_button_label(struct nk_context *ctx, const char *label, int *val, int cmp) { void nk_radio_button_label(struct nk_context *ctx, const char *label, int *val, int cmp) {
if (nk_option_label(ctx, label, (bool)*val == cmp)) *val = cmp; if (nk_option_label(ctx, label, *val == cmp)) *val = cmp;
} }
void nuke_radio_btn(const char *lbl, int *val, int cmp) { void nuke_radio_btn(const char *lbl, int *val, int cmp) {
nk_radio_button_label(ctx, lbl, val, cmp); //nk_radio_button_label(ctx, lbl, val, cmp);
if (nk_option_label(ctx, lbl, *val==cmp)) *val = cmp;
} }
void nuke_checkbox(const char *lbl, int *val) { void nuke_checkbox(const char *lbl, int *val) {

View file

@ -128,3 +128,10 @@ char *make_path(const char *file)
strncat(pathbuf, file, MAXPATH); strncat(pathbuf, file, MAXPATH);
return pathbuf; return pathbuf;
} }
char *strdup(const char *s)
{
char *new = malloc(sizeof(char)*(strlen(s)+1));
strcpy(new, s);
return new;
}

View file

@ -27,4 +27,6 @@ FILE *res_open(char *path, const char *tag);
FILE *path_open(const char *tag, const char *fmt, ...); FILE *path_open(const char *tag, const char *fmt, ...);
char *make_path(const char *file); char *make_path(const char *file);
char *strdup(const char *s);
#endif #endif

View file

@ -21,9 +21,6 @@ struct Texture *texture_pullfromfile(const char *path)
struct Texture *tex = calloc(1, sizeof(*tex)); struct Texture *tex = calloc(1, sizeof(*tex));
/* tex->path = malloc(strlen(path) + 1);
strncpy(tex->path, path, strlen(path) + 1);
*/
tex->flipy = 0; tex->flipy = 0;
tex->opts.sprite = 1; tex->opts.sprite = 1;
tex->opts.gamma = 0; tex->opts.gamma = 0;
@ -34,11 +31,8 @@ struct Texture *texture_pullfromfile(const char *path)
stbi_set_flip_vertically_on_load(0); stbi_set_flip_vertically_on_load(0);
unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4); unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4);
if (stbi_failure_reason()) { if (stbi_failure_reason())
YughLog(0, 3, "STBI failed to load file %s with message: %s", YughLog(0, 3, "STBI failed to load file %s with message: %s", path, stbi_failure_reason());
path, stbi_failure_reason());
}
tex->data = data; tex->data = data;
@ -71,6 +65,9 @@ struct Texture *texture_loadfromfile(const char *path)
void tex_pull(struct Texture *tex) void tex_pull(struct Texture *tex)
{ {
if (tex->data != NULL)
tex_flush(tex);
int n; int n;
char *path = tex_get_path(tex); char *path = tex_get_path(tex);
stbi_set_flip_vertically_on_load(0); stbi_set_flip_vertically_on_load(0);
@ -139,6 +136,12 @@ void anim_decr(struct TexAnimation *anim)
tex_anim_calc_uv(anim); tex_anim_calc_uv(anim);
} }
void anim_setframe(struct TexAnimation *anim, int frame)
{
anim->frame = frame;
tex_anim_calc_uv(anim);
}
void tex_anim_set(struct TexAnimation *anim) void tex_anim_set(struct TexAnimation *anim)
{ {
if (anim->playing) { if (anim->playing) {

View file

@ -41,7 +41,6 @@ struct TextureOptions {
struct Texture { struct Texture {
int type; int type;
unsigned int id; unsigned int id;
//char *path;
int width; int width;
int height; int height;
short flipy; short flipy;
@ -51,21 +50,20 @@ struct Texture {
struct TexAnim anim; struct TexAnim anim;
}; };
struct Texture *texture_pullfromfile(const char *path); struct Texture *texture_pullfromfile(const char *path); // Create texture from image
struct Texture *texture_loadfromfile(const char *path); struct Texture *texture_loadfromfile(const char *path); // Create texture & load to gpu
void tex_gpu_load(struct Texture *tex); void tex_gpu_load(struct Texture *tex); // Send texture data to gpu
void tex_gpu_reload(struct Texture *tex); void tex_gpu_reload(struct Texture *tex); // gpu_free then gpu_load
void tex_gpu_free(struct Texture *tex); void tex_gpu_free(struct Texture *tex); // Remove texture data from gpu
void tex_free(struct Texture *tex); void tex_free(struct Texture *tex); // Delete struct
void tex_flush(struct Texture *tex); void tex_flush(struct Texture *tex); // Remove pixel data from struct
void tex_pull(struct Texture *tex); void tex_pull(struct Texture *tex); // Pull pixel data from image
void tex_bind(struct Texture *tex); void tex_bind(struct Texture *tex); // Bind to gl context
unsigned int powof2(unsigned int num);
int ispow2(int num);
char * tex_get_path(struct Texture *tex); char * tex_get_path(struct Texture *tex); // Get image path for texture
void anim_play(struct TexAnimation *anim); void anim_play(struct TexAnimation *anim);
void anim_setframe(struct TexAnimation *anim, int frame);
void anim_stop(struct TexAnimation *anim); void anim_stop(struct TexAnimation *anim);
void anim_pause(struct TexAnimation *anim); void anim_pause(struct TexAnimation *anim);
void anim_fwd(struct TexAnimation *anim); void anim_fwd(struct TexAnimation *anim);

View file

@ -1,16 +1,12 @@
#include "timer.h" #include "timer.h"
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stdlib.h> #include <stdlib.h>
#include "vec.h"
#include <stb_ds.h>;
static double time; static double time;
struct vec timers; struct timer *timers;
void timer_init() {
time = glfwGetTime();
timers = vec_init(sizeof(struct timer), 10);
}
void check_timer(struct timer *t) void check_timer(struct timer *t)
{ {
@ -33,51 +29,60 @@ void check_timer(struct timer *t)
void timer_update(double s) { void timer_update(double s) {
time = s; time = s;
vec_walk(&timers, check_timer);
for (int i = 0; i < arrlen(timers); i++)
check_timer(&timers[i]);
} }
struct timer *timer_make(double interval, void (*callback)(void *param), void *param) { struct timer *timer_make(double interval, void (*callback)(void *param), void *param) {
struct timer *new = calloc(sizeof(*new),1); struct timer new;
new.remain_time = interval;
new.interval = interval;
new.cb = callback;
new.data = param;
new.repeat = 1;
new.timerid = arrlen(timers);
new->remain_time = interval; timer_start(&new);
new->interval = interval; arrput(timers, new);
new->cb = callback;
new->data = param;
new->repeat = 1;
timer_start(new); return &arrlast(timers);
struct timer *nn = vec_add(&timers, new);
free(new);
nn->timerid = timers.len-1;
return nn;
} }
void timer_pause(struct timer *t) { void timer_pause(struct timer *t) {
if (!t->on) return;
t->on = 0; t->on = 0;
t->remain_time = t->fire_time - time; t->remain_time = t->fire_time - time;
} }
void timer_stop(struct timer *t) { void timer_stop(struct timer *t) {
if (!t->on) return;
t->on = 0; t->on = 0;
t->remain_time = t->interval; t->remain_time = t->interval;
} }
void timer_start(struct timer *t) { void timer_start(struct timer *t) {
if (t->on) return;
t->on = 1; t->on = 1;
t->fire_time = time + t->remain_time; t->fire_time = time + t->remain_time;
} }
void timer_remove(struct timer *t) { void timer_remove(struct timer *t) {
vec_delete(&timers, t->timerid); int i = t->timerid;
arrdelswap(timers, i);
timers[i].timerid = i;
} }
void timer_settime(struct timer *t, double interval) { void timer_settime(struct timer *t, double interval) {
double elapsed = time - (t->fire_time - t->interval); //double elapsed = time - (t->fire_time - t->interval);
t->interval = interval; t->interval = interval;
t->remain_time = time + t->interval - elapsed; t->remain_time = t->interval;
// TODO: timer_settime reacts to elapsed time
} }

View file

@ -4,15 +4,15 @@
struct timer { struct timer {
int timerid; int timerid;
int on; int on;
double fire_time; double fire_time; // Time the timer will fire
double interval; double interval; // Time of timer
double start_time; // Time the timer started this loop
int repeat; int repeat;
double remain_time; double remain_time; // How much time until the timer executes
void (*cb)(void *data); void (*cb)(void *data);
void *data; void *data;
}; };
void timer_init();
struct timer *timer_make(double interval, void (*callback)(void *param), void *param); struct timer *timer_make(double interval, void (*callback)(void *param), void *param);
void timer_remove(struct timer *t); void timer_remove(struct timer *t);
void timer_start(struct timer *t); void timer_start(struct timer *t);