Skip to content

Latest commit

 

History

History
172 lines (125 loc) · 5.4 KB

File metadata and controls

172 lines (125 loc) · 5.4 KB

denise4j

A Java graphics effects library inspired by the demoscene of the 80s and 90s. Produces animated images from pixel sources, tile maps, and chainable effects — with no dependency on any GUI toolkit.


Available effects

Effect Method Description
Horizontal scroll scrollH(ParamInt offset) Shifts the source horizontally
Vertical scroll scrollV(ParamInt offset) Shifts the source vertically
Bilinear zoom zoom(ParamDouble factor) Zoom in/out centred on the Stage
Explicit-centre zoom zoom(ParamDouble factor, ParamDouble cx, ParamDouble cy) Explicit centre
Rotation rotate(ParamDouble angle) Clockwise rotation, Stage centre
Explicit-centre rotation rotate(ParamDouble angle, ParamDouble cx, ParamDouble cy) Explicit centre

Quick start

// 1. Pixel sources
TileSet tileSet = new TileSet(spriteSheet, 16, 16);
TileMap background = new TileMap(tileSet, 40, 30, TileMap.EdgePolicy.WRAP);
background.setTiles(0, 0, levelData);

ImageSource overlay = new ImageSource(overlayImage);

// 2. Mutable parameters (updated each frame)
ParamInt bgScroll  = new ParamInt(0);
ParamInt fgScroll  = new ParamInt(0);
ParamDouble fgZoom = new ParamDouble(1.0);

// 3. Pipeline (built once, reused every frame)
EffectPipeline pipeline = new EffectPipeline()
    .addSource(background)
        .scrollH(bgScroll)
    .addSource(overlay)
        .transparentColor(0xFF00FF00)   // color key: transparent green
        .scrollH(fgScroll)
        .zoom(fgZoom)
    .build();

// 4. Stage (output buffer)
Stage stage = new Stage(640, 480);   // black background by default

// 5. Animation loop
while (running) {
    bgScroll.add(1);
    fgScroll.add(3);
    pipeline.render(stage);

    // Display — your choice of toolkit
    Graphics g = canvas.getGraphics();
    g.drawImage(stage.getImage(), 0, 0, null);
}

Architecture

PixelSource          ← interface: any pixel source
├── ImageSource      ← wraps a BufferedImage
└── TileMap          ← tile grid (WRAP / CLIP / FEED)
        └── TileSet  ← spritesheet split into fixed-size tiles

ParamInt             ← mutable discrete parameter (pixel offset, ...)
ParamDouble          ← mutable continuous parameter (zoom factor, angle, ...)

EffectPipeline       ← effect chain — stateless, renders into a Stage
Stage                ← 32-bit ARGB pixel buffer — output to the toolkit of your choice

StagePool            ← pool of N stages for double/triple buffering
Orchestrator         ← render loop on a dedicated thread, paced at targetFps
FrameCallback        ← interface: callback invoked once per frame before rendering

PerformanceSampler   ← optional tumbling-window accumulator for FPS and render-time stats

Principles

  • Portable — no dependency on Swing, JavaFX, or SWT. The output is a BufferedImage, displayable in any toolkit or exportable to a file.
  • Stateless — the pipeline is built once, reused every frame. Only ParamInt/ParamDouble values change between frames.
  • Direct array access — pixels are read and written via the underlying int[] array (DataBufferInt), bypassing getRGB/setRGB.
  • Bilinear by default — zoom and rotation use bilinear interpolation. The integer path (pure scroll) short-circuits interpolation.

Compositing model

For each pixel (x, y) of the Stage:

  1. Initial value: stage.getBackgroundColor() (opaque black by default)
  2. For each layer, in order:
    • Transforms compute the source coordinate (sx, sy)
    • If the source is bounded (CLIP/FEED) and (sx, sy) is out of bounds → no write
    • If the source pixel matches the layer's transparentColor → no write
    • Otherwise → the source pixel overwrites the current Stage value

EdgePolicy

Value Out-of-bounds behaviour
WRAP Coordinates wrapped modulo the source dimensions (Math.floorMod)
CLIP IndexOutOfBoundsException — the pipeline never crosses the boundary
FEED Same runtime behaviour as CLIP — signals semantically that tiles are fed dynamically

Examples

Examples are located in fr.dufrenoy.imagefx.examples. Each is a standalone fullscreen application (AWT, no Swing). Press SPACE to quit.

Class Effect Image
FleursDemoExample Continuous rotation + sinusoidal zoom (mandala effect) fleurs.jpg
PaysageDemoExample Multi-directional scrolling on a 3:2 Lissajous curve paysage_montagne.jpg
ShadowDemo 5-layer parallax inspired by Shadow of the Beast — gradient sky + moon, clouds, ochre rock spires, slate menhirs generative

Maven dependency

<dependency>
  <groupId>fr.dufrenoy.imagefx</groupId>
  <artifactId>denise4j</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

Build and tests

# Compile and run tests
mvn clean install

# Run tests only
mvn test

# Formal JML verification (requires OpenJML — Linux/macOS)
mvn verify -P openjml-unix

# Formal JML verification (Windows via WSL)
mvn verify -P openjml-windows

Requirements: Java 11+, Maven 3.8+


Roadmap

  • Deformations (wave, distortion, tunnel, plasma)
  • Palette operations (cycling, fading, remapping)
  • Advanced compositing (blending, masking, overlay)

Licence

GNU Lesser General Public License v3 — see LICENCE.