14 Commits
Author SHA1 Message Date
Nunuhara Cabbage 04333ad689 Merge pull request #378 from kichikuou/bb-misc
Miscellaneous changes for Busou Shoujotai Blade Briders
2026-09-21 20:42:53 -07:00
kichikuou 960c97ecc9 Update game_compatibility.md
- Mark Busou Shoujotai Blade Briders as supported.
- Extend the table through Rance X.
2026-09-22 11:19:26 +09:00
kichikuou e61f4b3c42 Math: Add Asin() and Acos() 2026-09-22 11:18:54 +09:00
kichikuou 03f9e7e87e Implement SystemService.GetSystemBufferName 2026-09-22 11:18:54 +09:00
Nunuhara Cabbage 87e4bebb12 Merge pull request #377 from kichikuou/SengokuRanceFont
SengokuRanceFont: Fall back to Gothic TTF for missing FNL glyphs
2026-09-21 19:09:55 -07:00
Nunuhara Cabbage 3a0dc49340 Merge pull request #376 from kichikuou/bb-parts
PartsEngine fixes for Busou Shoujotai Blade Briders
2026-09-21 19:09:37 -07:00
kichikuou e93cddad76 SengokuRanceFont: Fall back to Gothic TTF for missing FNL glyphs
SengokuRanceFont.DLL falls back to MS Gothic for characters whose glyphs
are absent from the FNL font. Reproduce this behavior to enable Japanese
translations of mods based on the MangaGamer release of Sengoku Rance.

Add an HLL-local composite font that wraps each selected FNL font_size
together with a FreeType Gothic font_size. The composite font checks for
each glyph in the FNL font and delegates rendering and size to Gothic
when the glyph is missing.

Scale fallback glyphs down and adjust their vertical position so that
they align with the FNL text line.
2026-09-22 10:24:48 +09:00
kichikuou 461eca1a85 parts: Inherit alpha clipper from parent parts
Move alpha_clipper_parts_no into inherited part parameters so child
parts use their parent's clipper unless they explicitly override it.

Bump the save version to 7.
2026-09-16 12:47:59 +09:00
kichikuou 6ea8af95ba parts: Fix global params after releasing a parent
parts_release detached children without marking them dirty, leaving
them with global parameters inherited from the released parent.
Furthermore, parts_update_component skipped global parameter updates
for parentless parts.

Mark orphaned children dirty and combine parentless parts against the
root parameters.
2026-09-16 12:46:07 +09:00
kichikuou 167d75d092 parts: Implement PartsFunc 112 (GetText) 2026-09-16 10:14:38 +09:00
kichikuou 275d71712e parts: Honor FLAT graphic key alignment
Offset the sprite so that the origin matches the anchor selected by the
graphic key's align field. Use the source rectangle dimensions when an
area is specified, and the full texture dimensions otherwise.
2026-09-16 10:14:37 +09:00
kichikuou d68baa74a0 parts: Save and load 3DLayer components
Serialize the SealEngine plugin bound to the component. Instances now
remember the name so referenced assets can be reloaded.

Bump the parts save format version to 6.
2026-09-16 10:14:26 +09:00
kichikuou 267f7bb762 parts: Support PartsFunc func_id assignments in Blade Briders
Blade Briders inserts three layer functions at func_id 3-5 into the
assignment used by Rance9, shifting all subsequent func_ids up by three.
Evenicle uses the same assignment as Blade Briders.

