From 148fc8a037c0ae224bbe2cc1917dab1c12e89606 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff <timfelgentreff@gmail.com> Date: Mon, 25 Apr 2022 21:54:03 +0200 Subject: [PATCH] apply a shearing effect to generated shadows --- src/include/video.h | 2 +- src/stratagus/construct.cpp | 2 +- src/unit/script_unittype.cpp | 14 +++++++ src/unit/unittype.cpp | 2 +- src/video/graphic.cpp | 81 +++++++++++++++++++++++++++++------- 5 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/include/video.h b/src/include/video.h index 8be1aae60..9d081f401 100644 --- a/src/include/video.h +++ b/src/include/video.h @@ -169,7 +169,7 @@ public: void SetOriginalSize(); bool TransparentPixel(int x, int y); void SetPaletteColor(int idx, int r, int g, int b); - void MakeShadow(); + void MakeShadow(int xOffset, int yOffset); // minor programmatic editing features void OverlayGraphic(CGraphic *other, bool mask = false); diff --git a/src/stratagus/construct.cpp b/src/stratagus/construct.cpp index e1b72f759..219545680 100644 --- a/src/stratagus/construct.cpp +++ b/src/stratagus/construct.cpp @@ -108,7 +108,7 @@ void CConstruction::Load() this->ShadowSprite = CGraphic::ForceNew(file, this->ShadowWidth, this->ShadowHeight); this->ShadowSprite->Load(); this->ShadowSprite->Flip(); - this->ShadowSprite->MakeShadow(); + this->ShadowSprite->MakeShadow(0, 0); // FIXME: TODO: (timfel): construction shadows don't have X offset, so no shear? } } diff --git a/src/unit/script_unittype.cpp b/src/unit/script_unittype.cpp index d79dfdcfa..5788bec17 100644 --- a/src/unit/script_unittype.cpp +++ b/src/unit/script_unittype.cpp @@ -485,6 +485,9 @@ static int CclDefineUnitType(lua_State *l) // Slot identifier const char *str = LuaToString(l, 1); CUnitType *type = UnitTypeByIdent(str); + + constexpr int redefineSprite = 2; + int redefine; if (type) { redefine = 1; @@ -524,13 +527,20 @@ static int CclDefineUnitType(lua_State *l) } if (redefine) { if (type->Sprite && type->Sprite->File != type->File) { + redefine |= redefineSprite; CGraphic::Free(type->Sprite); type->Sprite = NULL; } if (type->AltSprite && type->AltSprite->File != type->AltFile) { + redefine |= redefineSprite; CGraphic::Free(type->AltSprite); type->AltSprite = NULL; } + if (redefine && type->ShadowSprite) { + redefine |= redefineSprite; + CGraphic::Free(type->ShadowSprite); + type->ShadowSprite = NULL; + } } if (type->ShadowFile == shadowMarker) { type->ShadowFile = type->File; @@ -575,6 +585,7 @@ static int CclDefineUnitType(lua_State *l) } } if (redefine && type->ShadowSprite) { + redefine |= redefineSprite; CGraphic::Free(type->ShadowSprite); type->ShadowSprite = NULL; } @@ -1210,6 +1221,9 @@ static int CclDefineUnitType(lua_State *l) } UpdateDefaultBoolFlags(*type); if (!CclInConfigFile) { + if (redefine & redefineSprite) { + LoadUnitTypeSprite(*type); + } UpdateUnitStats(*type, 1); } return 0; diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp index 1282cdcb7..c2eea6277 100644 --- a/src/unit/unittype.cpp +++ b/src/unit/unittype.cpp @@ -994,7 +994,7 @@ void LoadUnitTypeSprite(CUnitType &type) if (type.Flip) { type.ShadowSprite->Flip(); } - type.ShadowSprite->MakeShadow(); + type.ShadowSprite->MakeShadow(type.ShadowOffsetX, type.ShadowOffsetY); } } diff --git a/src/video/graphic.cpp b/src/video/graphic.cpp index 426b4a6b2..7c0404cf2 100644 --- a/src/video/graphic.cpp +++ b/src/video/graphic.cpp @@ -1154,24 +1154,75 @@ static inline void dither(SDL_Surface *Surface) { ** ** @todo FIXME: 32bpp */ -void CGraphic::MakeShadow() +void CGraphic::MakeShadow(int xOffset, int yOffset) { - if (Surface->format->BytesPerPixel == 1) { - SDL_Surface *alphaSurface = SDL_CreateRGBSurface(0, Surface->w, Surface->h, 32, RMASK, GMASK, BMASK, AMASK); - SDL_BlitSurface(Surface, NULL, alphaSurface, NULL); - SDL_SetSurfaceAlphaMod(alphaSurface, 80); - SDL_SetSurfaceColorMod(alphaSurface, 0, 0, 0); - SDL_FreeSurface(Surface); - Surface = alphaSurface; + VideoPaletteListRemove(Surface); + SDL_Surface *alphaSurface = SDL_CreateRGBSurface(0, Surface->w, Surface->h, 32, RMASK, GMASK, BMASK, AMASK); + SDL_BlitSurface(Surface, NULL, alphaSurface, NULL); + SDL_SetSurfaceAlphaMod(alphaSurface, 80); + SDL_SetSurfaceColorMod(alphaSurface, 0, 0, 0); + SDL_FreeSurface(Surface); + Surface = alphaSurface; + if (SurfaceFlip) { + VideoPaletteListRemove(SurfaceFlip); + SDL_Surface *alphaSurfaceFlip = SDL_CreateRGBSurface(0, SurfaceFlip->w, SurfaceFlip->h, 32, RMASK, GMASK, BMASK, AMASK); + SDL_BlitSurface(SurfaceFlip, NULL, alphaSurfaceFlip, NULL); + SDL_SetSurfaceAlphaMod(alphaSurfaceFlip, 80); + SDL_SetSurfaceColorMod(alphaSurfaceFlip, 0, 0, 0); + SDL_FreeSurface(SurfaceFlip); + SurfaceFlip = alphaSurfaceFlip; + } - if (SurfaceFlip) { - SDL_Surface *alphaSurfaceFlip = SDL_CreateRGBSurface(0, SurfaceFlip->w, SurfaceFlip->h, 32, RMASK, GMASK, BMASK, AMASK); - SDL_BlitSurface(SurfaceFlip, NULL, alphaSurfaceFlip, NULL); - SDL_SetSurfaceAlphaMod(alphaSurfaceFlip, 80); - SDL_SetSurfaceColorMod(alphaSurfaceFlip, 0, 0, 0); - SDL_FreeSurface(SurfaceFlip); - SurfaceFlip = alphaSurfaceFlip; + // Apply shearing effect. same angle for Surface and SurfaceFlip! + // The sun shines from the same angle on to both normal and flipped sprites :) + + // BEGIN HACK: XXX: FIXME: positive yOffset is used for fliers for now, these should not get shearing. + // We need to find a better way to communicate that. The rest of the code already supports shearing + // in both directions for y. + yOffset = std::min(0, yOffset); + // END HACK + + if (yOffset || xOffset) { + SDL_LockSurface(Surface); + uint32_t* pixels = (uint32_t *)Surface->pixels; + int pitch = Surface->pitch / sizeof(uint32_t); + for (int f = 0; f < NumFrames; f++) { + int frameX = frame_map[f].x; + int frameY = frame_map[f].y; + for (int x = xOffset > 0 ? 0 : Width - 1; xOffset > 0 ? x < Width : x >= 0; xOffset > 0 ? x++ : x--) { + for (int y = yOffset > 0 ? 0 : Height - 1; yOffset > 0 ? y < Height : y >= 0; yOffset > 0 ? y++ : y--) { + int xNew = x + xOffset * y / Height; + int yNew = y + yOffset * x / Width; + if (xNew < 0 || yNew < 0 || xNew >= Width || yNew >= Height) { + pixels[x + frameX + (y + frameY) * pitch] = 0; + } else { + pixels[x + frameX + (y + frameY) * pitch] = pixels[xNew + frameX + (yNew + frameY) * pitch]; + } + } + } } + SDL_UnlockSurface(Surface); + } + if ((yOffset || xOffset) && SurfaceFlip) { + SDL_LockSurface(SurfaceFlip); + uint32_t* pixels = (uint32_t *)SurfaceFlip->pixels; + int pitch = SurfaceFlip->pitch / sizeof(uint32_t); + for (int f = 0; f < NumFrames; f++) { + int frameX = frameFlip_map[f].x; + int frameY = frameFlip_map[f].y; + for (int x = xOffset > 0 ? 0 : Width - 1; xOffset > 0 ? x < Width : x >= 0; xOffset > 0 ? x++ : x--) { + for (int y = yOffset > 0 ? 0 : Height - 1; yOffset > 0 ? y < Height : y >= 0; yOffset > 0 ? y++ : y--) { + int xNew = x + xOffset * y / Height; + int yNew = y + yOffset * x / Width; + if (xNew < 0 || yNew < 0 || xNew >= Width || yNew >= Height) { + pixels[x + frameX + (y + frameY) * pitch] = 0; + } else { + pixels[x + frameX + (y + frameY) * pitch] = pixels[xNew + frameX + (yNew + frameY) * pitch]; + } + } + } + } + SDL_UnlockSurface(SurfaceFlip); } }