mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-01 19:38:06 +03:00
Merge pull request #208 from kichikuou/draw-plugins
Implement DrawSnow, DrawRain, and DrawRipple HLLs
This commit is contained in:
@@ -136,7 +136,10 @@ target_sources(xsystem4 PRIVATE
|
||||
src/hll/DrawGraph.c
|
||||
src/hll/DrawMovie.c
|
||||
src/hll/DrawPluginManager.c
|
||||
src/hll/DrawRain.c
|
||||
src/hll/DrawRipple.c
|
||||
src/hll/DrawSimpleText.c
|
||||
src/hll/DrawSnow.c
|
||||
src/hll/File.c
|
||||
src/hll/File2.c
|
||||
src/hll/FileOperation.c
|
||||
|
||||
@@ -151,6 +151,7 @@ void gfx_bright_dest_only(Texture *dst, int x, int y, int w, int h, int rate);
|
||||
void gfx_copy_stretch(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
|
||||
void gfx_copy_stretch_amap(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
|
||||
void gfx_copy_stretch_blend(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh, int a);
|
||||
void gfx_copy_stretch_blend_screen(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
|
||||
void gfx_copy_stretch_blend_amap(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
|
||||
void gfx_copy_stretch_blend_amap_alpha(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh, int a);
|
||||
void gfx_copy_rot_zoom(Texture *dst, Texture *src, int sx, int sy, int w, int h, float rotate, float mag);
|
||||
|
||||
@@ -25,6 +25,7 @@ struct sact_sprite;
|
||||
struct draw_plugin {
|
||||
const char *name;
|
||||
void (*update)(struct sact_sprite *);
|
||||
void (*render)(struct sact_sprite *); // for custom sprites
|
||||
cJSON *(*to_json)(struct sact_sprite *, bool);
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ int sact_SP_SetCGFromFile(int sp, struct string *filename);
|
||||
int sact_SP_SaveCG(int sp, struct string *filename);
|
||||
int sact_SP_Create(int sp, int width, int height, int r, int g, int b, int a);
|
||||
int sact_SP_CreatePixelOnly(int sp, int width, int height);
|
||||
int sact_SP_CreateCustom(int sp);
|
||||
int sact_SP_Delete(int sp);
|
||||
int sact_SP_DeleteAll(void);
|
||||
int sact_SP_SetPos(int sp_no, int x, int y);
|
||||
|
||||
@@ -91,6 +91,7 @@ int sprite_set_cg_from_file(struct sact_sprite *sp, const char *path);
|
||||
int sprite_save_cg(struct sact_sprite *sp, const char *path);
|
||||
void sprite_init(struct sact_sprite *sp);
|
||||
void sprite_init_color(struct sact_sprite *sp, int w, int h, int r, int g, int b, int a);
|
||||
void sprite_init_custom(struct sact_sprite *sp);
|
||||
void sprite_set_pos(struct sact_sprite *sp, int x, int y);
|
||||
void sprite_set_x(struct sact_sprite *sp, int x);
|
||||
void sprite_set_y(struct sact_sprite *sp, int y);
|
||||
|
||||
+10
@@ -707,6 +707,16 @@ void gfx_copy_stretch_blend(struct texture *dst, int dx, int dy, int dw, int dh,
|
||||
restore_blend_mode();
|
||||
}
|
||||
|
||||
void gfx_copy_stretch_blend_screen(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh)
|
||||
{
|
||||
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
|
||||
|
||||
struct copy_data data = STRETCH_DATA(dx, dy, dw, dh, sx, sy, sw, sh);
|
||||
run_copy_shader(©_shader.s, dst, src, &data);
|
||||
|
||||
restore_blend_mode();
|
||||
}
|
||||
|
||||
void gfx_copy_stretch_blend_amap(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh)
|
||||
{
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
@@ -426,7 +426,10 @@ extern struct static_library lib_DrawMovie;
|
||||
extern struct static_library lib_DrawMovie2;
|
||||
extern struct static_library lib_DrawMovie3;
|
||||
extern struct static_library lib_DrawPluginManager;
|
||||
extern struct static_library lib_DrawRain;
|
||||
extern struct static_library lib_DrawRipple;
|
||||
extern struct static_library lib_DrawSimpleText;
|
||||
extern struct static_library lib_DrawSnow;
|
||||
extern struct static_library lib_File;
|
||||
extern struct static_library lib_File2;
|
||||
extern struct static_library lib_FileOperation;
|
||||
@@ -529,7 +532,10 @@ static struct static_library *static_libraries[] = {
|
||||
&lib_DrawMovie2,
|
||||
&lib_DrawMovie3,
|
||||
&lib_DrawPluginManager,
|
||||
&lib_DrawRain,
|
||||
&lib_DrawRipple,
|
||||
&lib_DrawSimpleText,
|
||||
&lib_DrawSnow,
|
||||
&lib_File,
|
||||
&lib_File2,
|
||||
&lib_FileOperation,
|
||||
|
||||
@@ -223,7 +223,7 @@ HLL_LIBRARY(ChipmunkSpriteEngine,
|
||||
HLL_EXPORT(SP_SaveCG, sact_SP_SaveCG),
|
||||
HLL_EXPORT(SP_Create, sact_SP_Create),
|
||||
HLL_EXPORT(SP_CreatePixelOnly, sact_SP_CreatePixelOnly),
|
||||
HLL_TODO_EXPORT(SP_CreateCustom, SACT2_SP_CreateCustom),
|
||||
HLL_EXPORT(SP_CreateCustom, sact_SP_CreateCustom),
|
||||
HLL_EXPORT(SP_Delete, sact_SP_Delete),
|
||||
HLL_EXPORT(SP_DeleteAll, sact_SP_DeleteAll),
|
||||
HLL_EXPORT(SP_SetPos, sact_SP_SetPos),
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/* Copyright (C) 2024 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 <stdlib.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "hll.h"
|
||||
#include "plugin.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "xsystem4.h"
|
||||
|
||||
static const char plugin_name[] = "DrawRain";
|
||||
|
||||
struct draw_rain_plugin {
|
||||
struct draw_plugin p;
|
||||
int nr_lines;
|
||||
int length;
|
||||
float speed;
|
||||
float angle;
|
||||
uint32_t timestamp;
|
||||
bool started;
|
||||
};
|
||||
|
||||
static struct draw_rain_plugin *get_draw_rain_plugin(int surface)
|
||||
{
|
||||
struct sact_sprite *sp = sact_try_get_sprite(surface);
|
||||
if (!sp)
|
||||
return NULL;
|
||||
if (!sp->plugin || sp->plugin->name != plugin_name)
|
||||
return NULL;
|
||||
return (struct draw_rain_plugin *)sp->plugin;
|
||||
}
|
||||
|
||||
static void DrawRain_update(struct sact_sprite *sp)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = (struct draw_rain_plugin *)sp->plugin;
|
||||
if (!plugin->started)
|
||||
return;
|
||||
uint32_t timestamp = SDL_GetTicks();
|
||||
if (timestamp - plugin->timestamp < 16)
|
||||
return;
|
||||
plugin->timestamp = timestamp;
|
||||
|
||||
// Unlike the AliceSoft's DrawRain, we draw random lines every frame
|
||||
// ignoring the speed parameter. The difference is not noticeable unless
|
||||
// the speed is very small.
|
||||
struct texture *dst = sprite_get_texture(sp);
|
||||
gfx_fill_amap(dst, 0, 0, dst->w, dst->h, 0);
|
||||
float rad = plugin->angle * GLM_PIf / 180.f;
|
||||
for (int i = 0; i < plugin->nr_lines / 10; i++) {
|
||||
int x1 = rand() % dst->w;
|
||||
int y1 = rand() % dst->h;
|
||||
int len = rand() % plugin->length;
|
||||
int x2 = x1 + len * sinf(rad);
|
||||
int y2 = y1 - len * cosf(rad);
|
||||
int alpha = 128 + rand() % 128;
|
||||
gfx_draw_line_to_amap(dst, x1, y1, x2, y2, alpha);
|
||||
}
|
||||
sprite_dirty(sp);
|
||||
}
|
||||
|
||||
static cJSON *DrawRain_to_json(struct sact_sprite *sp, bool verbose)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = (struct draw_rain_plugin *)sp->plugin;
|
||||
cJSON *obj = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(obj, "name", plugin->p.name);
|
||||
cJSON_AddNumberToObject(obj, "nr_lines", plugin->nr_lines);
|
||||
cJSON_AddNumberToObject(obj, "length", plugin->length);
|
||||
cJSON_AddNumberToObject(obj, "speed", plugin->speed);
|
||||
cJSON_AddNumberToObject(obj, "angle", plugin->angle);
|
||||
cJSON_AddBoolToObject(obj, "started", plugin->started);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static int DrawRain_Init(int surface)
|
||||
{
|
||||
struct sact_sprite *sp = sact_get_sprite(surface);
|
||||
if (!sp) {
|
||||
WARNING("DrawRain.Init: invalid surface %d", surface);
|
||||
return 0;
|
||||
}
|
||||
struct draw_rain_plugin *plugin = xcalloc(1, sizeof(struct draw_rain_plugin));
|
||||
plugin->p.name = plugin_name;
|
||||
plugin->p.update = DrawRain_update;
|
||||
plugin->p.to_json = DrawRain_to_json;
|
||||
plugin->nr_lines = 1000;
|
||||
plugin->length = 300;
|
||||
plugin->speed = 0.03f;
|
||||
plugin->angle = 5.f;
|
||||
sprite_bind_plugin(sp, &plugin->p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void DrawRain_Release(int surface)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
sprite_bind_plugin(sact_get_sprite(surface), NULL);
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
static void DrawRain_SetNumofLine(int surface, int line)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->nr_lines = line;
|
||||
}
|
||||
|
||||
static void DrawRain_SetLength(int surface, int length)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->length = length;
|
||||
}
|
||||
|
||||
static void DrawRain_SetSpeed(int surface, float speed)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->speed = speed;
|
||||
}
|
||||
|
||||
static void DrawRain_SetAngle(int surface, float angle)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->angle = angle;
|
||||
}
|
||||
|
||||
static void DrawRain_Start(int surface)
|
||||
{
|
||||
struct draw_rain_plugin *plugin = get_draw_rain_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->started = true;
|
||||
}
|
||||
|
||||
HLL_LIBRARY(DrawRain,
|
||||
HLL_EXPORT(Init, DrawRain_Init),
|
||||
HLL_EXPORT(Release, DrawRain_Release),
|
||||
HLL_EXPORT(SetNumofLine, DrawRain_SetNumofLine),
|
||||
HLL_EXPORT(SetLength, DrawRain_SetLength),
|
||||
HLL_EXPORT(SetSpeed, DrawRain_SetSpeed),
|
||||
HLL_EXPORT(SetAngle, DrawRain_SetAngle),
|
||||
HLL_EXPORT(Start, DrawRain_Start)
|
||||
);
|
||||
@@ -0,0 +1,247 @@
|
||||
/* Copyright (C) 2024 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 <stdlib.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "hll.h"
|
||||
#include "plugin.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "xsystem4.h"
|
||||
|
||||
static const char plugin_name[] = "DrawRipple";
|
||||
|
||||
struct ripple {
|
||||
float x;
|
||||
float y;
|
||||
uint32_t start_time;
|
||||
};
|
||||
|
||||
struct draw_ripple_plugin {
|
||||
struct draw_plugin p;
|
||||
float width;
|
||||
float height;
|
||||
int time;
|
||||
int clip_surface;
|
||||
int nr_ripples;
|
||||
struct ripple *ripples;
|
||||
uint32_t timestamp;
|
||||
};
|
||||
|
||||
static struct draw_ripple_plugin *get_draw_ripple_plugin(int surface)
|
||||
{
|
||||
struct sact_sprite *sp = sact_try_get_sprite(surface);
|
||||
if (!sp)
|
||||
return NULL;
|
||||
if (!sp->plugin || sp->plugin->name != plugin_name)
|
||||
return NULL;
|
||||
return (struct draw_ripple_plugin *)sp->plugin;
|
||||
}
|
||||
|
||||
static void draw_point(uint32_t *pixels, int w, int h, int x, int y)
|
||||
{
|
||||
if (x < 0 || x >= w || y < 0 || y >= h)
|
||||
return;
|
||||
pixels[y * w + x] = 0xffffffff;
|
||||
}
|
||||
|
||||
static void draw_ellipse(uint32_t *pixels, int dst_w, int dst_h, int cx, int cy, int rx, int ry)
|
||||
{
|
||||
// Midpoint Ellipse Algorithm.
|
||||
if (rx == 0 || ry == 0)
|
||||
return;
|
||||
const int rx2 = rx * rx;
|
||||
const int ry2 = ry * ry;
|
||||
int x = 0;
|
||||
int y = ry;
|
||||
int px = 0;
|
||||
int py = 2 * rx2 * y;
|
||||
|
||||
// Region 1
|
||||
int p = ry2 - (rx2 * ry) + (0.25 * rx2);
|
||||
while (px < py) {
|
||||
draw_point(pixels, dst_w, dst_h, cx + x, cy + y);
|
||||
draw_point(pixels, dst_w, dst_h, cx - x, cy + y);
|
||||
draw_point(pixels, dst_w, dst_h, cx + x, cy - y);
|
||||
draw_point(pixels, dst_w, dst_h, cx - x, cy - y);
|
||||
x++;
|
||||
px += 2 * ry2;
|
||||
if (p < 0) {
|
||||
p += ry2 + px;
|
||||
} else {
|
||||
y--;
|
||||
py -= 2 * rx2;
|
||||
p += ry2 + px - py;
|
||||
}
|
||||
}
|
||||
|
||||
// Region 2
|
||||
p = ry2 * (x + 0.5) * (x + 0.5) + rx2 * (y - 1) * (y - 1) - rx2 * ry2;
|
||||
while (y > 0) {
|
||||
draw_point(pixels, dst_w, dst_h, cx + x, cy + y);
|
||||
draw_point(pixels, dst_w, dst_h, cx - x, cy + y);
|
||||
draw_point(pixels, dst_w, dst_h, cx + x, cy - y);
|
||||
draw_point(pixels, dst_w, dst_h, cx - x, cy - y);
|
||||
y--;
|
||||
py -= 2 * rx2;
|
||||
if (p > 0) {
|
||||
p += rx2 - py;
|
||||
} else {
|
||||
x++;
|
||||
px += 2 * ry2;
|
||||
p += rx2 - py + px;
|
||||
}
|
||||
}
|
||||
draw_point(pixels, dst_w, dst_h, cx + rx, cy);
|
||||
draw_point(pixels, dst_w, dst_h, cx - rx, cy);
|
||||
}
|
||||
|
||||
static void DrawRipple_update(struct sact_sprite *sp)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = (struct draw_ripple_plugin *)sp->plugin;
|
||||
if (!plugin->ripples)
|
||||
return;
|
||||
uint32_t timestamp = SDL_GetTicks();
|
||||
if (timestamp - plugin->timestamp < 16)
|
||||
return;
|
||||
plugin->timestamp = timestamp;
|
||||
|
||||
struct texture *dst = sprite_get_texture(sp);
|
||||
uint32_t *pixels = xcalloc(dst->w * dst->h, 4);
|
||||
for (int i = 0; i < plugin->nr_ripples; i++) {
|
||||
struct ripple *r = &plugin->ripples[i];
|
||||
float rate = (float)(timestamp - r->start_time) / plugin->time;
|
||||
if (rate >= 1.f) {
|
||||
r->x = rand() % dst->w;
|
||||
r->y = rand() % dst->h;
|
||||
r->start_time += plugin->time * floorf(rate);
|
||||
continue;
|
||||
}
|
||||
draw_ellipse(pixels, dst->w, dst->h, r->x, r->y, plugin->width * rate, plugin->height * rate);
|
||||
}
|
||||
gfx_update_texture_with_pixels(dst, pixels);
|
||||
free(pixels);
|
||||
struct texture *clip = sprite_get_texture(sact_get_sprite(plugin->clip_surface));
|
||||
gfx_blend_da_daxsa(dst, 0, 0, clip, 0, 0, clip->w, clip->h);
|
||||
sprite_dirty(sp);
|
||||
}
|
||||
|
||||
static cJSON *DrawRipple_to_json(struct sact_sprite *sp, bool verbose)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = (struct draw_ripple_plugin *)sp->plugin;
|
||||
cJSON *obj = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(obj, "name", plugin->p.name);
|
||||
cJSON_AddNumberToObject(obj, "width", plugin->width);
|
||||
cJSON_AddNumberToObject(obj, "height", plugin->height);
|
||||
cJSON_AddNumberToObject(obj, "time", plugin->time);
|
||||
cJSON_AddNumberToObject(obj, "clip_surface", plugin->clip_surface);
|
||||
cJSON_AddNumberToObject(obj, "nr_ripples", plugin->nr_ripples);
|
||||
cJSON_AddBoolToObject(obj, "started", !!plugin->ripples);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static int DrawRipple_Init(int surface)
|
||||
{
|
||||
struct sact_sprite *sp = sact_get_sprite(surface);
|
||||
if (!sp) {
|
||||
WARNING("DrawRipple.Init: invalid surface %d", surface);
|
||||
return 0;
|
||||
}
|
||||
struct draw_ripple_plugin *plugin = xcalloc(1, sizeof(struct draw_ripple_plugin));
|
||||
plugin->p.name = plugin_name;
|
||||
plugin->p.update = DrawRipple_update;
|
||||
plugin->p.to_json = DrawRipple_to_json;
|
||||
plugin->width = 6;
|
||||
plugin->height = 3;
|
||||
plugin->time = 100;
|
||||
plugin->nr_ripples = 384;
|
||||
sprite_bind_plugin(sp, &plugin->p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void DrawRipple_Release(int surface)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
sprite_bind_plugin(sact_get_sprite(surface), NULL);
|
||||
free(plugin->ripples);
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
static void DrawRipple_SetNumof(int surface, int numof)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface);
|
||||
if (!plugin || plugin->ripples)
|
||||
return;
|
||||
plugin->nr_ripples = numof;
|
||||
}
|
||||
|
||||
static void DrawRipple_SetSize(int surface, float width, float height)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->width = width;
|
||||
plugin->height = height;
|
||||
}
|
||||
|
||||
static void DrawRipple_SetTime(int surface, int time)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->time = time;
|
||||
}
|
||||
|
||||
//void DrawRipple_SetSpeed(int nSurface, float fSpeed);
|
||||
|
||||
static void DrawRipple_SetClipAMap(int surface, int clip_surface)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->clip_surface = clip_surface;
|
||||
}
|
||||
|
||||
static void DrawRipple_Start(int surface)
|
||||
{
|
||||
struct draw_ripple_plugin *plugin = get_draw_ripple_plugin(surface);
|
||||
if (!plugin)
|
||||
return;
|
||||
if (plugin->ripples)
|
||||
return; // already started
|
||||
plugin->ripples = xmalloc(plugin->nr_ripples * sizeof(struct ripple));
|
||||
struct sact_sprite *sp = sact_get_sprite(surface);
|
||||
uint32_t now = SDL_GetTicks();
|
||||
for (int i = 0; i < plugin->nr_ripples; i++) {
|
||||
plugin->ripples[i].x = rand() % sp->rect.w;
|
||||
plugin->ripples[i].y = rand() % sp->rect.h;
|
||||
plugin->ripples[i].start_time = now - rand() % plugin->time;
|
||||
}
|
||||
}
|
||||
|
||||
HLL_LIBRARY(DrawRipple,
|
||||
HLL_EXPORT(Init, DrawRipple_Init),
|
||||
HLL_EXPORT(Release, DrawRipple_Release),
|
||||
HLL_EXPORT(SetNumof, DrawRipple_SetNumof),
|
||||
HLL_EXPORT(SetSize, DrawRipple_SetSize),
|
||||
HLL_EXPORT(SetTime, DrawRipple_SetTime),
|
||||
HLL_TODO_EXPORT(SetSpeed, DrawRipple_SetSpeed),
|
||||
HLL_EXPORT(SetClipAMap, DrawRipple_SetClipAMap),
|
||||
HLL_EXPORT(Start, DrawRipple_Start)
|
||||
);
|
||||
@@ -0,0 +1,227 @@
|
||||
/* Copyright (C) 2024 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 <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <cglm/cglm.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "hll.h"
|
||||
#include "json.h"
|
||||
#include "plugin.h"
|
||||
#include "sact.h"
|
||||
#include "sprite.h"
|
||||
#include "xsystem4.h"
|
||||
|
||||
static const char plugin_name[] = "DrawSnow";
|
||||
|
||||
enum draw_snow_type {
|
||||
DRAW_SNOW_SCREEN_BLEND = 0,
|
||||
DRAW_SNOW_ALPHA_BLEND = 1,
|
||||
};
|
||||
|
||||
struct snowflake {
|
||||
int start_x;
|
||||
int start_y;
|
||||
int end_x;
|
||||
int end_y;
|
||||
int total_time;
|
||||
float scale;
|
||||
};
|
||||
|
||||
struct draw_snow_plugin {
|
||||
struct draw_plugin p;
|
||||
enum draw_snow_type type;
|
||||
int snow_sprite;
|
||||
int max_time;
|
||||
int max_amp;
|
||||
int nr_particles;
|
||||
struct snowflake *particles;
|
||||
uint32_t timestamp;
|
||||
};
|
||||
|
||||
static inline float frand(void)
|
||||
{
|
||||
return ((float)rand() / RAND_MAX);
|
||||
}
|
||||
|
||||
static struct draw_snow_plugin *get_draw_snow_plugin(int sprite)
|
||||
{
|
||||
struct sact_sprite *sp = sact_try_get_sprite(sprite);
|
||||
if (!sp)
|
||||
return NULL;
|
||||
if (!sp->plugin || sp->plugin->name != plugin_name)
|
||||
return NULL;
|
||||
return (struct draw_snow_plugin *)sp->plugin;
|
||||
}
|
||||
|
||||
static void DrawSnow_update(struct sact_sprite *sp)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = (struct draw_snow_plugin *)sp->plugin;
|
||||
if (!plugin->particles)
|
||||
return;
|
||||
int elapsed = SDL_GetTicks() - plugin->timestamp;
|
||||
if (elapsed >= 16)
|
||||
sprite_dirty(sp);
|
||||
}
|
||||
|
||||
static void DrawSnow_render(struct sact_sprite *sp)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = (struct draw_snow_plugin *)sp->plugin;
|
||||
if (!plugin->particles)
|
||||
return;
|
||||
|
||||
struct texture *src = sprite_get_texture(sact_get_sprite(plugin->snow_sprite));
|
||||
struct texture *dst = gfx_main_surface();
|
||||
plugin->timestamp = SDL_GetTicks();
|
||||
uint32_t timestamp = 30000 + plugin->timestamp;
|
||||
for (int i = 0; i < plugin->nr_particles; i++) {
|
||||
struct snowflake *p = &plugin->particles[i];
|
||||
float rate = (float)(timestamp % p->total_time) / p->total_time;
|
||||
int x = p->start_x + (p->end_x - p->start_x) * rate;
|
||||
int y = p->start_y + (p->end_y - p->start_y) * rate;
|
||||
if (x < 0 || x >= sp->rect.w || y < 0 || y >= sp->rect.h)
|
||||
continue;
|
||||
int dw = src->w * p->scale;
|
||||
int dh = src->h * p->scale;
|
||||
int dx = sp->rect.x + x - dw / 2;
|
||||
int dy = sp->rect.y + y - dh / 2;
|
||||
switch (plugin->type) {
|
||||
case DRAW_SNOW_SCREEN_BLEND:
|
||||
gfx_copy_stretch_blend_screen(dst, dx, dy, dw, dh, src, 0, 0, src->w, src->h);
|
||||
break;
|
||||
case DRAW_SNOW_ALPHA_BLEND:
|
||||
gfx_copy_stretch_blend_amap(dst, dx, dy, dw, dh, src, 0, 0, src->w, src->h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cJSON *DrawSnow_to_json(struct sact_sprite *sp, bool verbose)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = (struct draw_snow_plugin *)sp->plugin;
|
||||
cJSON *obj = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(obj, "name", plugin->p.name);
|
||||
cJSON_AddNumberToObject(obj, "type", plugin->type);
|
||||
cJSON_AddNumberToObject(obj, "max_time", plugin->max_time);
|
||||
cJSON_AddNumberToObject(obj, "max_amp", plugin->max_amp);
|
||||
cJSON_AddNumberToObject(obj, "nr_particles", plugin->nr_particles);
|
||||
cJSON *snow_sprite = sprite_to_json(sact_get_sprite(plugin->snow_sprite), verbose);
|
||||
cJSON_AddItemToObjectCS(obj, "snow_sprite", snow_sprite);
|
||||
cJSON_AddBoolToObject(obj, "started", !!plugin->particles);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void DrawSnow_Init(int sprite, int width, int height)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = xcalloc(1, sizeof(struct draw_snow_plugin));
|
||||
plugin->p.name = plugin_name;
|
||||
plugin->p.update = DrawSnow_update;
|
||||
plugin->p.render = DrawSnow_render;
|
||||
plugin->p.to_json = DrawSnow_to_json;
|
||||
struct sact_sprite *sp = sact_get_sprite(sprite);
|
||||
if (!sp)
|
||||
VM_ERROR("DrawSnow.Init: invalid sprite %d", sprite);
|
||||
sp->rect.w = width;
|
||||
sp->rect.h = height;
|
||||
sprite_bind_plugin(sp, &plugin->p);
|
||||
plugin->max_time = 3000;
|
||||
plugin->max_amp = 160;
|
||||
plugin->nr_particles = 1024;
|
||||
}
|
||||
|
||||
static void DrawSnow_Release(int sprite)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin)
|
||||
return;
|
||||
sprite_bind_plugin(sact_get_sprite(sprite), NULL);
|
||||
free(plugin->particles);
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
static void DrawSnow_Start(int sprite)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin)
|
||||
return;
|
||||
if (plugin->particles)
|
||||
return; // already started
|
||||
plugin->particles = xcalloc(plugin->nr_particles, sizeof(struct snowflake));
|
||||
struct sact_sprite *sp = sact_get_sprite(sprite);
|
||||
for (int i = 0; i < plugin->nr_particles; i++) {
|
||||
struct snowflake *p = &plugin->particles[i];
|
||||
p->start_x = rand() % sp->rect.w;
|
||||
p->start_y = -sp->rect.h + rand() % sp->rect.h;
|
||||
p->end_x = (p->start_x + rand() % plugin->max_amp) - (plugin->max_amp / 2);
|
||||
p->end_y = sp->rect.h + rand() % sp->rect.h;
|
||||
p->total_time = glm_lerp(0.8f, 1.2f, frand()) * plugin->max_time;
|
||||
p->scale = glm_lerp(0.25f, 1.f, frand());
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSnow_SetType(int sprite, int type)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->type = type;
|
||||
}
|
||||
|
||||
static void DrawSnow_SetSurface(int sprite, int surface)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->snow_sprite = surface;
|
||||
}
|
||||
|
||||
static void DrawSnow_SetNumof(int sprite, int numof)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin || plugin->particles)
|
||||
return;
|
||||
plugin->nr_particles = numof;
|
||||
}
|
||||
|
||||
static void DrawSnow_SetMaxAmp(int sprite, int max_amp)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->max_amp = max_amp;
|
||||
}
|
||||
|
||||
static void DrawSnow_SetMaxTime(int sprite, int max_time)
|
||||
{
|
||||
struct draw_snow_plugin *plugin = get_draw_snow_plugin(sprite);
|
||||
if (!plugin)
|
||||
return;
|
||||
plugin->max_time = max_time;
|
||||
}
|
||||
|
||||
HLL_LIBRARY(DrawSnow,
|
||||
HLL_EXPORT(Init, DrawSnow_Init),
|
||||
HLL_EXPORT(Release, DrawSnow_Release),
|
||||
HLL_EXPORT(Start, DrawSnow_Start),
|
||||
HLL_EXPORT(SetType, DrawSnow_SetType),
|
||||
HLL_EXPORT(SetSurface, DrawSnow_SetSurface),
|
||||
HLL_EXPORT(SetNumof, DrawSnow_SetNumof),
|
||||
HLL_EXPORT(SetMaxAmp, DrawSnow_SetMaxAmp),
|
||||
HLL_EXPORT(SetMaxTime, DrawSnow_SetMaxTime)
|
||||
);
|
||||
+8
-2
@@ -321,7 +321,13 @@ int sact_SP_CreatePixelOnly(int sp_no, int width, int height)
|
||||
return !!sact_create_sprite(sp_no, width, height, 0, 0, 0, -1);
|
||||
}
|
||||
|
||||
//int SACT2_SP_CreateCustom(int sp);
|
||||
int sact_SP_CreateCustom(int sp_no)
|
||||
{
|
||||
struct sact_sprite *sp = sact_get_sprite(sp_no);
|
||||
if (!sp) return 0;
|
||||
sprite_init_custom(sp);
|
||||
return true;
|
||||
}
|
||||
|
||||
int sact_SP_Delete(int sp_no)
|
||||
{
|
||||
@@ -857,7 +863,7 @@ int SACT2_SP_GetBrightness(int sp_no)
|
||||
HLL_EXPORT(SP_SaveCG, sact_SP_SaveCG), \
|
||||
HLL_EXPORT(SP_Create, sact_SP_Create), \
|
||||
HLL_EXPORT(SP_CreatePixelOnly, sact_SP_CreatePixelOnly), \
|
||||
HLL_TODO_EXPORT(SP_CreateCustom, SACT2_SP_CreateCustom), \
|
||||
HLL_EXPORT(SP_CreateCustom, sact_SP_CreateCustom), \
|
||||
HLL_EXPORT(SP_Delete, sact_SP_Delete), \
|
||||
HLL_EXPORT(SP_SetPos, sact_SP_SetPos), \
|
||||
HLL_EXPORT(SP_SetX, sact_SP_SetX), \
|
||||
|
||||
@@ -969,7 +969,7 @@ HLL_LIBRARY(StoatSpriteEngine,
|
||||
HLL_EXPORT(SP_SaveCG, sact_SP_SaveCG),
|
||||
HLL_EXPORT(SP_Create, sact_SP_Create),
|
||||
HLL_EXPORT(SP_CreatePixelOnly, sact_SP_CreatePixelOnly),
|
||||
HLL_TODO_EXPORT(SP_CreateCustom, SACT2_SP_CreateCustom),
|
||||
HLL_EXPORT(SP_CreateCustom, sact_SP_CreateCustom),
|
||||
HLL_EXPORT(SP_Delete, sact_SP_Delete),
|
||||
HLL_EXPORT(SP_DeleteAll, sact_SP_DeleteAll),
|
||||
HLL_EXPORT(SP_SetPos, sact_SP_SetPos),
|
||||
|
||||
@@ -90,7 +90,10 @@ xsystem4 = [version_h,
|
||||
'hll/DrawGraph.c',
|
||||
'hll/DrawMovie.c',
|
||||
'hll/DrawPluginManager.c',
|
||||
'hll/DrawRain.c',
|
||||
'hll/DrawRipple.c',
|
||||
'hll/DrawSimpleText.c',
|
||||
'hll/DrawSnow.c',
|
||||
'hll/File.c',
|
||||
'hll/File2.c',
|
||||
'hll/FileOperation.c',
|
||||
|
||||
@@ -170,6 +170,13 @@ static void sprite_render(struct sprite *_sp)
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
}
|
||||
|
||||
static void sprite_custom_render(struct sprite *_sp)
|
||||
{
|
||||
struct sact_sprite *sp = (struct sact_sprite*)_sp;
|
||||
if (sp->plugin && sp->plugin->render)
|
||||
sp->plugin->render(sp);
|
||||
}
|
||||
|
||||
struct texture *sprite_get_texture(struct sact_sprite *sp)
|
||||
{
|
||||
sprite_init_texture(sp);
|
||||
@@ -288,6 +295,12 @@ void sprite_init_color(struct sact_sprite *sp, int w, int h, int r, int g, int b
|
||||
sprite_dirty(sp);
|
||||
}
|
||||
|
||||
void sprite_init_custom(struct sact_sprite *sp)
|
||||
{
|
||||
sp->sp.render = sprite_custom_render;
|
||||
sp->sp.to_json = _sprite_to_json;
|
||||
}
|
||||
|
||||
void sprite_set_pos(struct sact_sprite *sp, int x, int y)
|
||||
{
|
||||
sp->rect.x = x;
|
||||
|
||||
Reference in New Issue
Block a user