-
Notifications
You must be signed in to change notification settings - Fork 0
Amiga 3D Render Process
Navigation: Home - Graphics - Amiga 3D Render Process
Based on the reverse-engineering documentation (15-3d-view-and-game-screen.md), the 3D first-person view on the Amiga version of Might and Magic 2 does not use modern polygon rendering or flat-color fills. Instead, it composites every frame entirely by blitting (pasting) pre-rendered 2D image sprites back-to-front (painter's algorithm).
Here is the detailed step-by-step breakdown of how a frame is constructed.
When loading into an area, an environment dispatcher (0x1786..0x187E) loads specific graphics sheets into global memory pointers based on the area type (town, cavern, castle, or outdoors). Each sheet carries its own 32-entry Amiga color palette.
-
Walls: e.g.,
town.32,cave.32,castle.32(contains multi-resolution sprites for depth scaling). -
Floor: e.g.,
townf.32,cavef.32. -
Ceiling: e.g.,
townt.32,cavet.32. -
Outdoor Sheets:
outdoor1.32,outdoor2.32, etc.
Because there are no flat-color polygons, the "color" of an area (e.g., inside vs. outside) is simply determined by which set of image sheets is currently loaded.
When rendering an indoor dungeon or town, the game builds a 208x120 pixel viewport (stacked as a 60px ceiling/sky and a 60px floor) through the following sequence:
- Input Latch Clear: The engine clears the input latch so it doesn't process stale input during the draw cycle.
-
Floor Backdrop: The engine blits the appropriate floor sheet (
townf.32, etc.) at the bottom of the viewport (y=68, x=8). -
Ceiling/Sky Backdrop: The engine blits the ceiling or sky sheet at the top (
y=8, x=8). It chooses frame 0 or 1 of the sky sheet based on a flag that indicates if the ceiling is closed or open. - Frustum Clear: The engine clears out an array of 20 "frustum" slots in memory, which represent the visible cells in front of the player.
-
Cell Builder (
0x2900): The engine reads the rawmap.dat(page 0 visual bytes) around the player's current position and facing. It extracts the 2-bit wall codes (open, wall, wall+torch, door) for the surrounding grid and populates the 20 frustum slots. -
Wall Painting (Back-to-Front):
- The engine loops through the populated frustum slots from furthest depth to closest (painter's algorithm).
- For each valid wall, it calls one of three specific wall-piece primitives: front, left side, or right side.
- These primitives use hardcoded lookup tables based on depth (
0..3) to determine the exact screenx, ycoordinates and which size frame to pick from the multi-resolution wall sheet (e.g.town.32). Deeper cells automatically pick smaller frames. - For instance, the absolute nearest front wall (depth 0) is a 160x92 sprite placed exactly at
(32, 23).
- Flush & Advance: The renderer flushes the draw queue and increments the animation frame counter.
The outdoor surface world is drawn via a completely separate rendering path. It doesn't use the indoor wall frustum, but rather layers horizon bands and terrain decor.
-
Backdrops: It paints the outdoor floor (
outf.32) and the sky sheet, similar to the indoor pipeline. -
Floor Decor: It reads the map to determine the biome (desert, swamp, tundra, ocean) and blits foreground details (grass, water edges, wedges) over the bottom of the floor using the
desert.32(or equivalent) sheet. -
Horizon Layers (3 Passes):
- The engine samples three rows of map data ahead of the player.
- It converts the raw map bytes into terrain IDs, which act as indices to select between the three loaded outdoor sheets (
outdoor1.32,outdoor2.32,outdoor3.32). - It blits these terrain sprites in three distinct overlapping passes (L1, L2, L3) using specialized coordinate lookup tables to layer distant mountains, forests, or plains over one another.
Every single 3D element is pasted using the exact same assembly function (JSR -$7C20(A4)), which takes 4 arguments:
blit(sheet_ptr, frame_index, y_coordinate, x_coordinate)
The screen coordinates are always absolute positions relative to the top-left of the 208x120 viewport area.
Once the 3D viewport is complete, the engine layers on the rest of the UI:
- Monsters: If there is an encounter, monster sprites are placed over the 3D viewport based on a 24-entry placement table.
- Chrome / UI: The text, borders, character names, HP, and the command lists are not a single background image. They are dynamically drawn over a 40x24 text grid using a custom font engine that draws characters and box-drawing line glyphs (e.g., lines, corners) to build the UI frames on the fly.
In accordance with the 100% ASM fidelity rule, the remake's C++ rendering implementation in the game/src/gfx/ directory mimics the logic, limits, and memory layout of the original Amiga executable. It builds pure data structures containing lists of blits, which are subsequently rendered by the graphics backend.
The indoor master routine is implemented as buildView3DScene(). It follows the exact same flow as the original 0x2ECE sequence:
-
Hood Generation:
refreshHood()gathers a 13-byte neighborhood (the "hood") from the central and adjacentMapGridpages (kMapPageSize), mimicking the original map sampling. -
Frustum Building:
buildFrustum()applies directional masks (N, E, S, W) mapping to the 2-bit field codes (Wall, Torch, Door) to construct the 20-slot frustum. -
Blit Collection:
collectBlits()walks through the frustum slots back-to-front (e.g. depth 4 to 0) and issues calls topaintFrustumCell()/view3dPaintLatticeCell(). -
Coordinate Tables: The raw Amiga DATA segment depth tables (like
-$75AE) are preserved as static compile-time constants (e.g.,T::kFrontX,T::kLeftFarY) insideView3DWallTables.
The outdoor master routine (0x18870) is handled by buildOutdoorScene():
-
Screen Resolution: Unlike indoor dungeons, the outdoor
OutdoorMapGridmust cross 16x16 screen boundaries. It usesneighborScreen()parsingMm2AttribFiledata to correctly wrap and fetch tiles from adjacent overland sectors. -
Terrain Lookup:
processTerrainRows()runs the raw map bytes through a 256-byte lookup arraykTerrainLookup(replicating the original0x9524translation table) to resolve terrain IDs. -
Horizon Passes:
buildHorizonBlits()handles the three L1, L2, and L3 horizon terrain passes, pushingOutdoorSpriteBlitinstructions pointing toOutdoor1,Outdoor2, orOutdoor3sheets. -
Floor Decor:
buildDecorBlits()layers the foreground wedges/grass according to the sector's biome (Ocean, Tundra, Swamp, Desert) usingbiomeForCell(), placing them at the bottom of the viewport usingT::kDecorY.
| Page | Why |
|---|---|
| 3D View and Game Screen | ASM-confirmed reference |
| Amiga Cpp Play Screen Draw | Remake implementation |
| map dat Format | Page 0 wall bits |
| GFX Loading | town/cave/castle .32 sheets |
- Docs Wiki Hub ← full doc index
- Getting Started ← read this first
- Overview
- Workspace Notes
- Open Questions
- Full Analysis
- Game Remake
- Startup and Init
- Runtime Memory Map
- Main Loop and Map
- Exploration Input and Options
- Party and Session
- Game State Struct
- Data Hunk mm2 data 00
- Time Era Calendar
- GFX Loading
- ANM TV Format
- PC DOS graphics
- SNES graphics
- 3D View and Game Screen
- Amiga 3D Render Process
- Scripted Scene Graphics
- Event Graphics Opcodes
- Title Screen Assets
- Title Screen Animation
- Format inventory
- items.dat
- monsters.dat
- roster.dat
- attrib.dat
- map.dat
- spells & item use
- event.dat
- Events by location ← 71 maps
- Events hub (numbered)
- Event Script Opcodes
-
Event Script DSL ←
.mm2evtauthoring - Event Text Rendering
- Event Graphics Opcodes
- Combat Overview
- Combat System
- Encounter Tables
- Spell Cast ASM
- monsters.dat abilities
- Spells and item use
- Amiga audio in exe ← Paula / DATA / remake
- Controls: Sounds / Walk Beep
- MM2 music format (superseded)
- Title/death audio paths (superseded)
- Known songs catalog (superseded)
- Town Services
- Spell Sources
- Character Mechanics
- Skills and Hirelings
- Commerce Formulas
- Commerce World Services
- Mount Farview Class Quest
- Class Quest HP Bug
- Event Runtime
- Event to String Path
- Embedded Exe Strings
- Copy Protection
- Time Era Calendar
- Game State Struct
- MM1 Overview ← hub + decode status
- MM1 MAZEDATA format
- MM1 to MM2 outdoor
- MM1 WALLPIX by sector
- MM1 art & graphics
- MM1 items / monsters (status)
- MM1 map walker ↗
- MM1 2D maps gallery
- MM1 WALLPIX gallery