Skip to content

Rendering

Daniel Aquino edited this page Aug 16, 2013 · 18 revisions

Passes

  1. Solid objects are drawn with zbuffer writes enabled
  2. Transparent objects are drawn with zbuffer writes disabled
  3. Orthogonal rendering last basically just text and 2d effects like lens flair

Level Groups

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.

Visibility Lists / Level Groups

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).

Portals / Level Groups

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

Bsp trees are only used for Level Collisions and have nothing to do with rendering in Forsaken.

See Physics for more information.

Particles - 2d Face Me Polys

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.

Textures

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.

Color Keyed Textures

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

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.*

User Interface

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

Some UI Processing Functions:

Some interesting functions in title.c

      ProcessText()
      ProcessSelect()
      CheckKeysForChanges()
      ProcessSlider()
      ProcessSlider2()
      ProcessList()
      ProcessKeys()
      ProcessBikerList()
      ProcessSavedGameList()
      ProcessPlayerList()
      ProcessWeaponOrder()
      ProcessPlaceTeamMember()
      ProcessLevelList()
      ProcessDifficultySet()
      MenuProcess()
      ProcessDefKey()
      KeyDefine()

Title Room Pipeline:

DisplayTitle()
	BeginScene()
		SetMatrix()
		SetViewport()
		ClearBuffers()
		InitPolySort()
		Execute()
		ModelDisp()
		DisplaySolidGroupClippedPolys()
		DisplaySolidGroupClippedFmPolys()
		Execute()
		Execute()
		DisplayGroupClippedPolys()
		DisplayGroupClippedFmPolys()
		ExecuteTransExe()
		ExecuteTransExeUnclipped()
		DisplayGroupUnclippedFmPolys()
		DisplayGroupUnclippedPolys()
		DisplayNonSolidScrPolys()
		Execute()
		DisplaySolidScrPolys()
	EndScene()

Main Game Pipeline:

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()
      }

    }
}

Lighting

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:

https://gist.github.com/chino/22b35b66dd2c83757b95