From 36111e069cbdd8cf38b7e855cc66c84e03327013 Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Mon, 25 Nov 2019 20:10:44 -0800 Subject: [PATCH] Implement simple DrawGraph.Fill* functions DrawGraph.Fill - fill solid color DrawGraph.FillAlphaColor - blend solid color DrawGraph.FillAMap - fill alpha channel --- hll/DrawGraph.c | 6 ++--- sact.h | 4 +++ sact_graphics.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/hll/DrawGraph.c b/hll/DrawGraph.c index 91a0cc9..c99f610 100644 --- a/hll/DrawGraph.c +++ b/hll/DrawGraph.c @@ -64,11 +64,11 @@ hll_unimplemented(DrawGraph, BlendMultiply); //void BlendScreenAlpha(int nDest, int nDx, int nDy, int nSrc, int nSx, int nSy, int nWidth, int nHeight, int nAlpha) hll_unimplemented(DrawGraph, BlendScreenAlpha); //void Fill(int nDest, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB) -hll_unimplemented(DrawGraph, Fill); +hll_defun_inline(Fill, (DrawGraph_Fill(a[0].i, a[1].i, a[2].i, a[3].i, a[4].i, a[5].i, a[6].i, a[7].i), 0)); //void FillAlphaColor(int nDest, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, int nRate) -hll_unimplemented(DrawGraph, FillAlphaColor); +hll_defun_inline(FillAlphaColor, (DrawGraph_FillAlphaColor(a[0].i, a[1].i, a[2].i, a[3].i, a[4].i, a[5].i, a[6].i, a[7].i, a[8].i), 0)); //void FillAMap(int nDest, int nX, int nY, int nWidth, int nHeight, int nAlpha) -hll_unimplemented(DrawGraph, FillAMap); +hll_defun_inline(FillAMap, (DrawGraph_FillAMap(a[0].i, a[1].i, a[2].i, a[3].i, a[4].i, a[5].i), 0)); //void FillAMapOverBorder(int nDest, int nX, int nY, int nWidth, int nHeight, int nAlpha, int nBorder) hll_unimplemented(DrawGraph, FillAMapOverBorder); //void FillAMapUnderBorder(int nDest, int nX, int nY, int nWidth, int nHeight, int nAlpha, int nBorder) diff --git a/sact.h b/sact.h index c673760..9b8fa77 100644 --- a/sact.h +++ b/sact.h @@ -65,4 +65,8 @@ void DrawGraph_CopyUseAMapBorder(int dno, int dx, int dy, int sno, int sx, int s void DrawGraph_CopyAMapMax(int dno, int dx, int dy, int sno, int sx, int sy, int w, int h); void DrawGraph_CopyAMapMin(int dno, int dx, int dy, int sno, int sx, int sy, int w, int h); +void DrawGraph_Fill(int sp_no, int x, int y, int w, int h, int r, int g, int b); +void DrawGraph_FillAMap(int sp_no, int x, int y, int w, int h, int a); +void DrawGraph_FillAlphaColor(int sp_no, int x, int y, int w, int h, int r, int g, int b, int a); + #endif /* SYSTEM4_SACT_H */ diff --git a/sact_graphics.c b/sact_graphics.c index 4ad030f..dbd8e80 100644 --- a/sact_graphics.c +++ b/sact_graphics.c @@ -125,11 +125,12 @@ int sact_SP_SetCG(int sp_no, int cg_no) int sact_SP_Create(int sp_no, int width, int height, int r, int g, int b, int a) { - struct sact_sprite *sp = sact_get_sprite(sp_no); + struct sact_sprite *sp; - if (!sp) { + if (sp_no < 0) + VM_ERROR("Invalid sprite number: %d", sp_no); + if (!(sp = sact_get_sprite(sp_no))) sp = alloc_sprite(sp_no); - } sp->color = (SDL_Color) { .r = r, .g = g, .b = b, .a = a }; sp->rect.w = width; @@ -344,6 +345,17 @@ static inline void next_pixel(SDL_Surface *s, uint32_t **p) SDL_UnlockSurface(ds); \ } while (0) +#define fill_for_each_pixel(s, x, y, w, h, p, expr) \ + do { \ + SDL_LockSurface(s); \ + for (int _row = 0; _row < h; _row++) { \ + uint32_t *p = get_pixel(s, x, _row+y); \ + for (int _col = 0; _col < w; _col++, next_pixel(s, &p)) \ + expr; \ + } \ + SDL_UnlockSurface(s); \ + } while(0); + void DrawGraph_CopyAMap(int dno, int dx, int dy, int sno, int sx, int sy, int w, int h) { SDL_Surface *ds = DrawGraph_get_sprite(dno)->cg->s; @@ -450,3 +462,52 @@ void DrawGraph_CopyAMapMin(int dno, int dx, int dy, int sno, int sx, int sy, int } }); } + +static void blend_pixels(SDL_Color *dst, SDL_Color src) +{ + uint32_t alpha = src.a + 1; + uint32_t inv_alpha = 256 - src.a; + dst->r = (uint8_t)((alpha * src.r + inv_alpha * dst->r) >> 8); + dst->g = (uint8_t)((alpha * src.g + inv_alpha * dst->g) >> 8); + dst->b = (uint8_t)((alpha * src.b + inv_alpha * dst->b) >> 8); +} + +void DrawGraph_Fill(int sp_no, int x, int y, int w, int h, int r, int g, int b) +{ + SDL_Surface *s = DrawGraph_get_sprite(sp_no)->cg->s; + + fill_for_each_pixel(s, x, y, w, h, p, { + *p &= ~(s->format->Rmask | s->format->Gmask | s->format->Bmask); + *p |= (uint32_t)r << s->format->Rshift; + *p |= (uint32_t)g << s->format->Gshift; + *p |= (uint32_t)b << s->format->Bshift; + }); +} + +// XXX: Despite being called a fill operation, this function actually performs blending. +void DrawGraph_FillAlphaColor(int sp_no, int x, int y, int w, int h, int r, int g, int b, int a) +{ + SDL_Surface *s = DrawGraph_get_sprite(sp_no)->cg->s; + + SDL_Color dst; + SDL_Color src = { .r = r, .g = g, .b = b, .a = a }; + fill_for_each_pixel(s, x, y, w, h, p, { + SDL_GetRGBA(*p, s->format, &dst.r, &dst.g, &dst.b, &dst.a); + blend_pixels(&dst, src); + *p &= ~(s->format->Rmask | s->format->Gmask | s->format->Bmask | s->format->Amask); + *p |= (uint32_t)dst.r << s->format->Rshift; + *p |= (uint32_t)dst.g << s->format->Gshift; + *p |= (uint32_t)dst.b << s->format->Bshift; + *p |= (uint32_t)dst.a << s->format->Ashift; + }); +} + +void DrawGraph_FillAMap(int sp_no, int x, int y, int w, int h, int a) +{ + SDL_Surface *s = DrawGraph_get_sprite(sp_no)->cg->s; + + fill_for_each_pixel(s, x, y, w, h, p, { + *p &= ~s->format->Amask; + *p |= (uint32_t)a << s->format->Ashift; + }); +}