mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 00:02:23 +02:00
CLOSES #223, CLOSES #233, CLOSES #236, CLOSES #240, CLOSES #241, CLOSES #249, CLOSES #252, CLOSES #255, CLOSES #257, CLOSES #258, CLOSES #263, CLOSES #265, CLOSES #274, CLOSES #275, CLOSES #276, CLOSES #279, CLOSES #280, CLOSES #282, CLOSES #283, CLOSES #287, CLOSES #291, CLOSES #292, CLOSES #293, CLOSES #301, CLOSES #304, CLOSES #315, CLOSES #316, CLOSES #317, CLOSES #321, CLOSES #322, CLOSES #330
This commit is contained in:
+90
-24
@@ -93,6 +93,25 @@ function PaletteFX.ogObj()
|
||||
return PaletteFX.GBC_OBJ, "gbcobj"
|
||||
end
|
||||
|
||||
-- The DMG object ramp every mode except OG RED bakes onto overworld sprites,
|
||||
-- plus its cache group (same two-value contract as ogObj). Entry 1 is never
|
||||
-- read -- SpriteRenderer.getObpImage keys OBJ color 0 to alpha, the hardware's
|
||||
-- unconditional OBJ transparency -- and entries 2..4 are OBJ colors 1..3 sent
|
||||
-- through rOBP0 = $D0 (home/fade.asm FadePal4 `dc 3,1,0,0`, the entry
|
||||
-- LoadGBPal reads while wMapPalOffset is 0): color 1 -> DMG shade 0, color 2
|
||||
-- -> shade 1, color 3 -> shade 3. Leaving the result in DMG shades is the
|
||||
-- whole point: the zone shader then colors a character out of the same map
|
||||
-- palette it colors the ground with, which is all the Super Game Boy can do to
|
||||
-- an OBJ (#301), and the OBP0 lift is what puts Red's cap on the ROUTE
|
||||
-- palette's grass green instead of its light-blue (#150).
|
||||
PaletteFX.OBP0_SHADES = {
|
||||
{ 255, 255, 255 }, { 255, 255, 255 }, { 170, 170, 170 }, { 0, 0, 0 },
|
||||
}
|
||||
|
||||
function PaletteFX.dmgObj()
|
||||
return PaletteFX.OBP0_SHADES, "obp0"
|
||||
end
|
||||
|
||||
local INV_MAP = { [0] = 3, [1] = 2, [2] = 1, [3] = 0 }
|
||||
|
||||
function PaletteFX.shader()
|
||||
@@ -207,32 +226,45 @@ function PaletteFX.usesGbcPack(mode)
|
||||
end
|
||||
|
||||
-- Whether the active mode bakes a per-OBJ palette onto overworld sprites
|
||||
-- (the OBP bake + post-zone redraw path). OG RED and SGB both do: characters
|
||||
-- wear the GBC boot-ROM object palette (PaletteFX.ogObj -- green over Red's red
|
||||
-- background, pink over Blue's blue background), so the player and NPCs carry a
|
||||
-- fixed object color instead of tinting with whatever region palette their
|
||||
-- feet stand over. On real hardware a sprite is an OBJ colored by an OBJ
|
||||
-- palette (color/sprites.asm ColorOverworldSprite), distinct from the BG it
|
||||
-- overlaps -- so Red's cap must stay green in tall grass, not turn the ROUTE
|
||||
-- palette's light-blue (issue #150: SGB region-tinting sent the cap to shade-2
|
||||
-- = light-blue and the character clashed with the grass it should blend into).
|
||||
-- Terrain is unaffected -- pal() below still hands SGB its per-map BG palette;
|
||||
-- only OG RED short-circuits BG to the one global red palette. An EARLIER
|
||||
-- attempt at per-sprite SGB color baked GBC_BG (the RED background ramp) onto
|
||||
-- (the OBP bake + post-zone redraw path). OG RED alone does: the Game Boy
|
||||
-- Color boot ROM hands the game one global object palette (PaletteFX.ogObj --
|
||||
-- green over Red's red background, pink over Blue's blue background), so on
|
||||
-- that machine the player and NPCs carry a fixed object color instead of
|
||||
-- tinting with whatever region palette their feet stand over. An EARLIER
|
||||
-- attempt at per-sprite color baked GBC_BG (the RED background ramp) onto
|
||||
-- characters -- that was the "reds coloring on the player/NPCs" bug; the object
|
||||
-- palette is GBC_OBJ (green), so baking it here is the fix, not that
|
||||
-- regression. RED++ colors sprites through the usesGbcPack() path in
|
||||
-- SpriteRenderer instead.
|
||||
-- palette is GBC_OBJ (green), so baking that here is the fix, not that
|
||||
-- regression. Terrain is unaffected -- pal() below still hands SGB its per-map
|
||||
-- BG palette; only OG RED short-circuits BG to the one global red palette.
|
||||
--
|
||||
-- SGB does NOT. The Super Game Boy colorizes the composited DMG picture it is
|
||||
-- handed and cannot tell an OBJ pixel from a BG one; pokered never sends the
|
||||
-- OBJ_TRN packet that would enable SGB sprite mode (data/sgb/sgb_packets.asm
|
||||
-- defines ATTR_BLK / PAL_SET / PAL_TRN / MLT_REQ / CHR_TRN / PCT_TRN and
|
||||
-- nothing else), so a character there wears the very palette its map does.
|
||||
-- Baking GBC_OBJ over it was issue #301 ("people in SGB mode are green": the
|
||||
-- boot-ROM greens sat on top of ROUTE's own greens and blues). What issue
|
||||
-- #150 actually caught was the missing rOBP0 step, not a missing object
|
||||
-- palette: overworld OBJs run through OBP0 = $D0 (home/fade.asm FadePal4
|
||||
-- `dc 3,1,0,0`), which lifts OBJ color 1 to DMG shade 0 and color 2 to shade 1,
|
||||
-- so Red's cap lands on the ROUTE palette's shade-1 GRASS GREEN and blends into
|
||||
-- the grass exactly as #150's reference shot shows. Drawn with an identity
|
||||
-- shade map it landed on shade 2 = light-blue instead, which is the clash #150
|
||||
-- reported. SpriteRenderer bakes that OBP0 ramp (PaletteFX.dmgObj) and lets
|
||||
-- the zone shader color the result. RED++ colors sprites through the
|
||||
-- usesGbcPack() path in SpriteRenderer instead.
|
||||
function PaletteFX.usesSpriteObp(mode)
|
||||
mode = mode or PaletteFX.mode
|
||||
return mode == "ogred" or mode == "gbc"
|
||||
return mode == "ogred"
|
||||
end
|
||||
|
||||
-- ------- post-zone sprite redraw (GBC mode)
|
||||
-- ------- post-zone sprite redraw (OG RED)
|
||||
--
|
||||
-- In GBC mode the world canvas still runs through the per-map zone
|
||||
-- In OG RED the world canvas still runs through the whole-screen zone
|
||||
-- shade-remap shader, which would corrupt an OBP-baked sprite's true-color
|
||||
-- pixels. So SpriteRenderer draws the baked sprite into the canvas (its
|
||||
-- pixels. (SGB used to come through here too; it no longer bakes an object
|
||||
-- palette at all, so its characters are colorized by the zone like the ground
|
||||
-- they stand on and never queue a replay -- see usesSpriteObp, #301.) So SpriteRenderer draws the baked sprite into the canvas (its
|
||||
-- pixels come out zone-tinted there) AND records the draw here;
|
||||
-- Renderer:endFrame replays the list on top of the finished zone pass,
|
||||
-- scaled into screen space -- the GBC's OBJ-over-BG compositing, one draw
|
||||
@@ -534,6 +566,34 @@ function PaletteFX.permute(colors, map)
|
||||
colors[map[2] + 1], colors[map[3] + 1] }
|
||||
end
|
||||
|
||||
-- ------- global shade map (rBGP)
|
||||
--
|
||||
-- home/fade.asm's LoadGBPal writes ONE rBGP for the whole screen, indexing
|
||||
-- FadePal4 - wMapPalOffset. A dark cave sets wMapPalOffset = 6
|
||||
-- (home/overworld.asm's ROCK_TUNNEL_1F check; the value rides in the extracted
|
||||
-- field.darkMaps.palOffset), which lands on FadePal2 = `dc 3,3,3,2`: DMG white
|
||||
-- drops to shade 2 and every darker shade goes to shade 3. So the WHOLE
|
||||
-- screen darkens -- the original never cuts a window of light around the
|
||||
-- player (#322) -- and FLASH clears wMapPalOffset again
|
||||
-- (engine/menus/start_sub_menus.asm .flash).
|
||||
--
|
||||
-- Renderer:beginFrame clears this every frame and the state that draws a dark
|
||||
-- map re-arms it while it draws, so it can never outlive the map it belongs
|
||||
-- to: a battle or a full-screen menu draws with no map beneath it and comes
|
||||
-- out lit, exactly like init_battle_variables.asm's `ld [wMapPalOffset], a`
|
||||
-- leaves the original.
|
||||
PaletteFX.DARK_BGP = { [0] = 2, [1] = 3, [2] = 3, [3] = 3 }
|
||||
|
||||
local shadeMap = nil
|
||||
|
||||
function PaletteFX.setShadeMap(map)
|
||||
shadeMap = map
|
||||
end
|
||||
|
||||
function PaletteFX.shadeMap()
|
||||
return shadeMap
|
||||
end
|
||||
|
||||
function PaletteFX.setMode(mode)
|
||||
local prev = PaletteFX.mode
|
||||
local ok = false
|
||||
@@ -623,16 +683,22 @@ end
|
||||
function PaletteFX.effectiveColors(c)
|
||||
if not c then return nil end
|
||||
local mode = PaletteFX.mode or "gbc"
|
||||
local out = c
|
||||
if mode == "og" then
|
||||
return PaletteFX.GRAYS
|
||||
out = PaletteFX.GRAYS
|
||||
elseif mode == "og_inv" then
|
||||
return PaletteFX.permute(PaletteFX.GRAYS, INV_MAP)
|
||||
out = PaletteFX.permute(PaletteFX.GRAYS, INV_MAP)
|
||||
elseif mode == "classic" then
|
||||
return PaletteFX.CLASSIC
|
||||
out = PaletteFX.CLASSIC
|
||||
elseif mode == "gbc_inv" then
|
||||
return PaletteFX.permute(c, INV_MAP)
|
||||
out = PaletteFX.permute(c, INV_MAP)
|
||||
end
|
||||
return c
|
||||
-- The shade map goes on LAST: rBGP is a hardware register write, so it
|
||||
-- composes on top of whatever colors the display mode settled on -- a dark
|
||||
-- cave has to read dark in CLASSIC's pea greens and in plain DMG grays too
|
||||
-- (#322). permute() is the identity (and returns `out` itself, which the
|
||||
-- mod-graphics parity check leans on) while nothing has armed one.
|
||||
return PaletteFX.permute(out, shadeMap)
|
||||
end
|
||||
|
||||
-- send a 4-color (0-255 RGB) palette to the shade-remap shader, after
|
||||
|
||||
Reference in New Issue
Block a user