Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ res/keeperfx_icon.ico
/src/ver_defs.h
keeperfx.log
crash_log.txt
.local/
22 changes: 16 additions & 6 deletions config/fxdata/lenses.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ Name = LENS_WIBBLE
; For displacement kind=1, following parameters are:
; magnitude and period
Displacement = 1 9 10
; Overlay has two parameters: file name of a RAW texture (or name of a custom lens),
; Alpha transparency scaled 0..255, where 255 is fully opaque
; Overlay = frac00.raw 0
; Overlay effect parameters (can be combined with Mist, which renders first):
; 1. File name of a RAW texture (or name of a custom lens overlay)
; 2. Alpha transparency 0..255 (0=transparent, 255=fully opaque)
; Note: Palette index 255 in overlay files is treated as transparent
; Overlay = frac00.raw 0

[lens2]
Name = FISH_EYE
Expand All @@ -29,9 +31,17 @@ Displacement = 3 1 1

[lens4]
Name = MIST_WATER
; Mist effect has three parameters: file name of a RAW texture (or name of a custom lens),
; lightness scaled 0..63, and ghost position (irrelevant)
Mist = frac00.raw 0 0
; Mist effect parameters:
; 1. File name of a RAW texture (or name of a custom lens)
; 2. Lightness scaled 0..63 (0=darkest, 63=lightest)
; 3. Ghost position 0..255 (transparency effect)
; 4-7. Optional animation parameters (0..255):
; 4. Primary layer X movement speed (default: 2)
; 5. Primary layer Y movement speed (default: 1)
; 6. Secondary layer X movement speed (default: 253)
; 7. Secondary layer Y movement speed (default: 3)
; Set all to 0 for static/frozen mist (no animation)
Mist = frac00.raw 0 0 2 1 253 3

[lens5]
Name = MIST_TWO_LAYERED_WATER
Expand Down
9 changes: 4 additions & 5 deletions src/config_lenses.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ const struct NamedField lenses_data_named_fields[] = {
{"MIST", 0, field(lenses_conf.lenses[0].mist_file), 0, 0, 0, NULL, value_mist, assign_null},
{"MIST", 1, field(lenses_conf.lenses[0].mist_lightness), 0, 0, 63, NULL, value_default, assign_default},
{"MIST", 2, field(lenses_conf.lenses[0].mist_ghost), 0, 0, 255, NULL, value_default, assign_default},
{"MIST", 3, field(lenses_conf.lenses[0].mist_pos_x_step), 2, 0, 255, NULL, value_default, assign_default},
{"MIST", 4, field(lenses_conf.lenses[0].mist_pos_y_step), 1, 0, 255, NULL, value_default, assign_default},
{"MIST", 5, field(lenses_conf.lenses[0].mist_sec_x_step), 253, 0, 255, NULL, value_default, assign_default},
{"MIST", 6, field(lenses_conf.lenses[0].mist_sec_y_step), 3, 0, 255, NULL, value_default, assign_default},
{"DISPLACEMENT", 0, field(lenses_conf.lenses[0].displace_kind), 0, 0, 255, NULL, value_default, assign_default},
{"DISPLACEMENT", 1, field(lenses_conf.lenses[0].displace_magnitude), 0, 0, 511, NULL, value_default, assign_default},
{"DISPLACEMENT", 2, field(lenses_conf.lenses[0].displace_period), 1, 0, 511, NULL, value_displace, assign_default},
Expand Down Expand Up @@ -124,11 +128,6 @@ static int64_t value_overlay(const struct NamedField* named_field, const char* v
lenses_conf.lenses[idx].flags |= LCF_HasOverlay;
struct LensConfig* lenscfg = &lenses_conf.lenses[idx];

// Clear mist flag and mist_file if this lens only has an overlay
// This prevents garbage mist data from previous lens configurations
lenscfg->flags &= ~LCF_HasMist;
lenscfg->mist_file[0] = '\0';

// Only store the overlay name when processing position 0 (the name field)
// Position 1 is the alpha value, handled by value_default
if (named_field->argnum == 0)
Expand Down
4 changes: 4 additions & 0 deletions src/config_lenses.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ struct LensConfig {
short mist_lightness;
short mist_ghost;
char mist_file[DISKPATH_SIZE];
short mist_pos_x_step;
short mist_pos_y_step;
short mist_sec_x_step;
short mist_sec_y_step;
short displace_kind;
short displace_magnitude;
short displace_period;
Expand Down
45 changes: 36 additions & 9 deletions src/lens_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ void setup_eye_lens(long nlens)
}
if (nlens == 0)
{
// Switching to no lens - free mist to reset state
free_mist();
game.active_lens_type = 0;
game.applied_lens_type = 0;
return;
Expand All @@ -461,6 +463,13 @@ void setup_eye_lens(long nlens)
game.applied_lens_type = nlens;
return;
}

// Clear the spare screen buffer when switching lenses to prevent corruption
// This ensures we don't have stale data from previous lens renders
if (eye_lens_spare_screen_memory != NULL) {
memset(eye_lens_spare_screen_memory, 0, (eye_lens_width * eye_lens_height) * sizeof(TbPixel));
}

struct LensConfig* lenscfg = get_lens_config(nlens);
if ((lenscfg->flags & LCF_HasMist) != 0)
{
Expand Down Expand Up @@ -494,7 +503,11 @@ void setup_eye_lens(long nlens)

setup_mist((unsigned char *)eye_lens_memory,
&pixmap.fade_tables[(lenscfg->mist_lightness)*256],
&pixmap.ghost[(lenscfg->mist_ghost)*256]);
&pixmap.ghost[(lenscfg->mist_ghost)*256],
(unsigned char)lenscfg->mist_pos_x_step,
(unsigned char)lenscfg->mist_pos_y_step,
(unsigned char)lenscfg->mist_sec_x_step,
(unsigned char)lenscfg->mist_sec_y_step);
}
if ((lenscfg->flags & LCF_HasDisplace) != 0)
{
Expand Down Expand Up @@ -544,11 +557,13 @@ void reinitialise_eye_lens(long nlens)
SYNCDBG(18,"Finished");
}

static void draw_displacement_lens(unsigned char *dstbuf, unsigned char *srcbuf, uint32_t *lens_mem, int width, int height, int dstpitch)
static void draw_displacement_lens(unsigned char *dstbuf, unsigned char *srcbuf, uint32_t *lens_mem, int width, int height, int dstpitch, int lens_pitch)
{
SYNCDBG(16,"Starting");
unsigned char* dst = dstbuf;
uint32_t* mem = lens_mem;
// srcbuf is the full screen buffer - pos_map indexes into it correctly
// lens_pitch is the width of the displacement map (full screen width)
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++)
Expand All @@ -558,6 +573,8 @@ static void draw_displacement_lens(unsigned char *dstbuf, unsigned char *srcbuf,
mem++;
}
dst += dstpitch;
// Skip to the next row in the displacement map if it's wider than our render width
mem += (lens_pitch - width);
}
}

Expand Down Expand Up @@ -650,7 +667,7 @@ static void draw_overlay(unsigned char *dstbuf, long dstpitch, long width, long
}
}

void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf, long srcpitch, long width, long height, long effect)
void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf, long srcpitch, long width, long height, long viewport_x, long effect)
{
long copied = 0;
if ((effect < 1) || (effect > lenses_conf.lenses_count))
Expand All @@ -660,9 +677,13 @@ void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbu
effect = 0;
}
struct LensConfig* lenscfg = &lenses_conf.lenses[effect];

// For sequential operations (mist, copy), offset srcbuf by viewport_x
unsigned char* viewport_srcbuf = srcbuf + viewport_x;

if ((lenscfg->flags & LCF_HasMist) != 0)
{
draw_mist(dstbuf, dstpitch, srcbuf, srcpitch, width, height);
draw_mist(dstbuf, dstpitch, viewport_srcbuf, srcpitch, width, height);
copied = true;
}
if ((lenscfg->flags & LCF_HasDisplace) != 0)
Expand All @@ -671,12 +692,18 @@ void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbu
{
case 1:
case 2:
draw_displacement_lens(dstbuf, srcbuf, eye_lens_memory,
width, height, dstpitch);
// For displacement, use full srcbuf (not offset) because displacement map contains absolute positions
// Offset the displacement map to start at the viewport position
long full_width = eye_lens_width;
uint32_t* viewport_lens_mem = eye_lens_memory + viewport_x;
draw_displacement_lens(dstbuf, srcbuf, viewport_lens_mem,
width, height, dstpitch, full_width);
copied = true;
break;
case 3:
flyeye_blitsec(srcbuf, srcpitch, dstbuf, dstpitch, 1, height);
// Flyeye effect uses its own optimized blitting function that handles displacement internally
// It also expects the full srcbuf and uses the viewport_x internally for lookups, so we pass the full srcbuf
flyeye_blitsec(viewport_srcbuf, srcpitch, dstbuf, dstpitch, 1, height);
copied = true;
break;
}
Expand All @@ -691,7 +718,7 @@ void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbu
// First, copy the source buffer to destination if not already done
if (!copied)
{
draw_copy(dstbuf, dstpitch, srcbuf, srcpitch, width, height);
draw_copy(dstbuf, dstpitch, viewport_srcbuf, srcpitch, width, height);
}
// Load overlay if not already loaded
if (load_overlay_image(effect)) {
Expand All @@ -704,7 +731,7 @@ void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbu
// If we haven't copied the buffer to screen yet, do so now
if (!copied)
{
draw_copy(dstbuf, dstpitch, srcbuf, srcpitch, width, height);
draw_copy(dstbuf, dstpitch, viewport_srcbuf, srcpitch, width, height);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/lens_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void initialise_eye_lenses(void);
void setup_eye_lens(long nlens);
void reinitialise_eye_lens(long nlens);
void reset_eye_lenses(void);
void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf, long srcpitch, long width, long height, long effect);
void draw_lens_effect(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf, long srcpitch, long width, long height, long viewport_x, long effect);
/******************************************************************************/
#ifdef __cplusplus
}
Expand Down
24 changes: 15 additions & 9 deletions src/lens_mist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ class CMistFade {
public:
CMistFade(void);
virtual ~CMistFade(void);
void setup(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost);
void setup(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost,
unsigned char pos_x_step, unsigned char pos_y_step,
unsigned char sec_x_step, unsigned char sec_y_step);
void animset(long a1, long a2);
void mist(unsigned char *dstbuf, long dstwidth, unsigned char *srcbuf, long srcwidth, long width, long height);
void animate(void);
Expand All @@ -56,7 +58,9 @@ class CMistFade {
CMistFade *mist = NULL;
/******************************************************************************/

void CMistFade::setup(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost)
void CMistFade::setup(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost,
unsigned char pos_x_step, unsigned char pos_y_step,
unsigned char sec_x_step, unsigned char sec_y_step)
{
this->lens_data = lens_mem;
this->fade_data = fade;
Expand All @@ -68,10 +72,10 @@ void CMistFade::setup(unsigned char *lens_mem, unsigned char *fade, unsigned cha
this->secondary_offset_y = 128;
this->animation_speed = 1024;
this->animation_counter = 0;
this->position_x_step = 2;
this->position_y_step = 1;
this->secondary_x_step = 253;
this->secondary_y_step = 3;
this->position_x_step = pos_x_step;
this->position_y_step = pos_y_step;
this->secondary_x_step = sec_x_step;
this->secondary_y_step = sec_y_step;
}

void CMistFade::animset(long a1, long a2)
Expand Down Expand Up @@ -161,7 +165,7 @@ void CMistFade::mist(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf

CMistFade::CMistFade(void)
{
setup(NULL, NULL, NULL);
setup(NULL, NULL, NULL, 2, 1, 253, 3);
}

CMistFade::~CMistFade(void)
Expand All @@ -181,12 +185,14 @@ TbBool draw_mist(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf, lo
return true;
}

void setup_mist(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost)
void setup_mist(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost,
unsigned char pos_x_step, unsigned char pos_y_step,
unsigned char sec_x_step, unsigned char sec_y_step)
{
SYNCDBG(8,"Starting");
if (mist == NULL)
mist = new CMistFade();
mist->setup(lens_mem, fade, ghost);
mist->setup(lens_mem, fade, ghost, pos_x_step, pos_y_step, sec_x_step, sec_y_step);
mist->animset(0, 1024);
}

Expand Down
4 changes: 3 additions & 1 deletion src/lens_mist.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
extern "C" {
#endif
/******************************************************************************/
void setup_mist(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost);
void setup_mist(unsigned char *lens_mem, unsigned char *fade, unsigned char *ghost,
unsigned char pos_x_step, unsigned char pos_y_step,
unsigned char sec_x_step, unsigned char sec_y_step);
TbBool draw_mist(unsigned char *dstbuf, long dstpitch, unsigned char *srcbuf, long srcpitch, long width, long height);
void free_mist(void);
/******************************************************************************/
Expand Down
3 changes: 2 additions & 1 deletion src/thing_creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -4286,8 +4286,9 @@ void draw_creature_view(struct Thing *thing)
// Draw the buffer on real screen using actual viewport dimensions
setup_engine_window(0, 0, MyScreenWidth, MyScreenHeight);
// Apply lens effect to the viewport area only (not including sidebar)
// Pass full srcbuf so displacement map lookups work correctly
draw_lens_effect(lbDisplay.WScreen + view_x, lbDisplay.GraphicsScreenWidth,
scrmem + view_x, eye_lens_width, view_width, view_height, game.applied_lens_type);
scrmem, eye_lens_width, view_width, view_height, view_x, game.applied_lens_type);
}

struct Thing *get_creature_near_for_controlling(PlayerNumber plyr_idx, MapCoord x, MapCoord y)
Expand Down