From a4b6703d12874fae1de616c4d80087a2244159cb Mon Sep 17 00:00:00 2001 From: Matteo Benedetto Date: Wed, 13 Aug 2025 23:50:21 +0200 Subject: [PATCH] Enhance blood stain handling: combine existing and new blood surfaces for better accumulation and add surface management --- engine/graphics.py | 21 ++++++++-- engine/sdl2.py | 95 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 11 deletions(-) diff --git a/engine/graphics.py b/engine/graphics.py index dc12dcd..3c58f49 100644 --- a/engine/graphics.py +++ b/engine/graphics.py @@ -47,11 +47,24 @@ class Graphics(): if not hasattr(self, 'blood_stains'): self.blood_stains = {} - # Generate blood surface - blood_surface = self.render_engine.generate_blood_surface() - self.blood_stains[position] = blood_surface + # Generate new blood surface + new_blood_surface = self.render_engine.generate_blood_surface() - # Regenerate background to include the new blood stain + if position in self.blood_stains: + # If there's already a blood stain at this position, combine them + existing_surface = self.blood_stains[position] + combined_surface = self.render_engine.combine_blood_surfaces(existing_surface, new_blood_surface) + + # Free the old surfaces + self.render_engine.free_surface(existing_surface) + self.render_engine.free_surface(new_blood_surface) + + self.blood_stains[position] = combined_surface + else: + # First blood stain at this position + self.blood_stains[position] = new_blood_surface + + # Regenerate background to include the updated blood stain self.regenerate_background() def scroll_cursor(self, x=0, y=0): diff --git a/engine/sdl2.py b/engine/sdl2.py index cc4ac0f..6a7b87c 100644 --- a/engine/sdl2.py +++ b/engine/sdl2.py @@ -304,13 +304,13 @@ class GameWindow: pixels = cast(blood_surface.contents.pixels, POINTER(c_uint32)) pitch = blood_surface.contents.pitch // 4 # pitch in pixel (32-bit) - # Colori del sangue (variazioni di rosso) + # Colori del sangue (variazioni di rosso in formato ABGR) blood_colors = [ - 0xFF8B0000, # Rosso scuro - 0xFFB22222, # Rosso mattone - 0xFFDC143C, # Cremisi - 0xFFFF0000, # Rosso puro - 0xFF800000, # Marrone + 0xFF00008B, # Rosso scuro (A=FF, B=00, G=00, R=8B) + 0xFF002222, # Rosso mattone (A=FF, B=00, G=22, R=22) + 0xFF003C14, # Cremisi (A=FF, B=00, G=3C, R=14) + 0xFF0000FF, # Rosso puro (A=FF, B=00, G=00, R=FF) + 0xFF000080, # Marrone rossastro (A=FF, B=00, G=00, R=80) ] # Genera la macchia con un algoritmo di diffusione @@ -385,4 +385,85 @@ class GameWindow: # Create texture from the temporary surface texture = self.factory.from_surface(temp_surface) sdl2.SDL_FreeSurface(temp_surface) - return texture \ No newline at end of file + return texture + + def combine_blood_surfaces(self, existing_surface, new_surface): + """Combine two blood surfaces by blending them together""" + # Create a new surface for the combined result + combined_surface = sdl2.SDL_CreateRGBSurface( + 0, self.cell_size, self.cell_size, 32, + 0x000000FF, # R mask + 0x0000FF00, # G mask + 0x00FF0000, # B mask + 0xFF000000 # A mask + ) + + if combined_surface is None: + return existing_surface + + # Lock both surfaces for pixel manipulation + sdl2.SDL_LockSurface(existing_surface) + sdl2.SDL_LockSurface(new_surface) + sdl2.SDL_LockSurface(combined_surface) + + # Get pixel data + existing_pixels = cast(existing_surface.contents.pixels, POINTER(c_uint32)) + new_pixels = cast(new_surface.contents.pixels, POINTER(c_uint32)) + combined_pixels = cast(combined_surface.contents.pixels, POINTER(c_uint32)) + + pitch = combined_surface.contents.pitch // 4 # pitch in pixels (32-bit) + + # Combine pixels manually for better blending + for y in range(self.cell_size): + for x in range(self.cell_size): + idx = y * pitch + x + + existing_pixel = existing_pixels[idx] + new_pixel = new_pixels[idx] + + # Extract RGBA components + existing_a = (existing_pixel >> 24) & 0xFF + existing_r = (existing_pixel >> 16) & 0xFF + existing_g = (existing_pixel >> 8) & 0xFF + existing_b = existing_pixel & 0xFF + + new_a = (new_pixel >> 24) & 0xFF + new_r = (new_pixel >> 16) & 0xFF + new_g = (new_pixel >> 8) & 0xFF + new_b = new_pixel & 0xFF + + # Blend the colors (additive blending for blood accumulation) + if new_a > 0: # If new pixel has color + if existing_a > 0: # If existing pixel has color + # Combine both colors, making it darker/more opaque + final_r = min(255, existing_r + (new_r // 2)) + final_g = min(255, existing_g + (new_g // 2)) + final_b = min(255, existing_b + (new_b // 2)) + final_a = min(255, existing_a + (new_a // 2)) + else: + # Use new pixel color + final_r = new_r + final_g = new_g + final_b = new_b + final_a = new_a + else: + # Use existing pixel color + final_r = existing_r + final_g = existing_g + final_b = existing_b + final_a = existing_a + + # Pack the final pixel + combined_pixels[idx] = (final_a << 24) | (final_r << 16) | (final_g << 8) | final_b + + # Unlock surfaces + sdl2.SDL_UnlockSurface(existing_surface) + sdl2.SDL_UnlockSurface(new_surface) + sdl2.SDL_UnlockSurface(combined_surface) + + return combined_surface + + def free_surface(self, surface): + """Safely free an SDL surface""" + if surface is not None: + sdl2.SDL_FreeSurface(surface) \ No newline at end of file