From 9983ff2bc9086ffaf9aa50736172c50543764abe Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Mon, 24 May 2021 12:36:55 -0700 Subject: [PATCH] Implement GoatGUIEngine text rendering --- src/audio.c | 1 - src/hll/GoatGUIEngine.c | 530 ++++++++++++++++++++++++++++++++-------- 2 files changed, 425 insertions(+), 106 deletions(-) diff --git a/src/audio.c b/src/audio.c index 5f4eae0..bf98d47 100644 --- a/src/audio.c +++ b/src/audio.c @@ -148,7 +148,6 @@ void audio_update(void) for (int i = 0; i < NR_ANONYMOUS_CHANNELS; i++) { if (anonymous_channels[i] >= 0) { if (!wav_is_playing(anonymous_channels[i])) { - NOTICE("FREEING CHANNEL"); wav_unprepare(anonymous_channels[i]); anonymous_channels[i] = -1; } diff --git a/src/hll/GoatGUIEngine.c b/src/hll/GoatGUIEngine.c index 7572087..2e38a50 100644 --- a/src/hll/GoatGUIEngine.c +++ b/src/hll/GoatGUIEngine.c @@ -18,6 +18,8 @@ #include "system4/cg.h" #include "system4/hashtable.h" +#include "system4/string.h" +#include "system4/utfsjis.h" #include #include "asset_manager.h" @@ -81,21 +83,50 @@ struct parts_motion { int end_time; }; -struct parts_state { +struct parts_text_line { + unsigned height; +}; + +enum parts_type { + PARTS_CG, + PARTS_TEXT, + PARTS_ANIMATION, +}; + +struct parts_cg { + Texture texture; + int no; +}; + +struct parts_text { + Texture texture; + unsigned nr_lines; + struct parts_text_line *lines; + unsigned char_space; + unsigned line_space; + Point cursor; + struct text_metrics tm; +}; + +struct parts_animation { Texture texture; unsigned cg_no; - // If there's a CG loop animation set up, the textures are stored in - // `frames` and the current texture is copied into `texture`. unsigned nr_frames; Texture *frames; - // The length of each frame unsigned frame_time; - // The time elapsed since the last frame unsigned elapsed; - // Index of the current frame unsigned current_frame; }; +struct parts_state { + enum parts_type type; + union { + struct parts_cg cg; + struct parts_text text; + struct parts_animation anim; + }; +}; + struct parts { struct sprite sp; enum parts_state_type state; @@ -132,15 +163,34 @@ static int click_down_parts = 0; // the mouse position at last update static Point prev_pos = {0}; +// true after call to BeginMotion until the motion ends or EndMotion is called +static bool is_motion = false; +// the elapsed time of the current motion +static int motion_t = 0; +// the end time of the current motion +static int motion_end_t = 0; + static bool GoatGUIEngine_Init(void) { parts_table = ht_create(1024); return 1; } -static struct parts *parts_alloc(void) +static struct text_metrics default_text_metrics = { + .color = { .r = 255, .g = 255, .b = 255, .a = 255 }, + .outline_color = { .r = 0, .g = 0, .b = 0, .a = 255 }, + .size = 16, + .weight = FW_NORMAL, + .face = FONT_GOTHIC, + .outline_left = 0, + .outline_up = 0, + .outline_right = 0, + .outline_down = 0, +}; + +static void parts_init(struct parts *parts) { - struct parts *parts = xcalloc(1, sizeof(struct parts)); + memset(parts, 0, sizeof(struct parts)); parts->on_cursor_sound = -1; parts->on_click_sound = -1; parts->origin_mode = 1; @@ -153,6 +203,12 @@ static struct parts *parts_alloc(void) parts->sp.z2 = 2; parts->sp.render = parts_render; TAILQ_INIT(&parts->motion); +} + +static struct parts *parts_alloc(void) +{ + struct parts *parts = xcalloc(1, sizeof(struct parts)); + parts_init(parts); return parts; } @@ -169,9 +225,54 @@ static struct parts *parts_get(int parts_no) return parts; } -possibly_unused static struct parts *parts_try_get(int parts_no) +static void parts_state_free(struct parts_state *state) { - return ht_get_int(parts_table, parts_no, NULL); + switch (state->type) { + case PARTS_CG: + gfx_delete_texture(&state->cg.texture); + break; + case PARTS_TEXT: + free(state->text.lines); + break; + case PARTS_ANIMATION: + for (unsigned i = 0; i < state->anim.nr_frames; i++) { + gfx_delete_texture(&state->anim.frames[i]); + } + break; + } +} + +static void parts_state_reset(struct parts_state *state, enum parts_type type) +{ + parts_state_free(state); + state->type = type; + if (type == PARTS_TEXT) { + state->text.tm = default_text_metrics; + } +} + +static struct parts_cg *parts_get_cg(struct parts *parts, int state) +{ + if (parts->states[state].type != PARTS_CG) { + parts_state_reset(&parts->states[state], PARTS_CG); + } + return &parts->states[state].cg; +} + +static struct parts_text *parts_get_text(struct parts *parts, int state) +{ + if (parts->states[state].type != PARTS_TEXT) { + parts_state_reset(&parts->states[state], PARTS_TEXT); + } + return &parts->states[state].text; +} + +static struct parts_animation *parts_get_animation(struct parts *parts, int state) +{ + if (parts->states[state].type != PARTS_ANIMATION) { + parts_state_reset(&parts->states[state], PARTS_ANIMATION); + } + return &parts->states[state].anim; } static struct parts_motion *parts_motion_alloc(enum parts_motion_type type, int begin_time, int end_time) @@ -202,17 +303,7 @@ static void parts_clear(struct parts *parts) parts_clear_motion(parts); scene_unregister_sprite(&parts->sp); for (int i = 0; i < PARTS_NR_STATES; i++) { - struct parts_state *state = &parts->states[i]; - if (state->nr_frames) { - for (unsigned i = 0; i < state->nr_frames; i++) { - gfx_delete_texture(&state->frames[i]); - } - free(state->frames); - state->frames = NULL; - state->nr_frames = 0; - } else { - gfx_delete_texture(&state->texture); - } + parts_state_free(&parts->states[i]); } } @@ -237,10 +328,6 @@ static void parts_release_all(void) } } -static bool is_motion = false; -static int motion_t = 0; -static int motion_end_t = 0; - static void parts_add_motion(struct parts *parts, struct parts_motion *motion) { struct parts_motion *p; @@ -371,7 +458,20 @@ static void parts_set_alpha(struct parts *parts, int alpha) { parts->alpha = max(0, min(255, alpha)); for (int i = 0; i < PARTS_NR_STATES; i++) { - parts->states[i].texture.alpha_mod = parts->alpha; + struct parts_state *s = &parts->states[i]; + switch (s->type) { + case PARTS_CG: + s->cg.texture.alpha_mod = parts->alpha; + break; + case PARTS_TEXT: + s->text.texture.alpha_mod = parts->alpha; + break; + case PARTS_ANIMATION: + for (unsigned i = 0; i < s->anim.nr_frames; i++) { + s->anim.frames[i].alpha_mod = parts->alpha; + } + break; + } } scene_sprite_dirty(&parts->sp); } @@ -384,12 +484,13 @@ static void parts_set_state(struct parts *parts, enum parts_state_type state) } } -static void parts_render(struct sprite *sp) +static void parts_render_text(struct parts *parts) { - struct parts *parts = (struct parts*)sp; - if (!parts->states[parts->state].cg_no) - return; + gfx_render_texture(&parts->states[parts->state].text.texture, &parts->rect); +} +static void parts_render_cg(struct parts *parts, Texture *t) +{ Rectangle *d = &parts->rect; mat4 mw_transform = GLM_MAT4_IDENTITY_INIT; glm_translate(mw_transform, (vec3) { d->x, d->y, 0 }); @@ -405,15 +506,31 @@ static void parts_render(struct sprite *sp) struct gfx_render_job job = { .shader = NULL, // default shader - .texture = parts->states[parts->state].texture.handle, + .texture = t->handle, .world_transform = mw_transform[0], .view_transform = wv_transform[0], - .data = &parts->states[parts->state].texture, + .data = t, }; gfx_render(&job); } +static void parts_render(struct sprite *sp) +{ + struct parts *parts = (struct parts*)sp; + switch (parts->states[parts->state].type) { + case PARTS_CG: + parts_render_cg(parts, &parts->states[parts->state].cg.texture); + break; + case PARTS_TEXT: + parts_render_text(parts); + break; + case PARTS_ANIMATION: + parts_render_cg(parts, &parts->states[parts->state].anim.texture); + break; + } +} + static void parts_update_with_motion(struct parts *parts, struct parts_motion *motion) { switch (motion->type) { @@ -492,21 +609,58 @@ static void parts_fini_all_motion(void) static void parts_update_loop(struct parts *parts, int passed_time) { - struct parts_state *state = &parts->states[parts->state]; - if (passed_time <= 0 || !state->nr_frames) + if (parts->states[parts->state].type != PARTS_ANIMATION) return; - const unsigned elapsed = state->elapsed + passed_time; - const unsigned frame_diff = elapsed / state->frame_time; - const unsigned remainder = elapsed % state->frame_time; + struct parts_animation *anim = &parts->states[parts->state].anim; + if (passed_time <= 0 || !anim->nr_frames) + return; + + const unsigned elapsed = anim->elapsed + passed_time; + const unsigned frame_diff = elapsed / anim->frame_time; + const unsigned remainder = elapsed % anim->frame_time; if (frame_diff > 0) { - state->elapsed = remainder; - state->current_frame = (state->current_frame + frame_diff) % state->nr_frames; - state->texture = state->frames[state->current_frame]; + anim->elapsed = remainder; + anim->current_frame = (anim->current_frame + frame_diff) % anim->nr_frames; + anim->texture = anim->frames[anim->current_frame]; scene_sprite_dirty(&parts->sp); } else { - state->elapsed = elapsed; + anim->elapsed = elapsed; + } +} + +static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clicking) +{ + if (!began_click || !parts->clickable) + return; + + bool prev_in = SDL_PointInRect(&prev_pos, &parts->pos); + bool cur_in = SDL_PointInRect(&cur_pos, &parts->pos); + + if (!cur_in) { + parts_set_state(parts, PARTS_STATE_DEFAULT); + return; + } + + // click down: just remember the parts number for later + if (cur_clicking && !prev_clicking) { + click_down_parts = parts->no; + } + + if (cur_clicking && click_down_parts == parts->no) { + parts_set_state(parts, PARTS_STATE_CLICKED); + } else { + if (!prev_in) { + audio_play_sound(parts->on_cursor_sound); + } + parts_set_state(parts, PARTS_STATE_HOVERED); + } + + // click event: only if the click down event had same parts number + if (prev_clicking && !cur_clicking && click_down_parts == parts->no) { + audio_play_sound(parts->on_click_sound); + clicked_parts = parts->no; } } @@ -521,32 +675,7 @@ static void GoatGUIEngine_Update(int passed_time, possibly_unused bool message_w struct parts *parts; TAILQ_FOREACH(parts, &parts_list, parts_list_entry) { parts_update_loop(parts, passed_time); - if (!parts->clickable) - continue; - bool prev_in = SDL_PointInRect(&prev_pos, &parts->pos); - bool cur_in = SDL_PointInRect(&cur_pos, &parts->pos); - - if (!cur_in) { - parts_set_state(parts, PARTS_STATE_DEFAULT); - continue; - } - // click down: just remember the parts number for later - if (cur_clicking && !prev_clicking) { - click_down_parts = parts->no; - } - if (cur_clicking && click_down_parts == parts->no) { - parts_set_state(parts, PARTS_STATE_CLICKED); - } else { - if (!prev_in) { - audio_play_sound(parts->on_cursor_sound); - } - parts_set_state(parts, PARTS_STATE_HOVERED); - } - // click event: only if the click down event had same parts number - if (prev_clicking && !cur_clicking && click_down_parts == parts->no) { - audio_play_sound(parts->on_click_sound); - clicked_parts = parts->no; - } + parts_update_mouse(parts, cur_pos, cur_clicking); } if (prev_clicking && !cur_clicking) { @@ -584,9 +713,10 @@ static bool GoatGUIEngine_SetPartsCG(int parts_no, int cg_no, possibly_unused in struct cg *cg = asset_cg_load(cg_no); if (!cg) return false; - gfx_delete_texture(&parts->states[state].texture); - gfx_init_texture_with_cg(&parts->states[state].texture, cg); - parts->states[state].cg_no = cg_no; + struct parts_cg *parts_cg = parts_get_cg(parts, state); + gfx_delete_texture(&parts_cg->texture); + gfx_init_texture_with_cg(&parts_cg->texture, cg); + parts_cg->no = cg_no; parts_add_cg(parts, cg); parts_recalculate_pos(parts); scene_sprite_dirty(&parts->sp); @@ -596,7 +726,13 @@ static bool GoatGUIEngine_SetPartsCG(int parts_no, int cg_no, possibly_unused in static int GoatGUIEngine_GetPartsCGNumber(int parts_no, int state) { - return parts_get(parts_no)->states[state].cg_no; + state--; + if (state < 0 || state > 2) { + WARNING("Invalid parts state: %d", state); + return false; + } + + return parts_get_cg(parts_get(parts_no), state)->no; } static bool GoatGUIEngine_SetLoopCG(int parts_no, int cg_no, int nr_frames, int frame_time, int state) @@ -625,44 +761,209 @@ static bool GoatGUIEngine_SetLoopCG(int parts_no, int cg_no, int nr_frames, int parts_add_cg(parts, cg); cg_free(cg); } - parts->states[state].frames = frames; - parts->states[state].nr_frames = nr_frames; - parts->states[state].frame_time = frame_time; - parts->states[state].elapsed = 0; - parts->states[state].current_frame = 0; - parts->states[state].texture = frames[0]; + + struct parts_animation *anim = parts_get_animation(parts, state); + anim->frames = frames; // free previous value? + anim->nr_frames = nr_frames; + anim->frame_time = frame_time; + anim->elapsed = 0; + anim->current_frame = 0; + anim->texture = frames[0]; return true; } -static bool GoatGUIEngine_SetText(int PartsNumber, struct string *pIText, int State) +static int extract_sjis_char(const char *src, char *dst) { - // TODO + if (SJIS_2BYTE(*src)) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = '\0'; + return 2; + } + dst[0] = src[0]; + dst[1] = '\0'; + return 1; +} + +static void parts_text_newline(struct parts_text *text) +{ + const unsigned height = text->lines[text->nr_lines-1].height; + text->cursor = POINT(0, text->cursor.y + height + text->line_space); + text->lines = xrealloc_array(text->lines, text->nr_lines, text->nr_lines+1, sizeof(struct parts_text_line)); + text->nr_lines++; +} + +static void parts_text_append(struct parts *parts, struct string *text, int state) +{ + struct parts_text *t = parts_get_text(parts, state); + + if (!t->texture.handle) { + gfx_init_texture_rgba(&t->texture, config.view_width, config.view_height, + (SDL_Color){ 0, 0, 0, 0 }); + } + + if (!t->nr_lines) { + t->lines = xcalloc(1, sizeof(struct parts_text_line)); + t->lines[0].height = 0; + t->nr_lines = 1; + } + + const char *msgp = text->text; + while (*msgp) { + char c[4]; + int len = extract_sjis_char(msgp, c); + msgp += len; + + if (c[0] == '\n') { + parts_text_newline(t); + continue; + } + + t->cursor.x += gfx_render_text(&t->texture, t->cursor, c, &t->tm, t->char_space); + + const unsigned old_height = t->lines[t->nr_lines-1].height; + const unsigned new_height = t->tm.size; + t->lines[t->nr_lines-1].height = max(old_height, new_height); + } +} + +static void parts_text_clear(struct parts *parts, int state) +{ + struct parts_text *text = parts_get_text(parts, state); + free(text->lines); + text->lines = NULL; + text->nr_lines = 0; + gfx_delete_texture(&text->texture); +} + +static bool GoatGUIEngine_SetText(int parts_no, struct string *text, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + struct parts *parts = parts_get(parts_no); + parts_text_clear(parts, state); + parts_text_append(parts, text, state); + return true; +} + +static bool GoatGUIEngine_AddPartsText(int parts_no, struct string *text, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + struct parts *parts = parts_get(parts_no); + parts_text_append(parts, text, state); return true; } -bool GoatGUIEngine_AddPartsText(int PartsNumber, struct string *pIText, int State); bool GoatGUIEngine_DeletePartsTopTextLine(int PartsNumber, int State); static bool GoatGUIEngine_SetFont(int parts_no, int type, int size, int r, int g, int b, float bold_weight, int edge_r, int edge_g, int edge_b, float edge_weight, int state) { - // TODO + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + struct parts_text *text = parts_get_text(parts_get(parts_no), state); + text->tm.face = type; + text->tm.size = size; + text->tm.color = (SDL_Color) { r, g, b, 255 }; + text->tm.weight = bold_weight * 1000; + text->tm.outline_color = (SDL_Color) { edge_r, edge_g, edge_b, 255 }; + text->tm.outline_left = edge_weight; + text->tm.outline_up = edge_weight; + text->tm.outline_right = edge_weight; + text->tm.outline_down = edge_weight; return true; } -bool GoatGUIEngine_SetPartsFontType(int PartsNumber, int Type, int State); -bool GoatGUIEngine_SetPartsFontSize(int PartsNumber, int Size, int State); -bool GoatGUIEngine_SetPartsFontColor(int PartsNumber, int R, int G, int B, int State); -bool GoatGUIEngine_SetPartsFontBoldWeight(int PartsNumber, float BoldWeight, int State); -bool GoatGUIEngine_SetPartsFontEdgeColor(int PartsNumber, int R, int G, int B, int State); -bool GoatGUIEngine_SetPartsFontEdgeWeight(int PartsNumber, float EdgeWeight, int State); +static bool GoatGUIEngine_SetPartsFontType(int parts_no, int type, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->tm.face = type; + return true; +} + +static bool GoatGUIEngine_SetPartsFontSize(int parts_no, int size, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->tm.size = size; + return true; +} + +static bool GoatGUIEngine_SetPartsFontColor(int parts_no, int r, int g, int b, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->tm.color = (SDL_Color) { r, g, b, 255 }; + return true; +} + +static bool GoatGUIEngine_SetPartsFontBoldWeight(int parts_no, float bold_weight, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->tm.weight = bold_weight * 1000; + return true; +} + +static bool GoatGUIEngine_SetPartsFontEdgeColor(int parts_no, int r, int g, int b, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->tm.outline_color = (SDL_Color) { r, g, b, 255 }; + return true; +} + +static bool GoatGUIEngine_SetPartsFontEdgeWeight(int parts_no, float edge_weight, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + struct parts_text *text = parts_get_text(parts_get(parts_no), state); + text->tm.outline_left = edge_weight; + text->tm.outline_up = edge_weight; + text->tm.outline_right = edge_weight; + text->tm.outline_down = edge_weight; + return true; +} static bool GoatGUIEngine_SetTextCharSpace(int parts_no, int char_space, int state) { - // TODO + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->char_space = char_space; + return true; +} + +static bool GoatGUIEngine_SetTextLineSpace(int parts_no, int line_space, int state) +{ + state--; + if (state < 0 || state >= PARTS_NR_STATES) + return false; + + parts_get_text(parts_get(parts_no), state)->line_space = line_space; return true; } -bool GoatGUIEngine_SetTextLineSpace(int PartsNumber, int LineSpace, int State); bool GoatGUIEngine_SetHGaugeCG(int PartsNumber, int CGNumber, int State); bool GoatGUIEngine_SetHGaugeRate(int PartsNumber, int Numerator, int Denominator, int State); bool GoatGUIEngine_SetVGaugeCG(int PartsNumber, int CGNumber, int State); @@ -919,6 +1220,10 @@ void GoatGUIEngine_AddMotionSound(int SoundNumber, int BeginTime); static void GoatGUIEngine_BeginMotion(void) { + if (began_click) + return; + + // FIXME: starting a motion seems to clear non-default states motion_t = 0; is_motion = true; parts_init_all_motion(); @@ -926,6 +1231,8 @@ static void GoatGUIEngine_BeginMotion(void) static void GoatGUIEngine_EndMotion(void) { + if (began_click) + return; motion_t = 0; motion_end_t = 0; is_motion = false; @@ -954,11 +1261,24 @@ static int GoatGUIEngine_GetMotionEndTime(void) return motion_end_t; } -void GoatGUIEngine_SetPartsMagX(int PartsNumber, float MagX); -void GoatGUIEngine_SetPartsMagY(int PartsNumber, float MagY); -void GoatGUIEngine_SetPartsRotateX(int PartsNumber, float RotateX); -void GoatGUIEngine_SetPartsRotateY(int PartsNumber, float RotateY); -void GoatGUIEngine_SetPartsRotateZ(int PartsNumber, float RotateZ); +static void GoatGUIEngine_SetPartsMagX(int parts_no, float scale_x) +{ + parts_set_scale_x(parts_get(parts_no), scale_x); +} + +static void GoatGUIEngine_SetPartsMagY(int parts_no, float scale_y) +{ + parts_set_scale_y(parts_get(parts_no), scale_y); +} + +void GoatGUIEngine_SetPartsRotateX(int parts_no, float rot_x); +void GoatGUIEngine_SetPartsRotateY(int parts_no, float rot_y); + +static void GoatGUIEngine_SetPartsRotateZ(int parts_no, float rot_z) +{ + parts_set_rotation_z(parts_get(parts_no), rot_z); +} + void GoatGUIEngine_SetPartsAlphaClipperPartsNumber(int PartsNumber, int AlphaClipperPartsNumber); void GoatGUIEngine_SetPartsPixelDecide(int PartsNumber, bool PixelDecide); bool GoatGUIEngine_SetThumbnailReductionSize(int ReductionSize); @@ -973,17 +1293,17 @@ HLL_LIBRARY(GoatGUIEngine, HLL_EXPORT(GetPartsCGNumber, GoatGUIEngine_GetPartsCGNumber), HLL_EXPORT(SetLoopCG, GoatGUIEngine_SetLoopCG), HLL_EXPORT(SetText, GoatGUIEngine_SetText), - HLL_TODO_EXPORT(AddPartsText, GoatGUIEngine_AddPartsText), + HLL_EXPORT(AddPartsText, GoatGUIEngine_AddPartsText), HLL_TODO_EXPORT(DeletePartsTopTextLine, GoatGUIEngine_DeletePartsTopTextLine), HLL_EXPORT(SetFont, GoatGUIEngine_SetFont), - HLL_TODO_EXPORT(SetPartsFontType, GoatGUIEngine_SetPartsFontType), - HLL_TODO_EXPORT(SetPartsFontSize, GoatGUIEngine_SetPartsFontSize), - HLL_TODO_EXPORT(SetPartsFontColor, GoatGUIEngine_SetPartsFontColor), - HLL_TODO_EXPORT(SetPartsFontBoldWeight, GoatGUIEngine_SetPartsFontBoldWeight), - HLL_TODO_EXPORT(SetPartsFontEdgeColor, GoatGUIEngine_SetPartsFontEdgeColor), - HLL_TODO_EXPORT(SetPartsFontEdgeWeight, GoatGUIEngine_SetPartsFontEdgeWeight), + HLL_EXPORT(SetPartsFontType, GoatGUIEngine_SetPartsFontType), + HLL_EXPORT(SetPartsFontSize, GoatGUIEngine_SetPartsFontSize), + HLL_EXPORT(SetPartsFontColor, GoatGUIEngine_SetPartsFontColor), + HLL_EXPORT(SetPartsFontBoldWeight, GoatGUIEngine_SetPartsFontBoldWeight), + HLL_EXPORT(SetPartsFontEdgeColor, GoatGUIEngine_SetPartsFontEdgeColor), + HLL_EXPORT(SetPartsFontEdgeWeight, GoatGUIEngine_SetPartsFontEdgeWeight), HLL_EXPORT(SetTextCharSpace, GoatGUIEngine_SetTextCharSpace), - HLL_TODO_EXPORT(SetTextLineSpace, GoatGUIEngine_SetTextLineSpace), + HLL_EXPORT(SetTextLineSpace, GoatGUIEngine_SetTextLineSpace), HLL_TODO_EXPORT(SetHGaugeCG, GoatGUIEngine_SetHGaugeCG), HLL_TODO_EXPORT(SetHGaugeRate, GoatGUIEngine_SetHGaugeRate), HLL_TODO_EXPORT(SetVGaugeCG, GoatGUIEngine_SetVGaugeCG), @@ -1047,11 +1367,11 @@ HLL_LIBRARY(GoatGUIEngine, HLL_EXPORT(SetMotionTime, GoatGUIEngine_SetMotionTime), HLL_EXPORT(IsMotion, GoatGUIEngine_IsMotion), HLL_EXPORT(GetMotionEndTime, GoatGUIEngine_GetMotionEndTime), - HLL_TODO_EXPORT(SetPartsMagX, GoatGUIEngine_SetPartsMagX), - HLL_TODO_EXPORT(SetPartsMagY, GoatGUIEngine_SetPartsMagY), + HLL_EXPORT(SetPartsMagX, GoatGUIEngine_SetPartsMagX), + HLL_EXPORT(SetPartsMagY, GoatGUIEngine_SetPartsMagY), HLL_TODO_EXPORT(SetPartsRotateX, GoatGUIEngine_SetPartsRotateX), HLL_TODO_EXPORT(SetPartsRotateY, GoatGUIEngine_SetPartsRotateY), - HLL_TODO_EXPORT(SetPartsRotateZ, GoatGUIEngine_SetPartsRotateZ), + HLL_EXPORT(SetPartsRotateZ, GoatGUIEngine_SetPartsRotateZ), HLL_TODO_EXPORT(SetPartsAlphaClipperPartsNumber, GoatGUIEngine_SetPartsAlphaClipperPartsNumber), HLL_TODO_EXPORT(SetPartsPixelDecide, GoatGUIEngine_SetPartsPixelDecide), HLL_TODO_EXPORT(SetThumbnailReductionSize, GoatGUIEngine_SetThumbnailReductionSize),