ACE (Amiga C Engine)

repository·main·Indexed 42 days ago

https://github.com/amigaports/ace

A lightweight, high-performance C-based framework for game and demo development on classic Amiga hardware (OCS/AGA). ACE provides a slim Hardware Abstraction Layer (HAL) for the Blitter, Copper, Audio, Keyboard, and Mouse, allowing developers to write high-performance code that remains AmigaOS-friendly. It includes a view and viewport system, specialized tilemap scrolling, and a suite of asset conversion tools for palettes, bitmaps, sprites, fonts, and audio.

Tokens
35.4K
Snippets
91
Records
135
Agent score
53%

What's inside ACE

  1. Overview of ACE - Amiga C Engine

    main

    ACE is a lightweight, flexible, and hackable game engine and framework written entirely in C for classic Amiga hardware. It is designed to provide high performance by using Amiga hardware features directly while remaining OS-friendly, allowing applications to run from and exit to the Workbench gracefully.

    Key Characteristics:

    • Hardware Oriented: Primarily OCS-oriented, though compatible with AGA.
    • Thin Abstraction: Provides a slim Hardware Abstraction Layer (HAL) for audio, blitter, copper, keyboard, and mouse.
    • Performance Focused: Can disable the OS for maximum performance, with the ability to re-enable it for tasks like file access or memory allocation.
    • Flexible Development: Suitable for developers who want to write high-performance code in C without relying entirely on assembly, or for those learning Amiga coding via a documented HAL.
  2. What is NOT included in ACE

    main

    To maintain its lightweight and flexible nature, ACE deliberately omits certain high-level features. Developers should be aware that you will need to implement or integrate the following yourself:

    • Game Maker Experience: ACE is a code-first engine; it does not provide a visual editor or GUI for game creation.
    • Sprite Management: There is no elaborate, automated sprite management system.
    • Direct Floppy Access: There are no built-in functions for direct data reading from specific floppy sectors.
  3. Understand Amiga sprite hardware constraints

    main

    Understanding the underlying hardware is necessary for correct sprite implementation:

    • Channels: There are 8 sprite channels. Each channel has its own sprXpt register.
    • Data Structure: A sprite consists of a 2-word header (position and height), the 2BPP display data, and a 32-bit footer (pointer to the next sprite in the chain).
    • Dimensions: Standard sprites are 16px wide. On OCS/ECS, wider sprites are simulated by placing 16px sprites side-by-side. With ACE_USE_AGA_FEATURES, 32px and 64px widths are supported by setting TAG_VPORT_FMODE sprite-fetch bits (0x04 for 32px, 0x0C for 64px).
    • Color/Palette: Sprite colors are 2BPP and are mapped to the upper half of the current display palette. The mapping depends on the channel index:
      • Channels 0-1: Indices 17-19
      • Channels 2-3: Indices 21-23
      • Channels 4-5: Indices 25-27
      • Channels 6-7: Indices 29-31 (Note: Index 0 is always transparent).
    • Safety: If a channel is not in use, its sprXpt register must still point to valid data (e.g., two empty 16-bit words in CHIP memory) to prevent the hardware from displaying garbage.
  4. How to move blitted objects using retained mode

    main

    In ACE, the blitter draws directly onto a bitmap. If you move an object by drawing it in a new position without clearing its previous position, it will leave a 'trail' or visual artifact.

    Because clearing the entire display bitmap every frame is too performance-intensive for Amiga hardware, you should use retained mode. In retained mode, you only update the parts of the screen that change by following these steps:

    1. Undraw: Draw the background color over the object's old position to erase it.
    2. Update: Calculate the object's new position.
    3. Draw: Draw the object at its new position.

    If your background is a solid color (e.g., black), you can simply use blitRect with that color to 'undraw' the object before drawing it in its new location.

  5. Core features and capabilities of ACE

    main

    ACE provides several low-level and high-level systems to facilitate Amiga development:

    • Hardware Abstraction Layer (HAL): Slim interfaces for controlling the Blitter, Copper, Audio, Keyboard, and Mouse.
    • Display System: A view and viewport system inspired by AmigaOS but optimized for lower overhead.
    • Memory-Efficient Scrolling: Specialized code for scrolling large tilemaps efficiently.
    • Debugging Support: Includes runtime error checks during debug builds that are stripped out in release builds for performance.
    • Framework Layer: An optional framework to help organize game logic and reduce boilerplate code.
    • Compatibility: Requires at least Kickstart 1.3, but supports OS 2.0+ features such as taglists and interleaved bitplane modes.
  6. Optimize line drawing for single bitplanes

    main

    To achieve faster 'demo-style' line drawing on a single bitplane, you can create an 'entangled' tBitMap struct.

    1. Create a tBitMap with the same width and height as your target bitmap.
    2. Set the depth to 1.
    3. Set the first bitplane pointer to the specific bitplane you wish to draw on.

    This allows you to use the same blit functions on a specialized bitmap that targets only one bitplane, reducing overhead.

  7. Compare Bartman's vs Bebbo's compilers

    main

    Choosing between the two toolchains depends on your development stage and requirements:

    FeatureBartman's GCCBebbo's GCC
    Primary UseMain developmentRelease builds / Standard library needs
    ProsNewer GCC version, integrated debugger, easy VSCode integrationCustom optimizers for better performance/size
    ConsIncomplete standard library (ACE uses mini-std)Optimizers can occasionally break code

    Best Practices

    • Development: Use Bartman's GCC for daily coding.
    • Release: Use Bebbo's GCC for final builds to compare size and performance. If your code doesn't need the latest features, this is the preferred way to optimize.
    • Troubleshooting Bebbo's Compiler: If code breaks mysteriously:
      1. Disable optimizations in your CMakeLists.txt (change -O3 to -O0 or use -DCMAKE_BUILD_TYPE=Debug).
      2. Add -fbbb=- to your compile options to disable Bebbo's custom optimizers.
      3. If the issue persists, it is likely a bug in your code.
  8. How views and viewports work in ACE

    main

    ACE uses a hierarchical graphics model based on Views and Viewports:

    • Views: The top-level container for everything on screen. You create a view using viewCreate(). While you can have multiple views, only one can be active at a time; use viewLoad() to switch between them.
    • Viewports: Contained within a view, viewports are scrollable windows that display associated bitmaps. They can have different resolutions and palettes.

    Constraint: Due to Amiga hardware limitations, viewports must be stacked vertically (one beneath another). They cannot be placed side-by-side or overlapping.

    s_pView = viewCreate(0, TAG_VIEW_GLOBAL_PALETTE, 1, TAG_END);
    viewLoad(s_pView);
  9. What requires Amiga OS to be enabled

    main

    Certain ACE features and system operations require the Amiga OS to be enabled. If you disable the OS via systemUnuse(), the following will not function correctly:

    • Memory Management: Most functions in ace/managers/memory.h.
    • Logging: All ace/managers/log.h functions (specifically when creating files or running in debug mode).
    • File/Directory Access: All ace/utils/file.h and ace/utils/dir.h functions.
    • System Resources: Usage of system .library and .device files.
    • Inter-process Communication: Multithreading and communicating with other applications.
  10. Understand the ACE architecture: Utils, Managers, and Viewport Managers

    main

    ACE organizes functionality into three distinct categories to manage resources and hardware:

    Utils

    Used for managing small or multiple resources of the same kind (e.g., bitmaps, files, fonts, viewports). They also simplify specific tasks like chunky processing or hardware register access.

    • Lifecycle: When you create a resource via a util (e.g., pBm = bitmapCreate(...)), you are responsible for manually freeing it using its dedicated destruction function (e.g., bitmapDestroy(pBm)).
    • Usage: Functions in a util typically take the resource pointer as the first parameter (e.g., bitmapGetByteWidth(pBm)).

    Managers

    Responsible for managing a single global resource (e.g., blitter, audio).

    • Lifecycle: You initialize a manager once using a create or open function (e.g., blitManagerCreate()) and clean it up once at the end of the program using a destroy or close counterpart (e.g., blitManagerDestroy()).
    • Usage: Manager functions (e.g., blitRect(), blitCopy()) are called throughout the program execution.

    Viewport Managers

    A specialized layer built on top of the manager/util system to handle display logic.

    • Camera Manager: Tracks the currently displayed rectangle within a larger playfield.
    • Buffer Manager: Manages the bitmap buffer used for display. It handles heavy lifting like scrolling (e.g., folding a background buffer on the Y axis) and managing tile buffers for drawing.
  11. Optimize trigonometric calculations using brads

    main

    The standard fix16_sin() and fix16_cos() functions accept angles in fixed-point format, which can be slow. To speed up calculations, you can use brads (byte-radians).

    Brads Concept:

    • Store angles in a single byte (0 to 255).
    • 0 represents $0^\circ$.
    • 255 represents approximately $360^\circ$.

    Benefits:

    • Allows you to precalculate trigonometric values into a lookup table (array).
    • Significantly faster than calculating sine/cosine at runtime.

    Implementation Tip: You can further optimize by limiting the angle range (e.g., 0..127 or 0..63) to reduce the size of your lookup table, but be careful to manage potential overflows and underflows.

  12. Use viewport managers to handle display buffers

    main

    A viewport requires a Viewport Manager to actually display content. ACE provides three types of managers depending on your performance and memory needs:

    1. Simple Buffer Manager (simpleBufferCreate): Allocates a display bitmap exactly matching the viewport size. It is easy to use but uses significant memory because it works on plain bitmaps, making it unsuitable for large scrollable backgrounds (e.g., RTS or Shmups).
    2. Scroll Buffer Manager (scrollBufferCreate): Allocates a bitmap slightly larger than the viewport. It wraps the buffer vertically and reserves extra lines to allow for efficient, finite horizontal scrolling and off-screen drawing.
    3. Tile Buffer Manager (tileBufferCreate): A derivative of the scroll buffer manager. It facilitates large scrolls and automatically manages background drawing using tilemaps. This is the recommended choice for most games.