PartsEngine: Implement LayoutBox

This adds PARTS_LAYOUT_BOX parts type with support for automatic
horizontal/vertical child positioning. Layout calculation runs during
the component update cycle, repositioning children before their global
parameters are combined.
This commit is contained in:
kichikuou
2026-04-22 11:25:28 +09:00
parent 2f436ce5bf
commit df6998c0f9
10 changed files with 500 additions and 31 deletions
+1
View File
@@ -100,6 +100,7 @@ target_sources(xsystem4 PRIVATE
src/parts/flash.c
src/parts/flat.c
src/parts/input.c
src/parts/layoutbox.c
src/parts/motion.c
src/parts/parts.c
src/parts/render.c
+19
View File
@@ -285,4 +285,23 @@ bool PE_StartPartsFlat(int parts_no, int state);
bool PE_GoFramePartsFlat(int parts_no, int frame_no, int state);
int PE_GetPartsFlatEndFrame(int parts_no, int state);
// layoutbox.c
void PE_SetLayoutBoxLayoutType(int parts_no, int type);
int PE_GetLayoutBoxLayoutType(int parts_no);
void PE_SetLayoutBoxReturn(int parts_no, bool return_flag, int return_size);
bool PE_IsLayoutBoxReturn(int parts_no);
int PE_GetLayoutBoxReturnSize(int parts_no);
void PE_SetLayoutBoxAlign(int parts_no, int align);
int PE_GetLayoutBoxAlign(int parts_no);
void PE_SetComponentMargin(int parts_no, int top, int bottom, int left, int right);
int PE_GetComponentMarginTop(int parts_no);
int PE_GetComponentMarginBottom(int parts_no);
int PE_GetComponentMarginLeft(int parts_no);
int PE_GetComponentMarginRight(int parts_no);
void PE_set_layoutbox_padding(int parts_no, int top, int bottom, int left, int right);
int PE_get_layoutbox_padding_top(int parts_no);
int PE_get_layoutbox_padding_bottom(int parts_no);
int PE_get_layoutbox_padding_left(int parts_no);
int PE_get_layoutbox_padding_right(int parts_no);
#endif /* SYSTEM4_PARTS_H */
+36 -12
View File
@@ -282,6 +282,30 @@ static int PartsEngine_PartsFunc(int func_id, struct page **array_int,
REQUIRE_INTS(2);
PE_parts_set_lock_input_state(ints[0].i, !!ints[1].i);
return 1;
case 57: // void AppendChild(int number, int child_number)
REQUIRE_INTS(2);
PE_SetParentPartsNumber(ints[1].i, ints[0].i);
return 1;
case 91: // void SetLayoutBoxPadding(int parts_no, int top, int bottom, int left, int right)
REQUIRE_INTS(5);
PE_set_layoutbox_padding(ints[0].i, ints[1].i, ints[2].i, ints[3].i, ints[4].i);
return 1;
case 92: // int GetLayoutBoxPaddingTop(int parts_no)
REQUIRE_INTS(2);
ints[1].i = PE_get_layoutbox_padding_top(ints[0].i);
return 1;
case 93: // int GetLayoutBoxPaddingBottom(int parts_no)
REQUIRE_INTS(2);
ints[1].i = PE_get_layoutbox_padding_bottom(ints[0].i);
return 1;
case 94: // int GetLayoutBoxPaddingLeft(int parts_no)
REQUIRE_INTS(2);
ints[1].i = PE_get_layoutbox_padding_left(ints[0].i);
return 1;
case 95: // int GetLayoutBoxPaddingRight(int parts_no)
REQUIRE_INTS(2);
ints[1].i = PE_get_layoutbox_padding_right(ints[0].i);
return 1;
case 103: // void GetPartsCGSurfaceArea(int parts_no, int *x, int *y, int *w, int *h, int state)
REQUIRE_INTS(6);
PE_GetPartsCGSurfaceArea(ints[0].i, &ints[1].i, &ints[2].i, &ints[3].i, &ints[4].i, ints[5].i);
@@ -552,11 +576,11 @@ HLL_LIBRARY(PartsEngine,
HLL_TODO_EXPORT(GetComponentRotateX, PartsEngine_GetComponentRotateX),
HLL_TODO_EXPORT(GetComponentRotateY, PartsEngine_GetComponentRotateY),
HLL_EXPORT(GetComponentRotateZ, PE_GetPartsRotateZ),
HLL_TODO_EXPORT(SetComponentMargin, PartsEngine_SetComponentMargin),
HLL_TODO_EXPORT(GetComponentMarginTop, PartsEngine_GetComponentMarginTop),
HLL_TODO_EXPORT(GetComponentMarginBottom, PartsEngine_GetComponentMarginBottom),
HLL_TODO_EXPORT(GetComponentMarginLeft, PartsEngine_GetComponentMarginLeft),
HLL_TODO_EXPORT(GetComponentMarginRight, PartsEngine_GetComponentMarginRight),
HLL_EXPORT(SetComponentMargin, PE_SetComponentMargin),
HLL_EXPORT(GetComponentMarginTop, PE_GetComponentMarginTop),
HLL_EXPORT(GetComponentMarginBottom, PE_GetComponentMarginBottom),
HLL_EXPORT(GetComponentMarginLeft, PE_GetComponentMarginLeft),
HLL_EXPORT(GetComponentMarginRight, PE_GetComponentMarginRight),
HLL_EXPORT(SetComponentAlphaClipper, PE_SetPartsAlphaClipperPartsNumber),
HLL_TODO_EXPORT(GetComponentAlphaClipper, PartsEngine_GetComponentAlphaClipper),
HLL_TODO_EXPORT(SetComponentTextureFilterType, PartsEngine_SetComponentTextureFilterType),
@@ -724,13 +748,13 @@ HLL_LIBRARY(PartsEngine,
HLL_TODO_EXPORT(GetMultiTextBoxSelectB, PartsEngine_GetMultiTextBoxSelectB),
HLL_TODO_EXPORT(SetMultiTextBoxCGName, PartsEngine_SetMultiTextBoxCGName),
HLL_TODO_EXPORT(GetMultiTextBoxCGName, PartsEngine_GetMultiTextBoxCGName),
HLL_TODO_EXPORT(SetLayoutBoxLayoutType, PartsEngine_SetLayoutBoxLayoutType),
HLL_TODO_EXPORT(GetLayoutBoxLayoutType, PartsEngine_GetLayoutBoxLayoutType),
HLL_TODO_EXPORT(SetLayoutBoxReturn, PartsEngine_SetLayoutBoxReturn),
HLL_TODO_EXPORT(IsLayoutBoxReturn, PartsEngine_IsLayoutBoxReturn),
HLL_TODO_EXPORT(GetLayoutBoxReturnSize, PartsEngine_GetLayoutBoxReturnSize),
HLL_TODO_EXPORT(SetLayoutBoxAlign, PartsEngine_SetLayoutBoxAlign),
HLL_TODO_EXPORT(GetLayoutBoxAlign, PartsEngine_GetLayoutBoxAlign),
HLL_EXPORT(SetLayoutBoxLayoutType, PE_SetLayoutBoxLayoutType),
HLL_EXPORT(GetLayoutBoxLayoutType, PE_GetLayoutBoxLayoutType),
HLL_EXPORT(SetLayoutBoxReturn, PE_SetLayoutBoxReturn),
HLL_EXPORT(IsLayoutBoxReturn, PE_IsLayoutBoxReturn),
HLL_EXPORT(GetLayoutBoxReturnSize, PE_GetLayoutBoxReturnSize),
HLL_EXPORT(SetLayoutBoxAlign, PE_SetLayoutBoxAlign),
HLL_EXPORT(GetLayoutBoxAlign, PE_GetLayoutBoxAlign),
HLL_EXPORT(Parts_SetPartsCG, PE_SetPartsCG),
HLL_EXPORT(Parts_GetPartsCGName, PE_GetPartsCGName),
HLL_EXPORT(Parts_SetPartsCGSurfaceArea, PE_SetPartsCGSurfaceArea),
+1
View File
@@ -61,6 +61,7 @@ xsystem4 = [version_h,
'parts/flash.c',
'parts/flat.c',
'parts/input.c',
'parts/layoutbox.c',
'parts/message.c',
'parts/motion.c',
'parts/parts.c',
+7
View File
@@ -272,6 +272,10 @@ static cJSON *parts_state_to_json(struct parts_state *state, bool verbose)
break;
case PARTS_RECT_DETECTION:
break;
case PARTS_LAYOUT_BOX:
cJSON_AddNumberToObject(obj, "layout_type", state->layout_box.layout_type);
cJSON_AddNumberToObject(obj, "align", state->layout_box.align);
break;
}
return obj;
@@ -566,6 +570,9 @@ static void parts_list_print(struct parts *parts, int indent)
case PARTS_RECT_DETECTION:
sys_message("(rect_detection)");
break;
case PARTS_LAYOUT_BOX:
sys_message("(layout_box type=%d)", state->layout_box.layout_type);
break;
}
sys_message(" @ controller=%d z=%d (%d)\n", parts->controller_no, parts->global.z, parts->local.z);
+337
View File
@@ -0,0 +1,337 @@
/* Copyright (C) 2026 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdlib.h>
#include "system4/flat.h"
#include "parts.h"
#include "parts_internal.h"
void PE_SetComponentMargin(int parts_no, int top, int bottom, int left, int right)
{
struct parts *parts = parts_get(parts_no);
parts->margin_top = top;
parts->margin_bottom = bottom;
parts->margin_left = left;
parts->margin_right = right;
}
int PE_GetComponentMarginTop(int parts_no)
{
return parts_get(parts_no)->margin_top;
}
int PE_GetComponentMarginBottom(int parts_no)
{
return parts_get(parts_no)->margin_bottom;
}
int PE_GetComponentMarginLeft(int parts_no)
{
return parts_get(parts_no)->margin_left;
}
int PE_GetComponentMarginRight(int parts_no)
{
return parts_get(parts_no)->margin_right;
}
void PE_SetLayoutBoxLayoutType(int parts_no, int type)
{
struct parts *parts = parts_get(parts_no);
struct parts_layout_box *lb = parts_get_layout_box(parts);
if (lb->layout_type != type) {
lb->layout_type = type;
parts_component_dirty(parts);
}
}
int PE_GetLayoutBoxLayoutType(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return PARTS_LAYOUT_FREE;
return parts->states[0].layout_box.layout_type;
}
void PE_SetLayoutBoxReturn(int parts_no, bool return_flag, int return_size)
{
struct parts *parts = parts_get(parts_no);
struct parts_layout_box *lb = parts_get_layout_box(parts);
lb->wrap = return_flag;
lb->wrap_size = return_size;
parts_component_dirty(parts);
}
bool PE_IsLayoutBoxReturn(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return false;
return parts->states[0].layout_box.wrap;
}
int PE_GetLayoutBoxReturnSize(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return 0;
return parts->states[0].layout_box.wrap_size;
}
void PE_SetLayoutBoxAlign(int parts_no, int align)
{
struct parts *parts = parts_get(parts_no);
struct parts_layout_box *lb = parts_get_layout_box(parts);
if (lb->align != align) {
lb->align = align;
parts_component_dirty(parts);
}
}
int PE_GetLayoutBoxAlign(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return 0;
return parts->states[0].layout_box.align;
}
void PE_set_layoutbox_padding(int parts_no, int top, int bottom, int left, int right)
{
struct parts *parts = parts_get(parts_no);
struct parts_layout_box *lb = parts_get_layout_box(parts);
lb->padding_top = top;
lb->padding_bottom = bottom;
lb->padding_left = left;
lb->padding_right = right;
parts_component_dirty(parts);
}
int PE_get_layoutbox_padding_top(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return 0;
return parts->states[0].layout_box.padding_top;
}
int PE_get_layoutbox_padding_bottom(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return 0;
return parts->states[0].layout_box.padding_bottom;
}
int PE_get_layoutbox_padding_left(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return 0;
return parts->states[0].layout_box.padding_left;
}
int PE_get_layoutbox_padding_right(int parts_no)
{
struct parts *parts = parts_try_get(parts_no);
if (!parts || parts->states[0].type != PARTS_LAYOUT_BOX)
return 0;
return parts->states[0].layout_box.padding_right;
}
static void parts_get_layout_size(struct parts *parts, int *w, int *h)
{
struct parts_state *state = &parts->states[parts->state];
if (state->type == PARTS_FLAT && state->flat.flat) {
// The layout size of Flat is specified in the header, and this may
// differ from the hitbox size.
*w = state->flat.flat->hdr.width;
*h = state->flat.flat->hdr.height;
} else {
*w = state->common.w;
*h = state->common.h;
}
}
static int align_offset_x(int align, int total_w)
{
switch (align) {
case 2: case 5: case 8: return -(total_w / 2);
case 3: case 6: case 9: return -total_w;
default: return 0;
}
}
static int align_offset_y(int align, int total_h)
{
switch (align) {
case 4: case 5: case 6: return -(total_h / 2);
case 7: case 8: case 9: return -total_h;
default: return 0;
}
}
// Calculates the total size of a horizontal layout box by summing child widths per row.
static void parts_layout_calc_size_horizontal(struct parts_layout_box *lb, struct parts *parts,
int *out_w, int *out_h)
{
int row_w = 0, max_row_w = 0, max_row_h = 0, total_h = 0;
struct parts *child;
PARTS_FOREACH_CHILD(child, parts) {
int child_w, child_h;
parts_get_layout_size(child, &child_w, &child_h);
int cw = child->margin_left + child_w + child->margin_right;
int ch = child->margin_top + child_h + child->margin_bottom;
if (lb->wrap && row_w + cw > lb->wrap_size && row_w > 0) {
if (row_w > max_row_w)
max_row_w = row_w;
total_h += max_row_h;
row_w = 0;
max_row_h = 0;
}
row_w += cw;
if (ch > max_row_h)
max_row_h = ch;
}
if (row_w > max_row_w)
max_row_w = row_w;
total_h += max_row_h;
*out_w = max_row_w + lb->padding_left + lb->padding_right;
*out_h = total_h + lb->padding_top + lb->padding_bottom;
}
// Calculates the total size of a vertical layout box by summing child heights per column.
static void parts_layout_calc_size_vertical(struct parts_layout_box *lb, struct parts *parts,
int *out_w, int *out_h)
{
int col_h = 0, max_col_h = 0, max_col_w = 0, total_w = 0;
struct parts *child;
PARTS_FOREACH_CHILD(child, parts) {
int child_w, child_h;
parts_get_layout_size(child, &child_w, &child_h);
int cw = child->margin_left + child_w + child->margin_right;
int ch = child->margin_top + child_h + child->margin_bottom;
if (lb->wrap && col_h + ch > lb->wrap_size && col_h > 0) {
if (col_h > max_col_h)
max_col_h = col_h;
total_w += max_col_w;
col_h = 0;
max_col_w = 0;
}
col_h += ch;
if (cw > max_col_w)
max_col_w = cw;
}
if (col_h > max_col_h)
max_col_h = col_h;
total_w += max_col_w;
*out_w = total_w + lb->padding_left + lb->padding_right;
*out_h = max_col_h + lb->padding_top + lb->padding_bottom;
}
void parts_do_layout(struct parts *parts)
{
if (parts->states[0].type != PARTS_LAYOUT_BOX)
return;
struct parts_layout_box *lb = &parts->states[0].layout_box;
if (lb->layout_type == PARTS_LAYOUT_FREE)
return;
int total_w, total_h;
if (lb->layout_type == PARTS_LAYOUT_HORIZONTAL)
parts_layout_calc_size_horizontal(lb, parts, &total_w, &total_h);
else
parts_layout_calc_size_vertical(lb, parts, &total_w, &total_h);
int align = lb->align;
bool is_left = (align == 1 || align == 4 || align == 7);
bool is_right = (align == 3 || align == 6 || align == 9);
bool is_top = (align == 1 || align == 2 || align == 3);
bool is_bottom = (align == 7 || align == 8 || align == 9);
int origin_x = align_offset_x(parts->origin_mode, total_w);
int origin_y = align_offset_y(parts->origin_mode, total_h);
int align_x = align_offset_x(align, total_w);
int align_y = align_offset_y(align, total_h);
int start_x = (is_left ? lb->padding_left : -lb->padding_right)
+ (origin_x - align_x);
int start_y = (is_top ? lb->padding_top : -lb->padding_bottom)
+ (origin_y - align_y);
int x_dir = is_right ? -1 : 1;
int y_dir = is_bottom ? -1 : 1;
int cur_x = start_x;
int cur_y = start_y;
int max_cross = 0;
struct parts *child;
PARTS_FOREACH_CHILD(child, parts) {
int child_w, child_h;
parts_get_layout_size(child, &child_w, &child_h);
int cw = child->margin_left + child_w + child->margin_right;
int ch = child->margin_top + child_h + child->margin_bottom;
// The layout box forces the child's origin_mode to match its own align.
if (child->origin_mode != align) {
child->origin_mode = align;
parts_recalculate_hitbox(child);
}
if (lb->layout_type == PARTS_LAYOUT_HORIZONTAL) {
if (lb->wrap && abs((cur_x + cw * x_dir) - start_x) > lb->wrap_size
&& max_cross > 0) {
cur_y += max_cross * y_dir;
max_cross = 0;
cur_x = start_x;
}
} else {
if (lb->wrap && abs((cur_y + ch * y_dir) - start_y) > lb->wrap_size
&& max_cross > 0) {
cur_x += max_cross * x_dir;
max_cross = 0;
cur_y = start_y;
}
}
// margin offset depends on alignment direction
int mx = is_left ? child->margin_left : is_right ? -child->margin_right : 0;
int my = is_top ? child->margin_top : is_bottom ? -child->margin_bottom : 0;
int pos_x = cur_x + mx;
int pos_y = cur_y + my;
if (child->local.pos.x != pos_x || child->local.pos.y != pos_y) {
child->local.pos.x = pos_x;
child->local.pos.y = pos_y;
parts_recalculate_hitbox(child);
parts_component_dirty(child);
}
if (lb->layout_type == PARTS_LAYOUT_HORIZONTAL) {
cur_x += cw * x_dir;
if (ch > max_cross)
max_cross = ch;
} else {
cur_y += ch * y_dir;
if (cw > max_cross)
max_cross = cw;
}
}
}
+22 -2
View File
@@ -174,6 +174,8 @@ static void parts_state_free(struct parts_state *state)
{
switch (state->type) {
case PARTS_UNINITIALIZED:
case PARTS_RECT_DETECTION:
case PARTS_LAYOUT_BOX:
break;
case PARTS_CG:
gfx_delete_texture(&state->common.texture);
@@ -213,8 +215,6 @@ static void parts_state_free(struct parts_state *state)
if (state->movie.sprite_no >= 0)
sact_SP_Delete(state->movie.sprite_no);
break;
case PARTS_RECT_DETECTION:
break;
}
memset(state, 0, sizeof(struct parts_state));
}
@@ -266,6 +266,10 @@ void parts_state_reset(struct parts_state *state, enum parts_type type)
case PARTS_MOVIE:
state->movie.sprite_no = -1;
break;
case PARTS_LAYOUT_BOX:
state->layout_box.layout_type = PARTS_LAYOUT_VERTICAL;
state->layout_box.align = 1;
break;
}
}
@@ -349,6 +353,14 @@ struct parts_movie *parts_get_movie(struct parts *parts, int state)
return &parts->states[state].movie;
}
struct parts_layout_box *parts_get_layout_box(struct parts *parts)
{
if (parts->states[0].type != PARTS_LAYOUT_BOX) {
parts_state_reset(&parts->states[0], PARTS_LAYOUT_BOX);
}
return &parts->states[0].layout_box;
}
static Point calculate_offset(int mode, int w, int h)
{
switch (mode) {
@@ -1077,6 +1089,8 @@ static void parts_update_component(struct parts *parts)
parts->dirty = false;
}
parts_do_layout(parts);
struct parts *child;
PARTS_FOREACH_CHILD(child, parts) {
parts_update_component(child);
@@ -1099,6 +1113,10 @@ void PE_UpdateComponent(possibly_unused int passed_time)
}
parts->parent = parent;
TAILQ_INSERT_TAIL(&parent->children, parts, child_list_entry);
// if parent is layout box, mark it dirty so that it can re-layout its children
if (parent->states[0].type == PARTS_LAYOUT_BOX)
parts_component_dirty(parent);
}
// TODO: should the child be orphaned if it already has a parent and an invalid
// parent no is given?
@@ -1931,6 +1949,7 @@ void PE_SetComponentType(int parts_no, int type, int state)
struct parts *parts = parts_get(parts_no);
enum parts_type pt = PARTS_UNINITIALIZED;
switch (type) {
case 8: pt = PARTS_LAYOUT_BOX; break;
case 11: pt = PARTS_CG; break;
case 12: pt = PARTS_ANIMATION; break;
case 13: pt = PARTS_TEXT; break;
@@ -1957,6 +1976,7 @@ int PE_GetComponentType(int parts_no, int state)
return -1;
switch (parts->states[state].type) {
case PARTS_LAYOUT_BOX: return 8;
case PARTS_UNINITIALIZED: // defaluts to CG
case PARTS_CG:
return 11;
+34 -11
View File
@@ -106,7 +106,8 @@ enum parts_type {
PARTS_FLAT,
PARTS_MOVIE,
PARTS_RECT_DETECTION,
#define PARTS_NR_TYPES (PARTS_RECT_DETECTION+1)
PARTS_LAYOUT_BOX,
#define PARTS_NR_TYPES (PARTS_LAYOUT_BOX+1)
};
struct parts_common {
@@ -320,6 +321,29 @@ struct parts_movie {
int sprite_no; // SACT sprite number used as movie render target
};
enum parts_layout_type {
PARTS_LAYOUT_FREE = 0, // no automatic layout
PARTS_LAYOUT_VERTICAL = 1,
PARTS_LAYOUT_HORIZONTAL = 2,
};
// In AliceSoft's PartsEngine implementation, LayoutBox is a component type
// that is NOT per-state. We store it per-state for uniformity with other
// component types, but parts_get_layout_box() and all code in layoutbox.c
// operate on states[0] only. This is safe as long as game scripts never
// convert a LayoutBox parts to/from another component type.
struct parts_layout_box {
struct parts_common common;
enum parts_layout_type layout_type;
bool wrap;
int wrap_size;
int align;
int padding_top;
int padding_bottom;
int padding_left;
int padding_right;
};
struct parts_state {
enum parts_type type;
union {
@@ -333,6 +357,7 @@ struct parts_state {
struct parts_flash flash;
struct parts_flat flat;
struct parts_movie movie;
struct parts_layout_box layout_box;
};
};
@@ -379,6 +404,10 @@ struct parts {
int draw_filter;
bool message_window;
int alpha_clipper_parts_no;
int margin_top;
int margin_bottom;
int margin_left;
int margin_right;
struct parts_motion_list motion;
int controller_no;
};
@@ -414,6 +443,7 @@ struct parts_construction_process *parts_get_construction_process(struct parts *
struct parts_flash *parts_get_flash(struct parts *parts, int state);
struct parts_flat *parts_get_flat(struct parts *parts, int state);
struct parts_movie *parts_get_movie(struct parts *parts, int state);
struct parts_layout_box *parts_get_layout_box(struct parts *parts);
void parts_set_pos(struct parts *parts, Point pos);
void parts_set_global_pos(Point pos);
void parts_set_dims(struct parts *parts, struct parts_common *common, int w, int h);
@@ -508,6 +538,9 @@ bool parts_flat_load(struct parts *parts, struct parts_flat *f, struct string *f
bool parts_flat_update(struct parts_flat *f, int passed_time);
int parts_flat_find_library(struct flat *fl, const char *name);
// layoutbox.c
void parts_do_layout(struct parts *parts);
// debug.c
struct sprite;
void parts_debug_init(void);
@@ -519,14 +552,4 @@ static inline bool parts_state_valid(int state)
return state >= 0 && state <= 2;
}
static inline int parts_get_width(struct parts *parts)
{
return parts->states[parts->state].common.w;
}
static inline int parts_get_height(struct parts *parts)
{
return parts->states[parts->state].common.h;
}
#endif /* SYSTEM4_PARTS_INTERNAL_H */
+2 -2
View File
@@ -411,6 +411,8 @@ void parts_render(struct parts *parts)
struct parts_state *state = &parts->states[parts->state];
switch (state->type) {
case PARTS_UNINITIALIZED:
case PARTS_RECT_DETECTION:
case PARTS_LAYOUT_BOX:
break;
case PARTS_CG:
case PARTS_ANIMATION:
@@ -431,8 +433,6 @@ void parts_render(struct parts *parts)
case PARTS_FLAT:
parts_render_flat(parts, &state->flat);
break;
case PARTS_RECT_DETECTION:
break;
}
}
+41 -4
View File
@@ -350,6 +350,30 @@ static void load_parts_flat(struct iarray_reader *r, struct parts *parts,
flat->needs_advance = true;
}
static void save_parts_layout_box(struct iarray_writer *w, struct parts_layout_box *lb)
{
iarray_write(w, lb->layout_type);
iarray_write(w, lb->wrap);
iarray_write(w, lb->wrap_size);
iarray_write(w, lb->align);
iarray_write(w, lb->padding_top);
iarray_write(w, lb->padding_bottom);
iarray_write(w, lb->padding_left);
iarray_write(w, lb->padding_right);
}
static void load_parts_layout_box(struct iarray_reader *r, struct parts_layout_box *lb)
{
lb->layout_type = iarray_read(r);
lb->wrap = iarray_read(r);
lb->wrap_size = iarray_read(r);
lb->align = iarray_read(r);
lb->padding_top = iarray_read(r);
lb->padding_bottom = iarray_read(r);
lb->padding_left = iarray_read(r);
lb->padding_right = iarray_read(r);
}
static void save_parts_state(struct iarray_writer *w, struct parts_state *state)
{
iarray_write(w, state->type);
@@ -360,6 +384,8 @@ static void save_parts_state(struct iarray_writer *w, struct parts_state *state)
iarray_write_rectangle(w, &state->common.surface_area);
switch (state->type) {
case PARTS_UNINITIALIZED:
case PARTS_MOVIE:
case PARTS_RECT_DETECTION:
break;
case PARTS_CG:
save_parts_cg(w, &state->cg);
@@ -386,8 +412,8 @@ static void save_parts_state(struct iarray_writer *w, struct parts_state *state)
case PARTS_FLAT:
save_parts_flat(w, &state->flat);
break;
case PARTS_MOVIE:
case PARTS_RECT_DETECTION:
case PARTS_LAYOUT_BOX:
save_parts_layout_box(w, &state->layout_box);
break;
}
}
@@ -403,6 +429,8 @@ static void load_parts_state(struct iarray_reader *r, struct parts *parts,
iarray_read_rectangle(r, &state->common.surface_area);
switch (state->type) {
case PARTS_UNINITIALIZED:
case PARTS_MOVIE:
case PARTS_RECT_DETECTION:
break;
case PARTS_CG:
load_parts_cg(r, parts, &state->cg);
@@ -431,8 +459,8 @@ static void load_parts_state(struct iarray_reader *r, struct parts *parts,
case PARTS_FLAT:
load_parts_flat(r, parts, &state->flat);
break;
case PARTS_MOVIE:
case PARTS_RECT_DETECTION:
case PARTS_LAYOUT_BOX:
load_parts_layout_box(r, &state->layout_box);
break;
}
}
@@ -538,6 +566,10 @@ static void save_parts(struct iarray_writer *w, struct parts *parts)
iarray_write(w, parts->controller_no);
iarray_write(w, parts->pass_cursor);
iarray_write(w, parts->lock_input_state);
iarray_write(w, parts->margin_top);
iarray_write(w, parts->margin_bottom);
iarray_write(w, parts->margin_left);
iarray_write(w, parts->margin_right);
}
unsigned motion_count_pos = iarray_writer_pos(w);
@@ -584,7 +616,12 @@ static void load_parts(struct iarray_reader *r, int version)
parts->controller_no = iarray_read(r);
parts->pass_cursor = iarray_read(r);
parts->lock_input_state = iarray_read(r);
parts->margin_top = iarray_read(r);
parts->margin_bottom = iarray_read(r);
parts->margin_left = iarray_read(r);
parts->margin_right = iarray_read(r);
}
int motion_count = iarray_read(r);
for (int i = 0; i < motion_count; i++) {
struct parts_motion *motion = load_parts_motion(r);