Use this assignment internally and add three to Rance9 func_ids before
dispatch. Also implement the functions 3-5.
2026-09-15 08:36:47 +09:00
kichikuou addc26ca45 parts: Implement PartsEngine.GetComponentSpeedupRateByMessageSkip 2026-09-15 08:36:39 +09:00
21 changed files with 730 additions and 86 deletions
+1
View File
@@ -85,6 +85,7 @@ target_sources(xsystem4 PRIVATE
src/3d/reign.c
src/3d/renderer.c
src/3d/s3de.c
src/3d/save.c
src/dungeon/dgn.c
src/dungeon/dtx.c
+11 -1
View File
@@ -84,4 +84,14 @@ issues, please let me know or open a pull request to update this table.
| Rance 01 - Quest for Hikari (EN) | Supported | |
| ランスIX-ヘルマン革命- | Supported | |
| Rance IX - The Helmanian Revolution (EN) | Unknown | |
| All games released after Rance IX | Unsupported | |
| 武想少女隊ぶれいど☆ブライダーズ | Supported | |
| イブニクル | Unsupported | |
| Evenicle (EN) | Unsupported | |
| ランス03 リーザス陥落 | Unsupported | |
| Rance 03 -The Fall of Leazas- (EN) | Unsupported | |
| 妻みぐい3 | Unsupported | |
| は~とふるママン | Unsupported | |
| 超昂神騎エクシール | Unsupported | |
| Beat Valkyrie Ixseal (EN) | Unsupported | |
| Rance X -決戦- | Unsupported | |
| All games released after Rance X | Unsupported | |
+3
View File
@@ -97,6 +97,7 @@ bool PE_SetPartsGroupNumber(int parts_no, int group_no);
void PE_SetPartsMessageWindowShowLink(int parts_no, bool message_window_show_link);
bool PE_GetPartsMessageWindowShowLink(int parts_no);
void PE_SetSpeedupRateByMessageSkip(int parts_no, int rate);
int PE_GetSpeedupRateByMessageSkip(int parts_no);
void PE_SetPartsMagX(int parts_no, float scale_x);
float PE_GetPartsMagX(int parts_no);
void PE_SetPartsMagY(int parts_no, float scale_y);
@@ -130,6 +131,7 @@ bool PE_IsExist(int parts_no);
void PE_set_active_controller(int controller_no);
int PE_get_active_controller(void);
int PE_get_system_controller(void);
int PE_get_nr_controllers(void);
void PE_parts_set_want_save(int parts_no, bool want_save);
bool PE_save_thumbnail(struct string *filename, int reduction_factor);
bool PE_init_parts_movie(int parts_no, int width, int height, int bg_r, int bg_g, int bg_b, int state);
@@ -252,6 +254,7 @@ void PE_PauseMotion(bool pause);
// text.c
bool PE_SetText(int parts_no, struct string *text, int state);
struct string *PE_GetText(int parts_no, int state);
bool PE_AddPartsText(int parts_no, struct string *text, int state);
bool PE_SetPartsTextSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
bool PE_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);
+8
View File
@@ -29,6 +29,8 @@
typedef struct cJSON cJSON;
struct hash_table;
struct billboard_texture;
struct iarray_reader;
struct iarray_writer;
enum RE_plugin_version {
RE_REIGN_PLUGIN, // Toushin Toshi 3
@@ -135,6 +137,7 @@ struct RE_plugin {
struct RE_renderer *renderer;
struct RE_camera camera;
mat4 proj_transform;
int viewport_x, viewport_y, viewport_width, viewport_height;
struct RE_back_cg back_cg[RE_NR_BACK_CGS];
@@ -195,6 +198,7 @@ struct RE_instance {
struct height_detector *height_detector;
enum RE_instance_type type;
struct string *name;
int target[RE_NR_INSTANCE_TARGETS];
vec3 pos;
float pitch, roll, yaw; // in degrees
@@ -362,6 +366,10 @@ bool RE_back_cg_set_name(struct RE_back_cg *bcg, struct string *name, struct arc
void RE_render(struct sact_sprite *sp);
cJSON *RE_to_json(struct sact_sprite *sp, bool verbose);
// save.c
void RE_plugin_serialize(struct RE_plugin *plugin, struct iarray_writer *w);
void RE_plugin_deserialize(struct RE_plugin *plugin, struct iarray_reader *r, int version);
// Exposed for PartsEngine 3DLayer
int ReignEngine_create_plugin(enum RE_plugin_version version);
bool ReignEngine_ReleasePlugin(int handle);
+1
View File
@@ -224,6 +224,7 @@ struct billboard_texture {
extern enum RE_plugin_version re_plugin_version;
struct RE_instance *RE_create_instance_at(struct RE_plugin *plugin, int index);
void RE_instance_update_local_transform(struct RE_instance *inst);
// model.c
+29 -8
View File
@@ -70,6 +70,10 @@ static void free_instance(struct RE_instance *instance);
static void unload_instance(struct RE_instance *instance)
{
if (instance->name) {
free_string(instance->name);
instance->name = NULL;
}
// A billboard's motion holds frame animation state that the game can set
// before loading the instance data, so it must survive unloads.
if (instance->motion && instance->type != RE_ITYPE_BILLBOARD) {
@@ -397,6 +401,10 @@ bool RE_set_viewport(struct RE_plugin *plugin, int x, int y, int width, int heig
sprite_init_color(sp, width, height, 0, 0, 0, 255);
sprite_set_pos(sp, x, y);
RE_renderer_set_viewport_size(plugin->renderer, width, height);
plugin->viewport_x = x;
plugin->viewport_y = y;
plugin->viewport_width = width;
plugin->viewport_height = height;
return true;
}
@@ -420,17 +428,29 @@ int RE_create_instance(struct RE_plugin *plugin)
{
if (!plugin)
return -1;
for (int i = 0; i < plugin->nr_instances; i++) {
if (!plugin->instances[i]) {
plugin->instances[i] = create_instance(plugin);
return i;
int index;
for (index = 0; index < plugin->nr_instances; index++) {
if (!plugin->instances[index])
break;
}
RE_create_instance_at(plugin, index);
return index;
}
struct RE_instance *RE_create_instance_at(struct RE_plugin *plugin, int index)
{
if (index >= plugin->nr_instances) {
int old_size = plugin->nr_instances;
plugin->nr_instances *= 2;
plugin->instances = xrealloc_array(plugin->instances, old_size, plugin->nr_instances, sizeof(struct RE_instance *));
plugin->instances[old_size] = create_instance(plugin);
return old_size;
int new_size = old_size;
while (new_size <= index)
new_size *= 2;
plugin->instances = xrealloc_array(plugin->instances, old_size, new_size, sizeof(struct RE_instance *));
plugin->nr_instances = new_size;
}
if (plugin->instances[index])
free_instance(plugin->instances[index]);
plugin->instances[index] = create_instance(plugin);
return plugin->instances[index];
}
bool RE_release_instance(struct RE_plugin *plugin, int instance)
@@ -540,6 +560,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name)
unload_instance(instance);
if (name[0] == '\0')
return true; // empty name just unloads the instance
instance->name = cstr_to_string(name);
switch (instance->type) {
case RE_ITYPE_STATIC:
+388
View File
@@ -0,0 +1,388 @@
/* 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 <cglm/cglm.h>
#include "system4.h"
#include "system4/string.h"
#include "3d_internal.h"
#include "reign.h"
#include "../hll/iarray.h"
static void write_vec3(struct iarray_writer *w, vec3 v)
{
for (int i = 0; i < 3; i++)
iarray_write_float(w, v[i]);
}
static void read_vec3(struct iarray_reader *r, vec3 v)
{
for (int i = 0; i < 3; i++)
v[i] = iarray_read_float(r);
}
static void write_cstring(struct iarray_writer *w, const char *s)
{
struct string *tmp = cstr_to_string(s);
iarray_write_string(w, tmp);
free_string(tmp);
}
static void save_motion(struct iarray_writer *w, struct motion *m)
{
iarray_write(w, !!m);
if (!m)
return;
write_cstring(w, m->mot ? m->mot->name : "");
iarray_write(w, m->state);
iarray_write_float(w, m->current_frame);
iarray_write_float(w, m->frame_begin);
iarray_write_float(w, m->frame_end);
iarray_write_float(w, m->loop_frame_begin);
iarray_write_float(w, m->loop_frame_end);
}
static void load_motion(struct iarray_reader *r, struct RE_instance *inst, bool next)
{
if (!iarray_read(r))
return;
struct string *name = iarray_read_string(r);
if (name->size > 0) {
if (next)
RE_instance_load_next_motion(inst, name->text);
else
RE_instance_load_motion(inst, name->text);
}
free_string(name);
int state = iarray_read(r);
float current_frame = iarray_read_float(r);
float frame_begin = iarray_read_float(r);
float frame_end = iarray_read_float(r);
float loop_frame_begin = iarray_read_float(r);
float loop_frame_end = iarray_read_float(r);
struct motion *m = next ? inst->next_motion : inst->motion;
if (!m)
return;
m->state = state;
m->current_frame = current_frame;
m->frame_begin = frame_begin;
m->frame_end = frame_end;
m->loop_frame_begin = loop_frame_begin;
m->loop_frame_end = loop_frame_end;
}
static void save_instance(struct iarray_writer *w, struct RE_instance *inst)
{
iarray_write(w, inst->type);
iarray_write_string_or_null(w, inst->name);
for (int i = 0; i < RE_NR_INSTANCE_TARGETS; i++)
iarray_write(w, inst->target[i]);
write_vec3(w, inst->pos);
iarray_write_float(w, inst->pitch);
iarray_write_float(w, inst->roll);
iarray_write_float(w, inst->yaw);
write_vec3(w, inst->scale);
iarray_write_float(w, inst->alpha);
iarray_write_float(w, inst->grayscale_rate);
iarray_write(w, inst->draw);
iarray_write(w, inst->draw_edge);
iarray_write(w, inst->draw_shadow);
iarray_write(w, inst->make_shadow);
iarray_write(w, inst->draw_bump);
iarray_write_float(w, inst->shadow_volume_bone_radius);
iarray_write_float(w, inst->fps);
iarray_write(w, inst->use_mag_speed);
iarray_write(w, inst->motion_blend);
iarray_write_float(w, inst->motion_blend_rate);
write_vec3(w, inst->diffuse);
write_vec3(w, inst->ambient);
write_vec3(w, inst->column_pos);
iarray_write_float(w, inst->column_height);
iarray_write_float(w, inst->column_radius);
iarray_write_float(w, inst->column_angle);
iarray_write(w, inst->draw_type);
for (int i = 0; i < 4; i++)
write_vec3(w, inst->vertex_pos[i]);
for (int i = 0; i < 4; i++) {
iarray_write_float(w, inst->vertex_uv[i][0]);
iarray_write_float(w, inst->vertex_uv[i][1]);
}
write_vec3(w, inst->vec);
write_vec3(w, inst->globe_diffuse);
iarray_write(w, !!inst->light_params);
if (inst->light_params) {
iarray_write(w, RE_NR_LIGHT_PARAMS);
for (int i = 0; i < RE_NR_LIGHT_PARAMS; i++)
iarray_write_float(w, inst->light_params[i]);
}
save_motion(w, inst->motion);
save_motion(w, inst->next_motion);
}
static void load_instance(struct iarray_reader *r, struct RE_instance *inst)
{
int type = iarray_read(r);
if (type != RE_ITYPE_UNINITIALIZED)
RE_instance_set_type(inst, type);
struct string *name = iarray_read_string_or_null(r);
if (name) {
RE_instance_load(inst, name->text);
free_string(name);
}
for (int i = 0; i < RE_NR_INSTANCE_TARGETS; i++)
inst->target[i] = iarray_read(r);
read_vec3(r, inst->pos);
inst->pitch = iarray_read_float(r);
inst->roll = iarray_read_float(r);
inst->yaw = iarray_read_float(r);
read_vec3(r, inst->scale);
inst->alpha = iarray_read_float(r);
inst->grayscale_rate = iarray_read_float(r);
inst->draw = iarray_read(r);
inst->draw_edge = iarray_read(r);
inst->draw_shadow = iarray_read(r);
inst->make_shadow = iarray_read(r);
inst->draw_bump = iarray_read(r);
inst->shadow_volume_bone_radius = iarray_read_float(r);
inst->fps = iarray_read_float(r);
inst->use_mag_speed = iarray_read(r);
inst->motion_blend = iarray_read(r);
inst->motion_blend_rate = iarray_read_float(r);
read_vec3(r, inst->diffuse);
read_vec3(r, inst->ambient);
read_vec3(r, inst->column_pos);
inst->column_height = iarray_read_float(r);
inst->column_radius = iarray_read_float(r);
inst->column_angle = iarray_read_float(r);
inst->local_transform_needs_update = true;
inst->draw_type = iarray_read(r);
for (int i = 0; i < 4; i++)
read_vec3(r, inst->vertex_pos[i]);
for (int i = 0; i < 4; i++) {
inst->vertex_uv[i][0] = iarray_read_float(r);
inst->vertex_uv[i][1] = iarray_read_float(r);
}
read_vec3(r, inst->vec);
read_vec3(r, inst->globe_diffuse);
if (iarray_read(r)) {
int nr_params = iarray_read(r);
for (int i = 0; i < nr_params; i++) {
float param = iarray_read_float(r);
if (inst->light_params && i < RE_NR_LIGHT_PARAMS)
inst->light_params[i] = param;
}
}
load_motion(r, inst, false);
load_motion(r, inst, true);
}
static void save_back_cg(struct iarray_writer *w, struct RE_back_cg *bcg)
{
iarray_write_string_or_null(w, bcg->name);
iarray_write(w, bcg->no);
iarray_write_float(w, bcg->blend_rate);
iarray_write_float(w, bcg->x);
iarray_write_float(w, bcg->y);
iarray_write_float(w, bcg->mag);
iarray_write(w, bcg->show);
}
static void load_back_cg(struct iarray_reader *r, struct RE_back_cg *bcg, struct archive *aar)
{
struct string *name = iarray_read_string_or_null(r);
int no = iarray_read(r);
float blend_rate = iarray_read_float(r);
float x = iarray_read_float(r);
float y = iarray_read_float(r);
float mag = iarray_read_float(r);
bool show = iarray_read(r);
if (bcg) {
if (name)
RE_back_cg_set_name(bcg, name, aar);
else if (no)
RE_back_cg_set(bcg, no);
bcg->blend_rate = blend_rate;
bcg->x = x;
bcg->y = y;
bcg->mag = mag;
bcg->show = show;
}
if (name)
free_string(name);
}
void RE_plugin_serialize(struct RE_plugin *plugin, struct iarray_writer *w)
{
write_vec3(w, plugin->camera.pos);
iarray_write_float(w, plugin->camera.pitch);
iarray_write_float(w, plugin->camera.roll);
iarray_write_float(w, plugin->camera.yaw);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
iarray_write_float(w, plugin->proj_transform[i][j]);
}
iarray_write(w, plugin->viewport_x);
iarray_write(w, plugin->viewport_y);
iarray_write(w, plugin->viewport_width);
iarray_write(w, plugin->viewport_height);
iarray_write(w, RE_NR_BACK_CGS);
for (int i = 0; i < RE_NR_BACK_CGS; i++)
save_back_cg(w, &plugin->back_cg[i]);
iarray_write(w, plugin->render_mode);
iarray_write(w, plugin->shadow_mode);
write_vec3(w, plugin->shadow_map_light_dir);
iarray_write_float(w, plugin->shadow_bias);
iarray_write(w, plugin->bump_mode);
iarray_write(w, plugin->bloom_mode);
iarray_write(w, plugin->glare_mode);
iarray_write(w, plugin->fog_mode);
iarray_write(w, plugin->fog_type);
iarray_write_float(w, plugin->fog_near);
iarray_write_float(w, plugin->fog_far);
write_vec3(w, plugin->fog_color);
iarray_write_float(w, plugin->ls_beta_r);
iarray_write_float(w, plugin->ls_beta_m);
iarray_write_float(w, plugin->ls_g);
iarray_write_float(w, plugin->ls_distance);
write_vec3(w, plugin->ls_light_dir);
write_vec3(w, plugin->ls_light_color);
write_vec3(w, plugin->ls_sun_color);
iarray_write(w, plugin->specular_mode);
iarray_write(w, plugin->light_map_mode);
iarray_write(w, plugin->soft_fog_edge_mode);
iarray_write(w, plugin->ssao_mode);
iarray_write(w, plugin->vertex_blend_mode);
iarray_write(w, plugin->shader_precision_mode);
iarray_write(w, plugin->texture_filter_mode);
iarray_write(w, plugin->use_power2_texture);
iarray_write(w, plugin->shadow_map_resolution_level);
iarray_write(w, plugin->texture_resolution_level);
write_vec3(w, plugin->global_ambient);
iarray_write_float(w, plugin->post_effect_filter_y);
iarray_write_float(w, plugin->post_effect_filter_cb);
iarray_write_float(w, plugin->post_effect_filter_cr);
iarray_write(w, RE_DRAW_OPTION_MAX);
for (int i = 0; i < RE_DRAW_OPTION_MAX; i++)
iarray_write(w, plugin->draw_options[i]);
iarray_write(w, plugin->suspended);
iarray_write(w, plugin->mag_speed);
iarray_write(w, RE_NR_LIGHT_PARAMS);
for (int i = 0; i < RE_NR_LIGHT_PARAMS; i++)
iarray_write_float(w, plugin->light_params[i]);
iarray_write_float(w, plugin->edge_length);
iarray_write_float(w, plugin->edge_reduction_rate);
write_vec3(w, plugin->edge_color);
iarray_write(w, plugin->nr_instances);
for (int i = 0; i < plugin->nr_instances; i++) {
iarray_write(w, !!plugin->instances[i]);
if (plugin->instances[i])
save_instance(w, plugin->instances[i]);
}
}
void RE_plugin_deserialize(struct RE_plugin *plugin, struct iarray_reader *r, int version)
{
read_vec3(r, plugin->camera.pos);
plugin->camera.pitch = iarray_read_float(r);
plugin->camera.roll = iarray_read_float(r);
plugin->camera.yaw = iarray_read_float(r);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++)
plugin->proj_transform[i][j] = iarray_read_float(r);
}
int viewport_x = iarray_read(r);
int viewport_y = iarray_read(r);
int viewport_width = iarray_read(r);
int viewport_height = iarray_read(r);
if (viewport_width > 0 && viewport_height > 0)
RE_set_viewport(plugin, viewport_x, viewport_y, viewport_width, viewport_height);
int nr_back_cgs = iarray_read(r);
for (int i = 0; i < nr_back_cgs; i++)
load_back_cg(r, i < RE_NR_BACK_CGS ? &plugin->back_cg[i] : NULL, plugin->aar);
plugin->render_mode = iarray_read(r);
plugin->shadow_mode = iarray_read(r);
read_vec3(r, plugin->shadow_map_light_dir);
plugin->shadow_bias = iarray_read_float(r);
plugin->bump_mode = iarray_read(r);
plugin->bloom_mode = iarray_read(r);
plugin->glare_mode = iarray_read(r);
plugin->fog_mode = iarray_read(r);
plugin->fog_type = iarray_read(r);
plugin->fog_near = iarray_read_float(r);
plugin->fog_far = iarray_read_float(r);
read_vec3(r, plugin->fog_color);
plugin->ls_beta_r = iarray_read_float(r);
plugin->ls_beta_m = iarray_read_float(r);
plugin->ls_g = iarray_read_float(r);
plugin->ls_distance = iarray_read_float(r);
read_vec3(r, plugin->ls_light_dir);
read_vec3(r, plugin->ls_light_color);
read_vec3(r, plugin->ls_sun_color);
plugin->specular_mode = iarray_read(r);
plugin->light_map_mode = iarray_read(r);
plugin->soft_fog_edge_mode = iarray_read(r);
plugin->ssao_mode = iarray_read(r);
plugin->vertex_blend_mode = iarray_read(r);
plugin->shader_precision_mode = iarray_read(r);
plugin->texture_filter_mode = iarray_read(r);
plugin->use_power2_texture = iarray_read(r);
plugin->shadow_map_resolution_level = iarray_read(r);
plugin->texture_resolution_level = iarray_read(r);
read_vec3(r, plugin->global_ambient);
plugin->post_effect_filter_y = iarray_read_float(r);
plugin->post_effect_filter_cb = iarray_read_float(r);
plugin->post_effect_filter_cr = iarray_read_float(r);
int nr_draw_options = iarray_read(r);
for (int i = 0; i < nr_draw_options; i++) {
int option = iarray_read(r);
if (i < RE_DRAW_OPTION_MAX)
plugin->draw_options[i] = option;
}
plugin->suspended = iarray_read(r);
plugin->mag_speed = iarray_read(r);
int nr_light_params = iarray_read(r);
for (int i = 0; i < nr_light_params; i++) {
float param = iarray_read_float(r);
if (i < RE_NR_LIGHT_PARAMS)
plugin->light_params[i] = param;
}
plugin->edge_length = iarray_read_float(r);
plugin->edge_reduction_rate = iarray_read_float(r);
read_vec3(r, plugin->edge_color);
int nr_instances = iarray_read(r);
for (int i = 0; i < nr_instances; i++) {
if (!iarray_read(r))
continue;
load_instance(r, RE_create_instance_at(plugin, i));
}
}
+2
View File
@@ -213,6 +213,8 @@ HLL_LIBRARY(Math,
HLL_EXPORT(Sin, Math_Sin),
HLL_EXPORT(Tan, Math_Tan),
HLL_EXPORT(Sqrt, sqrtf),
HLL_EXPORT(Asin, asinf),
HLL_EXPORT(Acos, acosf),
HLL_EXPORT(Atan, atanf),
HLL_EXPORT(Atan2, atan2f),
HLL_EXPORT(Abs, abs),
+50 -19
View File
@@ -17,6 +17,7 @@
#include <assert.h>
#include "system4/ain.h"
#include "system4/string.h"
#include "vm/heap.h"
#include "vm/page.h"
@@ -222,6 +223,10 @@ static void PartsEngine_add_construction_process(union vm_value *ints,
}
}
// Rance9 predates the layer functions at func_id 3-5. Use the numbering from
// later PartsEngine versions as canonical and adjust Rance9's ids to match.
static bool parts_func_uses_rance9_ids;
// Generic dispatch function for PartsEngine operations.
// func_id selects the operation; arguments and return values are passed
// through three typed arrays (int/bool, float, string).
@@ -247,7 +252,11 @@ static int PartsEngine_PartsFunc(int func_id, struct page **array_int,
#define REQUIRE_STRINGS(n) \
if (nr_strings < (n)) VM_ERROR("Invalid arguments for PartsFunc %d: expected %d strings, got %d", func_id, (n), nr_strings)
switch (func_id) {
int canonical_func_id = func_id;
if (parts_func_uses_rance9_ids && canonical_func_id > 2)
canonical_func_id += 3;
switch (canonical_func_id) {
case 0: // void SetActiveLayer(int layer)
REQUIRE_INTS(1);
PE_set_active_controller(ints[0].i);
@@ -260,76 +269,97 @@ static int PartsEngine_PartsFunc(int func_id, struct page **array_int,
REQUIRE_INTS(1);
ints[0].i = PE_get_system_controller();
return 1;
case 3: // void PauseMotion(bool pause)
// Layers are identified by their index in the controller stack, so the
// layer id and index conversions are identity functions.
case 3: // int GetLayerIndex(int layer_id)
case 4: // int GetLayerID(int layer_index)
REQUIRE_INTS(2);
ints[1].i = ints[0].i;
return 1;
case 5: // int NumofLayer()
REQUIRE_INTS(1);
ints[0].i = PE_get_nr_controllers();
return 1;
case 6: // void PauseMotion(bool pause)
REQUIRE_INTS(1);
PE_PauseMotion(!!ints[0].i);
return 1;
case 4: // void SetWantSave(int parts_no, bool want_save)
case 7: // void SetWantSave(int parts_no, bool want_save)
REQUIRE_INTS(2);
PE_parts_set_want_save(ints[0].i, !!ints[1].i);
return 1;
case 6: // bool SaveThumbnail(string filename, int reduction_factor)
case 9: // bool SaveThumbnail(string filename, int reduction_factor)
REQUIRE_INTS(2);
REQUIRE_STRINGS(1);
ints[1].i = PE_save_thumbnail(heap_get_string(strings[0].i), ints[0].i);
return 1;
case 40: // float PARTS_GetAbsoluteX(int number)
case 43: // float PARTS_GetAbsoluteX(int number)
REQUIRE_INTS(1);
REQUIRE_FLOATS(1);
floats[0].f = PE_parts_get_absolute_x(ints[0].i);
return 1;
case 41: // float PARTS_GetAbsoluteY(int number)
case 44: // float PARTS_GetAbsoluteY(int number)
REQUIRE_INTS(1);
REQUIRE_FLOATS(1);
floats[0].f = PE_parts_get_absolute_y(ints[0].i);
return 1;
case 42: // int PARTS_GetAbsoluteZ(int number)
case 45: // int PARTS_GetAbsoluteZ(int number)
REQUIRE_INTS(2);
ints[1].i = PE_parts_get_absolute_z(ints[0].i);
return 1;
case 45: // void PARTS_SetLockInputState(int number, bool lock)
case 48: // void PARTS_SetLockInputState(int number, bool lock)
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)
case 60: // 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)
case 94: // 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)
case 95: // 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)
case 96: // 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)
case 97: // 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)
case 98: // 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)
case 106: // 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);
return 1;
case 159: // AddConstructProcess(ArrayInt[32], ArrayFloat[2], ArrayString[2])
case 112: { // string GetText(int parts_no, int state)
REQUIRE_INTS(2);
REQUIRE_STRINGS(1);
struct string *text = PE_GetText(ints[0].i, ints[1].i);
if (text) {
heap_string_assign(strings[0].i, text);
free_string(text);
}
return 1;
}
case 162: // AddConstructProcess(ArrayInt[32], ArrayFloat[2], ArrayString[2])
REQUIRE_INTS(32);
REQUIRE_FLOATS(2);
REQUIRE_STRINGS(2);
PartsEngine_add_construction_process(ints, floats, strings);
return 1;
case 162: // bool InitPartsMovie(int parts_no, int width, int height, int bg_r, int bg_g, int bg_b, int state)
case 165: // bool InitPartsMovie(int parts_no, int width, int height, int bg_r, int bg_g, int bg_b, int state)
REQUIRE_INTS(8);
ints[7].i = PE_init_parts_movie(ints[0].i, ints[1].i, ints[2].i, ints[3].i, ints[4].i, ints[5].i, ints[6].i);
return 1;
case 163: // int GetMovieSprite(int parts_no, int state)
case 166: // int GetMovieSprite(int parts_no, int state)
REQUIRE_INTS(3);
ints[2].i = PE_get_movie_sprite(ints[0].i, ints[1].i);
return 1;
@@ -597,7 +627,7 @@ HLL_LIBRARY(PartsEngine,
HLL_TODO_EXPORT(SetComponentMipmap, PartsEngine_SetComponentMipmap),
HLL_TODO_EXPORT(IsComponentMipmap, PartsEngine_IsComponentMipmap),
HLL_EXPORT(SetComponentSpeedupRateByMessageSkip, PE_SetSpeedupRateByMessageSkip),
HLL_TODO_EXPORT(GetComponentSpeedupRateByMessageSkip, PartsEngine_GetComponentSpeedupRateByMessageSkip),
HLL_EXPORT(GetComponentSpeedupRateByMessageSkip, PE_GetSpeedupRateByMessageSkip),
HLL_EXPORT(AddComponentMotionPos, PartsEngine_AddComponentMotionPos),
HLL_EXPORT(AddComponentMotionAlpha, PE_AddMotionAlpha_curve),
HLL_TODO_EXPORT(AddComponentMotionCG, PartsEngine_AddComponentMotionCG),
@@ -896,4 +926,5 @@ static void PartsEngine_PreLink(void)
if (get_fun(libno, "AddController")) {
PE_enable_multi_controller();
}
parts_func_uses_rance9_ids = ain_get_function(ain, "PARTS_GetLayerIndex") < 0;
}
+101
View File
@@ -43,6 +43,105 @@ struct sr_text_properties {
struct text_style ts;
};
// A font_size that uses FNL first and Gothic for missing glyphs.
struct sr_fallback_font_size {
struct font_size super;
struct font_size *fnl;
struct font_size *gothic;
struct sr_fallback_font_size *next;
};
#define SR_FALLBACK_FONT_SCALE 0.75f
#define SR_FALLBACK_VERTICAL_SHIFT_RATIO 0.65f
static struct sr_fallback_font_size *sr_fallback_sizes;
static uint32_t sjis_code_to_unicode(uint32_t code)
{
char sjis[] = { code >> 8, code, 0 };
const char *p = code > 0xff ? sjis : sjis + 1;
int unicode;
sjis_char2unicode(p, &unicode);
return unicode;
}
static bool sr_fallback_get_glyph(struct font_size *_size, struct glyph *glyph,
uint32_t code, enum font_weight weight)
{
struct sr_fallback_font_size *size = (struct sr_fallback_font_size*)_size;
if (size->fnl->font->get_glyph(size->fnl, glyph, code, weight))
return true;
if (!size->gothic->font->get_glyph(size->gothic, glyph,
sjis_code_to_unicode(code), weight))
return false;
// Align the gothic glyph toward the bottom of the FNL line.
glyph->rect.y += size->fnl->y_offset - size->gothic->y_offset;
glyph->rect.y -= lroundf((size->fnl->size - size->gothic->size)
* SR_FALLBACK_VERTICAL_SHIFT_RATIO);
return true;
}
static float sr_fallback_size_char(struct font_size *_size, uint32_t code)
{
struct sr_fallback_font_size *size = (struct sr_fallback_font_size*)_size;
float width = size->fnl->font->size_char(size->fnl, code);
if (width != 0.0f)
return width;
return size->gothic->font->size_char(size->gothic,
sjis_code_to_unicode(code));
}
static float sr_fallback_size_char_kerning(struct font_size *size, uint32_t code,
uint32_t code_next)
{
struct sr_fallback_font_size *fallback = (struct sr_fallback_font_size*)size;
float width = fallback->fnl->font->size_char_kerning(fallback->fnl,
code, code_next);
if (width != 0.0f)
return width;
return fallback->gothic->font->size_char_kerning(fallback->gothic,
sjis_code_to_unicode(code), sjis_code_to_unicode(code_next));
}
static struct font sr_fallback_font = {
.charmap = CHARMAP_SJIS,
.get_glyph = sr_fallback_get_glyph,
.size_char = sr_fallback_size_char,
.size_char_kerning = sr_fallback_size_char_kerning,
};
static struct font_size *sr_get_fallback_size(struct font_size *fnl)
{
// One wrapper per FNL size.
for (struct sr_fallback_font_size *size = sr_fallback_sizes; size;
size = size->next) {
if (size->fnl == fnl)
return &size->super;
}
struct sr_fallback_font_size *size = xcalloc(1, sizeof(*size));
size->super.size = fnl->size;
size->super.y_offset = fnl->y_offset;
size->super.font = &sr_fallback_font;
size->fnl = fnl;
size->gothic = gfx_font_get_size(FONT_GOTHIC,
fnl->size * SR_FALLBACK_FONT_SCALE);
size->next = sr_fallback_sizes;
sr_fallback_sizes = size;
return &size->super;
}
static void sr_prepare_text_style(struct text_style *ts)
{
if (ts->font_size)
return;
struct font_size *size = gfx_font_get_size(ts->face, ts->size);
// Install the wrapper only on FNL text styles.
ts->font_size = size->font->charmap == CHARMAP_SJIS
? sr_get_fallback_size(size) : size;
}
static struct sr_text_properties default_text_properties = {
.x = 0.0,
.y = 0,
@@ -134,6 +233,7 @@ static void SengokuRanceFont_SetEdgeWidth(float w)
static float SengokuRanceFont_GetTextWidth(struct string *str)
{
sr_prepare_text_style(&current_text_properties.ts);
return gfx_size_text(&current_text_properties.ts, str->text);
}
@@ -326,6 +426,7 @@ static float sp_text_draw(struct sact_sprite *sp, struct sr_text_properties *tp,
if (tp->ts.size < 8) {
tp->ts.size = 8;
}
sr_prepare_text_style(&tp->ts);
if (!sp->text.texture.handle) {
gfx_init_texture_rgba(&sp->text.texture, sp->rect.w, sp->rect.h, COLOR(0, 0, 0, 0));
+6
View File
@@ -410,6 +410,11 @@ static void SystemService_XXX(struct string **text) {
*text = cstr_to_string("FORMAT HDD ERASE 578205024758284076520478254092784789752384758204687293");
}
// Busou Shoujotai Blade Briders
static void SystemService_GetSystemBufferName(struct string **text) {
*text = cstr_to_string("xxx4wxx:xxxx-xxxxxfx5x3");
}
static void SystemService_PreLink(void);
static void SystemService_ModuleInit(void)
@@ -463,6 +468,7 @@ HLL_LIBRARY(SystemService,
HLL_TODO_EXPORT(Debug_GetUseVideoMemorySize, SystemService_Debug_GetUseVideoMemorySize),
HLL_EXPORT(Rance0123456789, SystemService_Rance0123456789),
HLL_EXPORT(XXXXX01XXXXXXXX, SystemService_XXXXX01XXXXXXXX),
HLL_EXPORT(GetSystemBufferName, SystemService_GetSystemBufferName),
HLL_EXPORT(XXX, SystemService_XXX),
HLL_EXPORT(Test, SystemService_Test),
HLL_EXPORT(DRPKT, SystemService_DRPKT),
+1
View File
@@ -46,6 +46,7 @@ xsystem4 = [version_h,
'3d/reign.c',
'3d/renderer.c',
'3d/s3de.c',
'3d/save.c',
'dungeon/dgn.c',
'dungeon/dtx.c',
+1 -1
View File
@@ -303,6 +303,7 @@ static cJSON *parts_params_to_json(struct parts_params *params, bool verbose)
cJSON_AddNumberToObject(tmp, "z", params->rotation.z);
cJSON_AddItemToObjectCS(obj, "add_color", color_to_json(&params->add_color, verbose));
cJSON_AddItemToObjectCS(obj, "mul_color", color_to_json(&params->multiply_color, verbose));
cJSON_AddNumberToObject(obj, "alpha_clipper_parts_no", params->alpha_clipper_parts_no);
return obj;
}
@@ -411,7 +412,6 @@ cJSON *parts_to_json(struct parts *parts, bool recursive, bool verbose)
cJSON_AddNumberToObject(obj, "linked_from", parts->linked_from);
cJSON_AddNumberToObject(obj, "draw_filter", parts->draw_filter);
cJSON_AddBoolToObject(obj, "message_window", parts->message_window);
cJSON_AddNumberToObject(obj, "alpha_clipper_parts_no", parts->alpha_clipper_parts_no);
cJSON_AddItemToObjectCS(obj, "motions", motions = cJSON_CreateArray());
struct parts_motion *motion;
+15 -5
View File
@@ -749,7 +749,20 @@ void parts_flat_emitter_resolve_layer(
? em->draw_filter : draw_filter;
}
// Compute the alignment origin offset for particle_align (1-9 numpad layout).
// Compute the alignment origin offset (1-9 phone keypad layout).
void parts_flat_align_offset(int align, int w, int h, vec2 out)
{
if (align < 1 || align > 9) {
glm_vec2_zero(out);
return;
}
int col = (align - 1) % 3;
int row = (align - 1) / 3;
out[0] = -(float)w * col / 2.0f;
out[1] = -(float)h * row / 2.0f;
}
// Compute the alignment origin offset for the emitter's particle_align.
bool parts_flat_emitter_get_align_offset(struct parts_flat *f, int emitter_lib_idx, vec2 out)
{
struct flat_emitter *em = &f->flat->libraries[emitter_lib_idx].emitter;
@@ -773,10 +786,7 @@ bool parts_flat_emitter_get_align_offset(struct parts_flat *f, int emitter_lib_i
int align = em->particle_align;
if (align < 1 || align > 9) align = 5;
int col = (align - 1) % 3;
int row = (align - 1) / 3;
out[0] = tex->w * col / 2.0f;
out[1] = tex->h * row / 2.0f;
parts_flat_align_offset(align, tex->w, tex->h, out);
return true;
}
+5
View File
@@ -554,6 +554,11 @@ void PE_SetSpeedupRateByMessageSkip(int parts_no, int rate)
msgskip_speedup_rate = max(1, rate);
}
int PE_GetSpeedupRateByMessageSkip(int parts_no)
{
return msgskip_speedup_rate;
}
bool PE_IsMotion(void)
{
return is_motion;
+37 -24
View File
@@ -34,24 +34,26 @@
struct parts_list parts_list = TAILQ_HEAD_INITIALIZER(parts_list);
static struct parts_list dirty_list = TAILQ_HEAD_INITIALIZER(dirty_list);
static struct hash_table *parts_table = NULL;
static Point root_pos = { 0, 0 };
struct parts_controller_stack ctrl_stack;
bool parts_multi_controller;
static void ctrl_stack_init(void);
#define PARTS_PARAMS_INITIALIZER (struct parts_params) { \
.z = 1, \
#define PARTS_PARAMS_INITIALIZER(Z) (struct parts_params) { \
.z = Z, \
.pos = { 0, 0 }, \
.show = true, \
.alpha = 255, \
.scale = { 1.0f, 1.0f }, \
.rotation = { 0.0f, 0.0f, 0.0f }, \
.add_color = { 0, 0, 0, 0 }, \
.multiply_color = { 255, 255, 255, 255 } \
.multiply_color = { 255, 255, 255, 255 }, \
.alpha_clipper_parts_no = 0 \
}
static struct parts_params root_params = PARTS_PARAMS_INITIALIZER(0);
struct parts_controller_stack ctrl_stack;
bool parts_multi_controller;
static void ctrl_stack_init(void);
static void parts_init(struct parts *parts)
{
parts->sp.z = 1;
@@ -59,8 +61,8 @@ static void parts_init(struct parts *parts)
parts->sp.has_alpha = true;
parts->sp.render = parts_sprite_render;
parts->sp.to_json = parts_sprite_to_json;
parts->local = PARTS_PARAMS_INITIALIZER;
parts->global = PARTS_PARAMS_INITIALIZER;
parts->local = PARTS_PARAMS_INITIALIZER(1);
parts->global = PARTS_PARAMS_INITIALIZER(1);
parts->delegate_index = -1;
parts->want_save = true;
parts->on_cursor_sound = -1;
@@ -452,16 +454,16 @@ void parts_set_pos(struct parts *parts, Point pos)
parts->local.pos.x = pos.x;
parts->local.pos.y = pos.y;
parts_recalculate_hitbox(parts);
parts_update_global_pos(parts, parts->parent ? parts->parent->global.pos : root_pos);
parts_update_global_pos(parts, parts->parent ? parts->parent->global.pos : root_params.pos);
parts_dirty(parts);
}
void parts_set_global_pos(Point pos)
{
root_pos = pos;
root_params.pos = pos;
struct parts *parts;
PARTS_LIST_FOREACH(parts) {
parts_update_global_pos(parts, root_pos);
parts_update_global_pos(parts, root_params.pos);
}
parts_engine_dirty();
}
@@ -1002,6 +1004,7 @@ void parts_release(int parts_no)
struct parts *child = TAILQ_FIRST(&parts->children);
TAILQ_REMOVE(&parts->children, child, child_list_entry);
child->parent = NULL;
parts_component_dirty(child);
}
if (parts->parent) {
TAILQ_REMOVE(&parts->parent->children, parts, child_list_entry);
@@ -1094,13 +1097,14 @@ static void parts_combine_params(struct parts_params *parent, struct parts_param
out->multiply_color.r = parent->multiply_color.r * (child->multiply_color.r / 255.0f);
out->multiply_color.g = parent->multiply_color.g * (child->multiply_color.g / 255.0f);
out->multiply_color.b = parent->multiply_color.b * (child->multiply_color.b / 255.0f);
out->alpha_clipper_parts_no = child->alpha_clipper_parts_no
? child->alpha_clipper_parts_no : parent->alpha_clipper_parts_no;
}
static void parts_update_component(struct parts *parts)
{
if (parts->parent) {
parts_combine_params(&parts->parent->global, &parts->local, &parts->global);
}
parts_combine_params(parts->parent ? &parts->parent->global : &root_params,
&parts->local, &parts->global);
if (parts_get_sprite_z(parts) != parts->sp.z
|| parts_get_sprite_z2(parts) != parts->sp.z2) {
parts_list_resort(parts);
@@ -1938,7 +1942,8 @@ float PE_GetPartsRotateZ(int parts_no)
void PE_SetPartsAlphaClipperPartsNumber(int parts_no, int alpha_clipper_parts_no)
{
struct parts *parts = parts_get(parts_no);
parts->alpha_clipper_parts_no = alpha_clipper_parts_no;
parts->local.alpha_clipper_parts_no = alpha_clipper_parts_no;
parts_component_dirty(parts);
parts_dirty(parts);
}
@@ -2184,6 +2189,11 @@ int PE_get_system_controller(void)
return PARTS_CONTROLLER_SYSTEM_OVERLAY;
}
int PE_get_nr_controllers(void)
{
return ctrl_stack.nr_controllers;
}
void PE_parts_set_want_save(int parts_no, bool want_save)
{
parts_get(parts_no)->want_save = want_save;
@@ -2248,13 +2258,8 @@ int PE_get_movie_sprite(int parts_no, int state)
return parts->states[state].movie.sprite_no;
}
bool PE_CreateParts3DLayerPluginID(int parts_no, int state)
bool parts_3dlayer_create_plugin(struct parts_3dlayer *l)
{
if (!parts_state_valid(--state))
return false;
struct parts *parts = parts_get(parts_no);
struct parts_3dlayer *l = parts_get_3dlayer(parts, state);
if (l->plugin >= 0)
return false;
@@ -2283,6 +2288,14 @@ bool PE_CreateParts3DLayerPluginID(int parts_no, int state)
return true;
}
bool PE_CreateParts3DLayerPluginID(int parts_no, int state)
{
if (!parts_state_valid(--state))
return false;
struct parts *parts = parts_get(parts_no);
return parts_3dlayer_create_plugin(parts_get_3dlayer(parts, state));
}
int PE_GetParts3DLayerPluginID(int parts_no, int state)
{
if (!parts_state_valid(--state))
+3 -1
View File
@@ -396,6 +396,7 @@ struct parts_params {
struct { float x, y, z; } rotation;
SDL_Color add_color;
SDL_Color multiply_color;
int alpha_clipper_parts_no;
};
struct parts {
@@ -428,7 +429,6 @@ struct parts {
int hover_time;
int draw_filter;
bool message_window;
int alpha_clipper_parts_no;
int margin_top;
int margin_bottom;
int margin_left;
@@ -504,6 +504,7 @@ bool parts_gauge_set_cg(struct parts *parts, struct parts_gauge *g, struct strin
bool parts_gauge_set_cg_by_index(struct parts *parts, struct parts_gauge *g, int cg_no);
void parts_hgauge_set_rate(struct parts *parts, struct parts_gauge *g, float rate);
void parts_vgauge_set_rate(struct parts *parts, struct parts_gauge *g, float rate);
bool parts_3dlayer_create_plugin(struct parts_3dlayer *l);
// text.c
void parts_text_free(struct parts_text *t);
@@ -602,6 +603,7 @@ struct flat_key_stack {
typedef void (*flat_emitter_particle_fn)(const struct flat_emitter_particle *p,
void *ud);
void parts_flat_align_offset(int align, int w, int h, vec2 out);
bool parts_flat_emitter_get_align_offset(struct parts_flat *f, int emitter_lib_idx, vec2 out);
void parts_flat_foreach_emitter_particle(struct parts_flat *f, int emitter_lib_idx,
const struct flat_key_data_graphic *keys,
+24 -17
View File
@@ -134,7 +134,7 @@ static void parts_render_text(struct parts *parts, struct parts_text *t)
mat4 mw_transform = WORLD_TRANSFORM(ch->t.w, ch->t.h, x, y);
Rectangle r = { 0, 0, ch->t.w, ch->t.h };
parts_render_texture(&ch->t, mw_transform, &r, blend_rate, add_color,
multiply_color, 0, parts->alpha_clipper_parts_no);
multiply_color, 0, parts->global.alpha_clipper_parts_no);
x += ch->advance;
}
x = parts->global.pos.x + t->common.origin_offset.x;
@@ -189,7 +189,9 @@ static void parts_render_cg(struct parts *parts, struct parts_common *common)
parts->global.multiply_color.g / 255.0f,
parts->global.multiply_color.b / 255.0f,
};
parts_render_texture(&common->texture, mw_transform, &r, parts->global.alpha / 255.0, add_color, multiply_color, parts->draw_filter, parts->alpha_clipper_parts_no);
parts_render_texture(&common->texture, mw_transform, &r, parts->global.alpha / 255.0,
add_color, multiply_color, parts->draw_filter,
parts->global.alpha_clipper_parts_no);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
}
@@ -224,7 +226,7 @@ static void render_emitter_particle_cb(const struct flat_emitter_particle *p,
if (p->rot[1] != 0)
glm_rotate_y(m, glm_rad(p->rot[1]), m);
glm_scale(m, (vec3){ p->scale[0], p->scale[1], 1.0f });
glm_translate(m, (vec3){ -d->align[0], -d->align[1], 0 });
glm_translate(m, (vec3){ d->align[0], d->align[1], 0 });
// Bring particle into screen space, then kill the Z-output row so
// clip_z stays at the near plane.
@@ -292,7 +294,7 @@ static void render_flat_emitter(struct parts *parts, struct parts_flat *f,
struct emitter_render_ud ud = {
.f = f,
.parent_alpha = eff.alpha,
.alpha_clipper = parts->alpha_clipper_parts_no,
.alpha_clipper = parts->global.alpha_clipper_parts_no,
.draw_filter = eff.draw_filter,
};
glm_vec2_copy(align, ud.align);
@@ -328,17 +330,6 @@ static void render_flat_cg(struct parts *parts, Texture *tex,
set_draw_filter_blend_func(ctx->draw_filter);
mat4 render_m;
glm_mat4_copy(ctx->matrix, render_m);
// Kill the Z-output row to pin clip_z at the near plane, avoiding
// near/far clipping of 3D-rotated sprites.
render_m[0][2] = render_m[1][2] = render_m[2][2] = render_m[3][2] = 0.0f;
// area_x/area_y select a sub-rectangle of the texture atlas, but
// should not shift the on-screen position. This translation cancels
// the offset that the sub-rect's top-left would otherwise introduce.
glm_translate(render_m, (vec3){ -(float)key->area_x, -(float)key->area_y, 0.0f });
glm_scale(render_m, (vec3){ tex->w, tex->h, 1.0f });
Rectangle rect;
if (key->area_width && key->area_height) {
rect = (Rectangle){ key->area_x, key->area_y, key->area_width, key->area_height };
@@ -346,8 +337,23 @@ static void render_flat_cg(struct parts *parts, Texture *tex,
rect = (Rectangle){ 0, 0, tex->w, tex->h };
}
vec2 align;
parts_flat_align_offset(key->align, rect.w, rect.h, align);
mat4 render_m;
glm_mat4_copy(ctx->matrix, render_m);
// Kill the Z-output row to pin clip_z at the near plane, avoiding
// near/far clipping of 3D-rotated sprites.
render_m[0][2] = render_m[1][2] = render_m[2][2] = render_m[3][2] = 0.0f;
glm_translate(render_m, (vec3){ align[0], align[1], 0.0f });
// area_x/area_y select a sub-rectangle of the texture atlas, but
// should not shift the on-screen position. This translation cancels
// the offset that the sub-rect's top-left would otherwise introduce.
glm_translate(render_m, (vec3){ -(float)key->area_x, -(float)key->area_y, 0.0f });
glm_scale(render_m, (vec3){ tex->w, tex->h, 1.0f });
parts_render_texture(tex, render_m, &rect, ctx->alpha, ctx->add_color, ctx->mul_color,
ctx->draw_filter, parts->alpha_clipper_parts_no);
ctx->draw_filter, parts->global.alpha_clipper_parts_no);
if (ctx->draw_filter != PARTS_DRAW_FILTER_NORMAL)
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
@@ -516,7 +522,8 @@ static void parts_render_flash_shape(struct parts *parts, struct parts_flash *f,
(parts->global.multiply_color.g / 255.0f) * fixed16_to_float(obj->color_transform.mult_terms[1]),
(parts->global.multiply_color.b / 255.0f) * fixed16_to_float(obj->color_transform.mult_terms[2])
};
parts_render_texture(src, mw_transform, &r, blend_rate, add_color, multiply_color, 0, parts->alpha_clipper_parts_no);
parts_render_texture(src, mw_transform, &r, blend_rate, add_color, multiply_color,
0, parts->global.alpha_clipper_parts_no);
}
static void parts_render_flash_sprite(struct parts *parts, struct parts_flash *f, struct parts_flash_object *obj, struct swf_tag_define_sprite *tag)
+33 -7
View File
@@ -21,10 +21,11 @@
#include "vm/page.h"
#include "asset_manager.h"
#include "parts.h"
#include "reign.h"
#include "parts_internal.h"
#include "../hll/iarray.h"
#define CURRENT_SAVE_VERSION 5
#define CURRENT_SAVE_VERSION 7
static void save_parts_params(struct iarray_writer *w, struct parts_params *params)
{
@@ -39,9 +40,10 @@ static void save_parts_params(struct iarray_writer *w, struct parts_params *para
iarray_write_float(w, params->rotation.z);
iarray_write_color(w, &params->add_color);
iarray_write_color(w, &params->multiply_color);
iarray_write(w, params->alpha_clipper_parts_no);
}
static void load_parts_params(struct iarray_reader *r, struct parts_params *params)
static void load_parts_params(struct iarray_reader *r, struct parts_params *params, int version)
{
params->z = iarray_read(r);
iarray_read_point(r, &params->pos);
@@ -54,6 +56,8 @@ static void load_parts_params(struct iarray_reader *r, struct parts_params *para
params->rotation.z = iarray_read_float(r);
iarray_read_color(r, &params->add_color);
iarray_read_color(r, &params->multiply_color);
if (version >= 7)
params->alpha_clipper_parts_no = iarray_read(r);
}
static void save_parts_cg(struct iarray_writer *w, struct parts_cg *cg)
@@ -376,6 +380,24 @@ static void load_parts_flat(struct iarray_reader *r, struct parts *parts,
flat->needs_advance = true;
}
static void save_parts_3dlayer(struct iarray_writer *w, struct parts_3dlayer *l)
{
struct RE_plugin *plugin = l->plugin >= 0 ? RE_get_plugin(l->plugin) : NULL;
iarray_write(w, !!plugin);
if (plugin)
RE_plugin_serialize(plugin, w);
}
static void load_parts_3dlayer(struct iarray_reader *r, struct parts_3dlayer *l,
int version)
{
if (!iarray_read(r))
return;
if (!parts_3dlayer_create_plugin(l))
VM_ERROR("cannot create 3D layer plugin");
RE_plugin_deserialize(RE_get_plugin(l->plugin), r, version);
}
static void save_parts_layout_box(struct iarray_writer *w, struct parts_layout_box *lb)
{
iarray_write(w, lb->layout_type);
@@ -412,7 +434,9 @@ static void save_parts_state(struct iarray_writer *w, struct parts_state *state)
case PARTS_UNINITIALIZED:
case PARTS_MOVIE:
case PARTS_RECT_DETECTION:
break;
case PARTS_3DLAYER:
save_parts_3dlayer(w, &state->layer3d);
break;
case PARTS_CG:
save_parts_cg(w, &state->cg);
@@ -458,7 +482,10 @@ static void load_parts_state(struct iarray_reader *r, struct parts *parts,
case PARTS_UNINITIALIZED:
case PARTS_MOVIE:
case PARTS_RECT_DETECTION:
break;
case PARTS_3DLAYER:
if (version > 5)
load_parts_3dlayer(r, &state->layer3d, version);
break;
case PARTS_CG:
load_parts_cg(r, parts, &state->cg);
@@ -587,7 +614,6 @@ static void save_parts(struct iarray_writer *w, struct parts *parts)
iarray_write(w, parts->linked_from);
iarray_write(w, parts->draw_filter);
iarray_write(w, parts->message_window);
iarray_write(w, parts->alpha_clipper_parts_no);
iarray_write(w, parts->controller_no);
iarray_write(w, parts->pass_cursor);
iarray_write(w, parts->lock_input_state);
@@ -619,8 +645,8 @@ static void load_parts(struct iarray_reader *r, int version)
load_parts_state(r, parts, &parts->states[i], version);
}
load_parts_params(r, &parts->local);
load_parts_params(r, &parts->global);
load_parts_params(r, &parts->local, version);
load_parts_params(r, &parts->global, version);
parts->pending_parent = iarray_read(r);
parts->delegate_index = iarray_read(r);
parts->sprite_deform = iarray_read(r);
@@ -633,8 +659,8 @@ static void load_parts(struct iarray_reader *r, int version)
parts->draw_filter = iarray_read(r);
if (version > 0)
parts->message_window = iarray_read(r);
if (version > 2)
parts->alpha_clipper_parts_no = iarray_read(r);
if (version > 2 && version < 7)
parts->local.alpha_clipper_parts_no = iarray_read(r);
if (version > 3 || (version == 3 && parts_multi_controller)) {
parts->controller_no = iarray_read(r);
parts->pass_cursor = iarray_read(r);
+8
View File
@@ -169,6 +169,14 @@ bool PE_SetText(int parts_no, struct string *text, int state)
return true;
}
struct string *PE_GetText(int parts_no, int state)
{
if (!parts_state_valid(--state))
return NULL;
return parts_text_get(parts_get_text(parts_get(parts_no), state));
}
bool PE_AddPartsText(int parts_no, struct string *text, int state)
{
if (!parts_state_valid(--state))