-
Notifications
You must be signed in to change notification settings - Fork 30
Rendering
- Solid objects are drawn with zbuffer writes enabled
- Transparent objects are drawn with zbuffer writes disabled
- Orthogonal rendering last basically just text and 2d effects like lens flair
Forsaken levels are broken up into various named groups that connect to one another. Groups generally don't have many restrictions on their geometry. They use a bsp tree to define outside/inside of the group.
Forsaken also allows groups to overlap to create multi dimensional levels. For instance the Pandora level has a small sphere in the middle of a room where you can enter it on one side that opens up to a whole new region of the level.
Pre generated visibility lists are used to selectively render different areas of the level. Each level is broken up into named level groups. The engine tracks which group the player is currently in and based on the visibility list it knows which groups to render. Unless the player is outside the level in which case all groups are rendered (generally this is only possible in debug mode).
Where level groups touch they form a planar polygon surface called a portal. These regions are defines inside the mx level format. The engine clips other level groups to this portal to reduce rendering.
Bsp trees are only used for Level Collisions and have nothing to do with rendering in Forsaken.
See Physics for more information.
Various particle affects such as fire (explosions, pyro), smoke (ships, missiles), engine lights, trojax, pulsars, orbitals, and others are generally a texture with transparent/color-keyed pixels rendered to flat quads (two triangles) which can give the appearance of 3d object. Things like smoke and pyro rotate and switch between different images (like a gif) to make it look random and more realistic.
Level and Model textures simply use tu/tv as normal.
Certain other textures like fonts, weapons, 2d-face-me polys (like bullets, fire, etc) use atlases (sprites) which are cut up based information in the the offset files.
Pure black pixels (rgb = 0) are considered transparent and discarded in the rendering pipeline. This is heavily used by the game to create windows, bike wind shields, and anything else transparent.
In a shader based backend we would normally call the glsl discard
statement to drop the fragment in the fragment shader.
Color keying was a common technique in older rendering pipelines to reduce need for extra geometry but was later deprecated. So to support the existing models/textures that require this feature we use GL_ALPHA_TEST instead. During texture loading we detect black pixels and set the alpha value to 0. Then using GL_ALPHA_TEST we can tell the pipeline to discard any pixels that have a alpha value of 0. In reality due to texture sampling/mixing and other things that happen in the pipeline we have to reject values that are below a given threshold near 0 which can at times be a rather hacky technique causing either too many or too little pixels to be discarded. Modern approaches would be to simply use more geometry.
Fonts are loaded from textures and mapped to an ascii table. They are rendered on quads (2 triangles that form a rectangle) orthogonally as a final rendering step.
Files: text.*
RGB Color Table: Colourtrans[ MAXFONTCOLORS ]
Color Names: enum colors_t
Various functions exist such as CenterPrintText() see text.*
Forsaken has it's own user interface mostly in title.*
General layout of in game HUD:
+-----------------------------------------------------------+
| player list fps mines |
| messages |
| MISSILE VIEW REAR VIEW |
| |
| |
| cross hair |
| invul time |
| nitro time |
| choas time |
| shield primary |
| hull power pod level secondary |
+-----------------------------------------------------------+
In game HUD rendering routines:
DrawSimplePanel() // prints the ui in the above layout
PrintScoreSort(); // top left names
UI Rendering Pipeline:
DisplayTitle() // top level routine
ProcessTextItems() // print title menu to screen
DisplayTextItem() // print actual text strings
DisplayTextCharacter() // print characters
2d menus are defined in title.c
Menu Entry Definitions are in the format:
MENU name = { // a new menu
text_name,
enter_menu_function,
exit_menu_function,
NULL,
NULL,
0,
{ // entries
{ // menu entry
// bounding box
x (int),
y (int),
xMax (int),
yMax (int),
? (int),
text (char*), // the text to display
font-size, // font size of the text
TEXTFLAG [| TEXTFLAG ...], // tell the text how to act
target_variable (void*), // variable to manipulate
?,
run_on_focus(), // run this function on focus
?,
?,
?
}, // end of entry
// required last menu entry
{ -1, -1, 0, 0, 0, "", 0, 0, NULL, NULL, NULL, NULL, NULL, 0 }
} // end of entries
} // end of menu
ProcessText()
ProcessSelect()
CheckKeysForChanges()
ProcessSlider()
ProcessSlider2()
ProcessList()
ProcessKeys()
ProcessBikerList()
ProcessSavedGameList()
ProcessPlayerList()
ProcessWeaponOrder()
ProcessPlaceTeamMember()
ProcessLevelList()
ProcessDifficultySet()
MenuProcess()
ProcessDefKey()
KeyDefine()
DisplayTitle()
BeginScene()
SetMatrix()
SetViewport()
ClearBuffers()
InitPolySort()
Execute()
ModelDisp()
DisplaySolidGroupClippedPolys()
DisplaySolidGroupClippedFmPolys()
Execute()
Execute()
DisplayGroupClippedPolys()
DisplayGroupClippedFmPolys()
ExecuteTransExe()
ExecuteTransExeUnclipped()
DisplayGroupUnclippedFmPolys()
DisplayGroupUnclippedPolys()
DisplayNonSolidScrPolys()
Execute()
DisplaySolidScrPolys()
EndScene()
Note: This needs updating...
MainGame()
{
MainRoutines()
{
ProcessShips();
FirePrimary();
FireSecondary();
ProcessEnemies();
ProcessSpotFX();
ProcessPrimaryBullets();
ProcessSecondaryBullets();
RegeneratePickups();
ProcessPickups();
ProcessBGObjects( TRUE );
ProcessRestartPoints();
ProcessModels();
ProcessPolys();
ProcessXLights( &Mloadheader );
DoAfterBurnerEffects();
FmPolyProcess();
ShowScreenMultiples();
ProcessActiveConditions();
ProcessTriggerAreas();
ProcessGoals();
WaterProcess();
ProcessRTLights();
}
TloadCheckForLostSurfaces()
{
TloadReloadTextureSurf()
TloadReloadPlaceHolder()
}
BeginScene()
RenderCurrentCamera()
EndScene()
SetFOV( chosen_fov + fov_inc ); // nitro effect
}
ProcessShips()
{
ModeControl[]
{
ShipMode0()
ShipMode1()
{
control_ship()
}
ShipMode2()
{
AnyKeyReleased()
control_ship()
}
}
}
Forsaken lighting is all done on the cpu.
Each frame most verts are crawled and distance to lights is calculated to blend the light color into the vert color.
In NEW_LIGHTING verts are modified as they are passed through the pipeline.
In classic lighting mode each render object has original vertices backed up and restored after modification.
Forsaken currently only supports basic lights (go out in all directions) and spot lights (have a given direction and arc defining their cone).
See render_* lights* and other files for more information.
Here is a good comparison: