mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-22 23:18:01 +03:00
Flash: add support for sprite objects
This implementation supports only single-frame sprites with a single child object. As far as I know, all Flash effects in AliceSoft games meet this requirement.
This commit is contained in:
@@ -27,6 +27,22 @@ typedef uint16_t fixedu16;
|
||||
typedef uint32_t rgb_t; // 0x00BBGGRR
|
||||
typedef uint32_t rgba_t; // 0xAABBGGRR
|
||||
|
||||
static inline float twips_to_float(int32_t twips) {
|
||||
return twips / 20.0f;
|
||||
}
|
||||
|
||||
static inline float fixed32_to_float(fixed32 f32) {
|
||||
return f32 / 65536.0f;
|
||||
}
|
||||
|
||||
static inline float fixed16_to_float(fixed16 f16) {
|
||||
return f16 / 256.0f;
|
||||
}
|
||||
|
||||
static inline fixed16 fixed16_mul(fixed16 a, fixed16 b) {
|
||||
return (int32_t)a * (int32_t)b / 256;
|
||||
}
|
||||
|
||||
struct swf_rect {
|
||||
// in twips (1/20 pixel)
|
||||
int32_t x_min;
|
||||
|
||||
+48
-7
@@ -17,6 +17,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cglm/cglm.h>
|
||||
#include "system4.h"
|
||||
#include "system4/archive.h"
|
||||
#include "system4/hashtable.h"
|
||||
@@ -60,6 +61,10 @@ void parts_flash_free(struct parts_flash *f)
|
||||
ht_foreach_value(f->bitmaps, free_bitmap);
|
||||
ht_free_int(f->bitmaps);
|
||||
}
|
||||
if (f->sprites) {
|
||||
ht_foreach_value(f->sprites, free);
|
||||
ht_free_int(f->sprites);
|
||||
}
|
||||
}
|
||||
|
||||
bool parts_flash_load(struct parts *parts, struct parts_flash *f, struct string *filename)
|
||||
@@ -88,6 +93,7 @@ bool parts_flash_load(struct parts *parts, struct parts_flash *f, struct string
|
||||
f->current_frame = 0;
|
||||
f->dictionary = ht_create(256);
|
||||
f->bitmaps = ht_create(64);
|
||||
f->sprites = ht_create(64);
|
||||
|
||||
int width = f->swf->frame_size.x_max / 20;
|
||||
int height = f->swf->frame_size.y_max / 20;
|
||||
@@ -147,17 +153,20 @@ static struct parts_flash_object *update_object(struct parts_flash_object *obj,
|
||||
}
|
||||
if (tag->flags & PLACE_FLAG_HAS_CHARACTER) {
|
||||
obj->character_id = tag->character_id;
|
||||
obj->matrix = (struct swf_matrix) {
|
||||
.scale_x = 1 << 16,
|
||||
.scale_y = 1 << 16,
|
||||
};
|
||||
glm_mat4_identity(obj->matrix);
|
||||
obj->color_transform = (struct swf_cxform_with_alpha) {
|
||||
.mult_terms = { 256, 256, 256, 256 }
|
||||
};
|
||||
}
|
||||
|
||||
if (tag->flags & PLACE_FLAG_HAS_MATRIX)
|
||||
obj->matrix = tag->matrix;
|
||||
if (tag->flags & PLACE_FLAG_HAS_MATRIX) {
|
||||
obj->matrix[0][0] = fixed32_to_float(tag->matrix.scale_x);
|
||||
obj->matrix[1][1] = fixed32_to_float(tag->matrix.scale_y);
|
||||
obj->matrix[0][1] = fixed32_to_float(tag->matrix.rotate_skew_0);
|
||||
obj->matrix[1][0] = fixed32_to_float(tag->matrix.rotate_skew_1);
|
||||
obj->matrix[3][0] = twips_to_float(tag->matrix.translate_x);
|
||||
obj->matrix[3][1] = twips_to_float(tag->matrix.translate_y);
|
||||
}
|
||||
if (tag->flags & PLACE_FLAG_HAS_COLOR_TRANSFORM)
|
||||
obj->color_transform = tag->color_transform;
|
||||
if (tag->flags & PLACE_FLAG_HAS_BLEND_MODE)
|
||||
@@ -253,6 +262,35 @@ static void start_sound(struct parts_flash *f, struct swf_tag_start_sound *tag)
|
||||
audio_play_archive_data(dfile);
|
||||
}
|
||||
|
||||
static void define_sprite(struct parts_flash *f, struct swf_tag_define_sprite *tag)
|
||||
{
|
||||
ht_put_int(f->dictionary, tag->sprite_id, tag);
|
||||
struct ht_slot *slot = ht_put_int(f->sprites, tag->sprite_id, NULL);
|
||||
if (slot->value)
|
||||
return; // already defined.
|
||||
if (tag->frame_count != 1)
|
||||
ERROR("sprites with multiple frames are not supported");
|
||||
struct parts_flash_object *obj = NULL;
|
||||
for (struct swf_tag *t = tag->tags; t && t->type != TAG_END; t = t->next) {
|
||||
switch (t->type) {
|
||||
case TAG_SOUND_STREAM_HEAD2:
|
||||
case TAG_SHOW_FRAME:
|
||||
// ignored.
|
||||
break;
|
||||
case TAG_PLACE_OBJECT2:
|
||||
if (obj)
|
||||
ERROR("sprites with multiple objects are not supported");;
|
||||
obj = update_object(NULL, (struct swf_tag_place_object*)t);
|
||||
break;
|
||||
default:
|
||||
ERROR("unsupported tag %d in sprite", t->type);
|
||||
}
|
||||
}
|
||||
if (!obj)
|
||||
ERROR("sprite has no PlaceObject2 tag");
|
||||
slot->value = obj;
|
||||
}
|
||||
|
||||
bool parts_flash_seek(struct parts_flash *f, int frame)
|
||||
{
|
||||
if (!f->swf || f->current_frame == frame)
|
||||
@@ -285,6 +323,9 @@ bool parts_flash_seek(struct parts_flash *f, int frame)
|
||||
case TAG_DEFINE_SHAPE:
|
||||
define_shape(f, (struct swf_tag_define_shape*)t);
|
||||
break;
|
||||
case TAG_DEFINE_SPRITE:
|
||||
define_sprite(f, (struct swf_tag_define_sprite*)t);
|
||||
break;
|
||||
case TAG_DEFINE_SOUND:
|
||||
define_sound(f, (struct swf_tag_define_sound*)t);
|
||||
break;
|
||||
@@ -302,7 +343,7 @@ bool parts_flash_seek(struct parts_flash *f, int frame)
|
||||
start_sound(f, (struct swf_tag_start_sound*)t);
|
||||
break;
|
||||
default:
|
||||
ERROR("unknown tag 0x%x", t->type);
|
||||
ERROR("unknown tag %d", t->type);
|
||||
}
|
||||
}
|
||||
f->tag = t;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef SYSTEM4_PARTS_INTERNAL_H
|
||||
#define SYSTEM4_PARTS_INTERNAL_H
|
||||
|
||||
#include <cglm/types.h>
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/font.h"
|
||||
#include "queue.h"
|
||||
@@ -217,7 +218,7 @@ struct parts_flash_object {
|
||||
TAILQ_ENTRY(parts_flash_object) entry;
|
||||
uint16_t depth;
|
||||
uint16_t character_id;
|
||||
struct swf_matrix matrix;
|
||||
mat4 matrix;
|
||||
struct swf_cxform_with_alpha color_transform;
|
||||
};
|
||||
|
||||
@@ -232,6 +233,7 @@ struct parts_flash {
|
||||
int current_frame;
|
||||
struct hash_table *dictionary;
|
||||
struct hash_table *bitmaps; // bitmap character id -> struct texture *
|
||||
struct hash_table *sprites; // sprite character id -> struct parts_flash_object *
|
||||
TAILQ_HEAD(, parts_flash_object) display_list;
|
||||
};
|
||||
|
||||
|
||||
+47
-14
@@ -122,30 +122,60 @@ static void parts_render_flash_shape(struct parts *parts, struct parts_flash *f,
|
||||
glm_translate(mw_transform, (vec3) { parts->global.pos.x, parts->global.pos.y, 0 });
|
||||
glm_rotate_z(mw_transform, parts->local.rotation.z, mw_transform);
|
||||
glm_scale(mw_transform, (vec3){ parts->global.scale.x, parts->global.scale.y, 1.0 });
|
||||
int x = f->common.origin_offset.x + (obj->matrix.translate_x + tag->bounds.x_min) / 20;
|
||||
int y = f->common.origin_offset.y + (obj->matrix.translate_y + tag->bounds.y_min) / 20;
|
||||
int width = (tag->bounds.x_max - tag->bounds.x_min) / 20 * (obj->matrix.scale_x / 65536.0f);
|
||||
int height = (tag->bounds.y_max - tag->bounds.y_min) / 20 * (obj->matrix.scale_y / 65536.0f);
|
||||
// TODO: consider matrix.roate_skew
|
||||
glm_translate(mw_transform, (vec3){ x, y, 0 });
|
||||
glm_scale(mw_transform, (vec3){ width, height, 1.0 });
|
||||
glm_translate(mw_transform, (vec3){ f->common.origin_offset.x, f->common.origin_offset.y, 0 });
|
||||
|
||||
Rectangle r = { 0, 0, width, height };
|
||||
glm_mul(mw_transform, obj->matrix, mw_transform);
|
||||
|
||||
float blend_rate = (parts->global.alpha / 255.0f) * (obj->color_transform.mult_terms[3] / 256.0f);
|
||||
glm_translate(mw_transform, (vec3){
|
||||
twips_to_float(tag->bounds.x_min),
|
||||
twips_to_float(tag->bounds.y_min),
|
||||
0});
|
||||
glm_scale(mw_transform, (vec3){
|
||||
twips_to_float(tag->bounds.x_max - tag->bounds.x_min),
|
||||
twips_to_float(tag->bounds.y_max - tag->bounds.y_min),
|
||||
1.0});
|
||||
|
||||
Rectangle r = { 0, 0, src->w, src->h };
|
||||
|
||||
float blend_rate = (parts->global.alpha / 255.0f) * fixed16_to_float(obj->color_transform.mult_terms[3]);
|
||||
vec3 add_color = {
|
||||
(parts->global.add_color.r + obj->color_transform.add_terms[0]) / 255.0f,
|
||||
(parts->global.add_color.g + obj->color_transform.add_terms[1]) / 255.0f,
|
||||
(parts->global.add_color.b + obj->color_transform.add_terms[2]) / 255.0f
|
||||
};
|
||||
vec3 multiply_color = {
|
||||
(parts->global.multiply_color.r / 255.0f) * (obj->color_transform.mult_terms[0] / 256.0f),
|
||||
(parts->global.multiply_color.g / 255.0f) * (obj->color_transform.mult_terms[1] / 256.0f),
|
||||
(parts->global.multiply_color.b / 255.0f) * (obj->color_transform.mult_terms[2] / 256.0f)
|
||||
(parts->global.multiply_color.r / 255.0f) * fixed16_to_float(obj->color_transform.mult_terms[0]),
|
||||
(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);
|
||||
}
|
||||
|
||||
static void parts_render_flash_sprite(struct parts *parts, struct parts_flash *f, struct parts_flash_object *obj, struct swf_tag_define_sprite *tag)
|
||||
{
|
||||
struct parts_flash_object *obj2 = ht_get_int(f->sprites, tag->sprite_id, NULL);
|
||||
if (!obj)
|
||||
ERROR("undefined sprite id %d", tag->sprite_id);
|
||||
|
||||
struct swf_tag *child = ht_get_int(f->dictionary, obj2->character_id, NULL);
|
||||
if (!child)
|
||||
ERROR("character %d is not defined", obj2->character_id);
|
||||
if (child->type != TAG_DEFINE_SHAPE)
|
||||
ERROR("unexpected child type %d", child->type);
|
||||
|
||||
struct parts_flash_object transform;
|
||||
glm_mul(obj->matrix, obj2->matrix, transform.matrix);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
transform.color_transform.add_terms[i] =
|
||||
obj->color_transform.add_terms[i] + obj2->color_transform.add_terms[i];
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
transform.color_transform.mult_terms[i] =
|
||||
fixed16_mul(obj->color_transform.mult_terms[i], obj2->color_transform.mult_terms[i]);
|
||||
}
|
||||
parts_render_flash_shape(parts, f, &transform, (struct swf_tag_define_shape*)child);
|
||||
}
|
||||
|
||||
static void parts_render_flash(struct parts *parts, struct parts_flash *f)
|
||||
{
|
||||
struct parts_flash_object *obj;
|
||||
@@ -157,10 +187,13 @@ static void parts_render_flash(struct parts *parts, struct parts_flash *f)
|
||||
}
|
||||
switch (tag->type) {
|
||||
case TAG_DEFINE_SHAPE:
|
||||
parts_render_flash_shape(parts, f, obj, (struct swf_tag_define_shape *)tag);
|
||||
parts_render_flash_shape(parts, f, obj, (struct swf_tag_define_shape*)tag);
|
||||
break;
|
||||
case TAG_DEFINE_SPRITE:
|
||||
parts_render_flash_sprite(parts, f, obj, (struct swf_tag_define_sprite*)tag);
|
||||
break;
|
||||
default:
|
||||
ERROR("unknown tag 0x%x", tag->type);
|
||||
ERROR("unknown tag %d", tag->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user