mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Compare commits
14
Commits
bc745035e1
...
04333ad689
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04333ad689 | ||
|
|
960c97ecc9 | ||
|
|
e61f4b3c42 | ||
|
|
03f9e7e87e | ||
|
|
87e4bebb12 | ||
|
|
3a0dc49340 | ||
|
|
e93cddad76 | ||
|
|
461eca1a85 | ||
|
|
6ea8af95ba | ||
|
|
167d75d092 | ||
|
|
275d71712e | ||
|
|
d68baa74a0 | ||
|
|
267f7bb762 | ||
|
|
addc26ca45 |
@@ -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
@@ -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 | |
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
+31
-10
@@ -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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(¤t_text_properties.ts);
|
||||
return gfx_size_text(¤t_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));
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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(¶ms->add_color, verbose));
|
||||
cJSON_AddItemToObjectCS(obj, "mul_color", color_to_json(¶ms->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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
@@ -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, ¶ms->add_color);
|
||||
iarray_write_color(w, ¶ms->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, ¶ms->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, ¶ms->add_color);
|
||||
iarray_read_color(r, ¶ms->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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
+1
-1
Submodule subprojects/libsys4 updated: cbc57ce564...20560d4d6d
Reference in New Issue
Block a user