Skip to content

GGMax Enhancement - Add image pixel editing ability. #6355

@Dr-Eyeball

Description

@Dr-Eyeball

GGMax Enhancement - Add image pixel editing ability

Summary

Request: Please add a small set of Lua-accessible functions to allow pixel-level editing of images (sprites / color-maps) in GameGuru Max.

Requirements: The goal is to read and write individual pixels in an image that is either already loaded in memory or loaded from disk.

  • Later, this would be extended to paste one small icon-sized image/sprite (eg: 16x16) onto another large map sprite (eg: 1024x1024) at a specified position

Goal: The primary goal is to progressively draw a player-discovered dungeon map.

  • (It would not make sense to provide the player with a pre-drawn map.)

Requested API (suggested names)

Minimum required functions

  • local color = ImageGetPixel(imageHandleOrFilename, x, y)
    local color = ImageGetPixel(imageHandleOrFilename, vector2 pos)
    Returns the pixel colour at integer coordinates x, y as an RGBA tuple with 8-bit channels (values 0-255).

  • local err = ImageSetPixel(imageHandleOrFilename, x, y, r, g, b, a)
    local err = ImageSetPixel(imageHandleOrFilename, vector2 pos, vector4 rgba)
    Sets the pixel at integer coordinates x, y to the specified RGBA values (0-255).

  • local err = SaveImage(Filename)
    Saves an image back to a file. This function does not appear to be exposed to the Lua functions yet.
    Eg: an image is loaded, the image pixels are modified slightly, the image is then written back to disk, or written at the next game save.

Convenience function

  • local err = PasteSpriteOnImageAtPos(destImage, srcImageOrFilename, x, y)
    Pastes srcImageOrFilename (or an already loaded image handle) onto destImage at position x, y.

Behaviour and data formats

  • Coordinate system: x and y are integer pixel coordinates. Use row-major order (left-to-right, top-to-bottom) consistent with existing image code.
  • Colour format: 8-bit per channel RGBA (r,g,b,a each 0-255).
    • The Alpha channel would allow sprites to be odd shapes and to not overwrite areas where A == 0 (transparent).
    • If A == 1 (fully opaque), it would completely replace the pixel.
    • If (0 < A < 255), you get alpha blending using LERP (out = (src * srcA + dst * (255 - srcA)) / 255)
  • Image identifiers: Accept either a filename string or an existing image handle returned by LoadImage()(?).
  • Memory model:
    If the image is not currently loaded, the function may load it into memory, perform the operation, and either keep it loaded or write it back to disk.
    If the image is a GPU texture, use a staging texture or equivalent to read/write CPU-side pixel data and then update the GPU texture.
  • Error handling: Return an integer error code on failure, or 0 on success.
    Eg: 1 = invalid imageHandle, 2 = invalid pathname, 3 = position coordinates out-of-bounds, 4 = image issue or unsupported format

Implementation notes and relevant functions

  • The engine already has code paths that read image data into CPU memory and decompress textures to RGBA. Relevant code areas to inspect:

    • CImageC.cpp
      • LoadImage(), SetImageData(), GetImageData(), DecompressImage(), ConvertDDSCompressedFormat(), LoadImageCoreFullTex().
    • DarkLUA.cpp
      • DeleteSpriteImage(), GetImageWidth(), GetImageHeight(), CreateSprite(), PasteSprite(), PasteSpritePosition(), SetSpritePosition(), SetSpriteSize(), SetSpriteColor(), SetSpriteOffset(), DeleteSprite(), SetSpriteScissor(), SetSpriteImage()
    • wickedcalls.cpp — texture staging examples; WickedCall_TextureMeshWithImagePtr().
    • global.lua — Lua bindings for existing sprite/image functions to mirror naming and calling conventions.
  • The Lua code has basic map-related image handling.

    • hud0.lua — Map filename and image loading, sprite image assignment, scissor clipping, map rendering.
  • Use the engine's existing image staging mechanism to transfer pixel data between GPU and CPU when needed.


Concerns and questions for the devs (for your consideration)

  • Image lifetime: How and when does the engine unload images from memory to free space for new images in a scene (or does it not check this)?
  • File write policy: If a filename is passed and the image is modified, should the engine write back to disk automatically, or should it only modify the in-memory image and leave saving to an explicit API?

Clarifying the image caching/unloading & file write policy will help decide whether ImageSetPixel() should force the image to remain resident, or mark it dirty for later upload, or for saving before unload.


Suggested labels

enhancement, lua, sprite, image, pixel-editing

Thank you for considering this enhancement.
These changes will enable dynamic in-game drawing (for example, progressive dungeon maps) without adding a full external graphics library.

It does not have to be optimised early on. I can also help with the analysis, optimisation, or additional functions once the relevant source code is identified or the initial image pixel get/set code is written.

Metadata

Metadata

Assignees

Labels

MaxIssues related to GameGuru Max.enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions