Lit Model¶
A model prepared for drawing: the geometry of a model definition, plus the per face colours lighting writes and the routines that project and rasterize it.
The geometry is shared with the definition rather than copied - nothing here writes to it, and lighting keeps its colours in arrays of its own.
LitModel.Create¶
function TLitModel.Create(const src: TModelDefinition): TLitModel; static;
A decoded model, ready to light and draw.
The geometry arrays are shared with src rather than copied, since lighting writes its per face
colours into arrays of its own. Apply any recolouring, retexturing or resizing to the definition
first, and leave it alone afterwards - changing src later changes this model with it.
LitModel.FaceNormal¶
procedure TLitModel.FaceNormal(idx: Integer; out nX, nY, nZ: Integer);
The normal of face idx, as the cross product of the face’s two edges scaled to a length of
roughly 256.
The cross product is halved until it fits in 13 bits so that the squares below cannot overflow, using an arithmetic shift - a logical one would turn a negative component into a large positive and flip the face’s normal.
LitModel.LightIntensity¶
function TLitModel.LightIntensity(normalX, normalY, normalZ, mag, atten, ambient: Integer): Integer; static;
How brightly the fixed light falls on a surface facing along the normal, unclamped.
mag is how many face normals were summed into the normal, 1 for a single face’s own normal.
LitModel.ApplyLightIntensity¶
function TLitModel.ApplyLightIntensity(color, intensity: Integer): Integer; static;
Scale a colour’s luminance by a light intensity.
Pascal’s shr is a logical shift, so it cannot be used here: intensity
is unclamped and goes negative for a face turned away from the light, and a
logical shift would turn that into a large positive value that clamps to full
brightness instead of the minimum.
LitModel.Light¶
procedure TLitModel.Light(ambient, contrast: Integer);
Computes vertex/face normals and lights each face from the fixed -50, -10, -50 light the game
uses for items and world objects, writing the result into FaceColors1/2/3.
ambient and contrast are the values the client passes once it has added its base to the
definition’s own: Ambient + 64 for both, and Contrast + 768 where the definition’s contrast
is already scaled - by 5 for items and by 25 for objects.
LitModel.CalcBoundsCylinder¶
procedure TLitModel.CalcBoundsCylinder();
Measures the cylinder the model fits inside: how far it reaches from the vertical axis, and how far it rises above and drops below its origin.
The height is what an item icon is centred on, and the radius is what face sorting offsets depths by so that they never go negative. It is computed once and remembered.
LitModel.RasterFace¶
procedure TLitModel.RasterFace(var graphics: TGraphics3D; faceIdx: Integer);
Draws one face, already projected to screen space by TLitModel.ProjectAndDraw.
A face with three distinct vertex colours is Gouraud shaded and one with a single colour is filled flat. Clipping is only turned on for faces that actually reach outside the viewport.
A textured face is drawn with the texels of graphics.TextureFrame. Its colours are light levels
rather than palette indices, and the texture is laid across it by the three points its texture
coordinate names, or by the face’s own corners when it has none or names one that isn’t mapped
flat. A texture that can’t be loaded is drawn in its average colour instead.
LitModel.DrawByPriority¶
procedure TLitModel.DrawByPriority(var graphics: TGraphics3D);
Draws faces in the order their render priorities ask for, rather than purely by depth.
Depth sorting alone gets some models wrong, so faces can carry a priority that pins them in front of or behind others regardless of where they sit. Priorities 0 to 9 are drawn as groups in order, while 10 and 11 stay depth sorted and are woven in between them at the points where their depth passes the average depth of the group being drawn.
LitModel.Draw¶
procedure TLitModel.Draw(var graphics: TGraphics3D);
Draws every visible face of the projected model, furthest first.
Back faces are dropped by the sign of their screen-space winding, and what is left is sorted by average depth with an insertion sort - models are small enough that it beats anything cleverer. Models with render priorities are handed to TLitModel.DrawByPriority instead.
LitModel.ProjectAndDraw¶
procedure TLitModel.ProjectAndDraw(var graphics: TGraphics3D; yzRot, xzRot, xyRot, orientation, xOffset, yOffset, zOffset: Integer);
Rotates the model, projects its vertices onto the screen and draws it.
The three rotations are applied about each axis in turn, the model is moved by the offsets, and
then the camera pitch given by orientation is applied. Every angle is in the client’s units of
2048 to a full turn and every multiply is fixed point, matching what the game does rather than
using floating point. Vertices land in Viewport, which TLitModel.Draw then reads.