|
|
# Main loop
|
|
|
|
|
|
After the game has finished loading, it will run the main loop until the player quits. The most important parts of the loop are "game logic" and graphics. Game logic includes all game mechanics like physics, enemies, etc. Game logic happens in steps that are called tics. 35 (=TICRATE) tics happen in one second. Normally the graphics on the screen are updated after running one tic. (in D_Display) However, if the game detects that it is running slowly, multiple tics can be run without updating the graphics between them.
|
|
|
|
|
|
# Game logic
|
|
|
|
|
|
The TryRunTics function is responsible for running game logic tics. Before running tics however, it handles player inputs, gui logic and the network connection when in a netgame. It then runs tics by calling G_Ticker, multiple times if the game is lagging behind.
|
|
|
|
|
|
G_Ticker runs one tic. The contents of the tic depend on gamestate, which is most commonly GS_LEVEL (playing a level), but there are other states like GS_INTERMISSION, GS_CUTSCENE and GS_TITLESCREEN. When in GS_LEVEL, G_Ticker calls various HUD logic functions and P_Ticker.
|
|
|
|
|
|
P_Ticker handles all level-related logic, including thinkers. Thinkers are a mechanism used by the engine to implement dynamic elements in a level. A thinker consists of a function pointer and a varying amount of data belonging to the thinker. Effects that change the map, like scrolling textures and moving platforms are implemented with thinkers. All thinkers have their functions executed once on each tic.
|
|
|
|
|
|
Map objects are also a kind of thinker. (or map objects contain a thinker) The thinker points to the P_MobjThinker function, which contains the logic for all map objects and their interactions. This includes states, actions, movement, physics etc.
|
|
|
|
|
|
If a mobj has momentum, P_XYMovement is called to handle movement in the XY-axes. P_ZMovement handles vertical movement.
|
|
|
|
|
|
Collision detection happens in P_CheckPosition, called by code that moves the mobj. Here mobj to mobj collisions are checked by calling PIT_CheckThing on mobjs nearby on the blockmap. Mobj to line collisions are similarly checked using PIT_CheckLine. Various global vars beginning with "tm" (Thing Movement? TryMove? unknown meaning) are set in P_CheckPosition, keeping track of properties related to the mobj that is currently moving and needs collision checking.
|
|
|
|
|
|
# Graphics
|
|
|
|
|
|
D_Display handles most/all drawing in the game. Drawing the level is done by calling R_RenderPlayerView in software mode and HWR_RenderPlayerView in OpenGL mode.
|
|
|
|
|
|
HWR_RenderPlayerView draws the player's view of the level in OpenGL mode. Most of the rendering process actually happens twice, first the skybox is rendered and then the level itself is rendered on top. After clearing the frame buffer and initializing various variables, the rendering begins with HWR_RenderBSPNode((INT32)numnodes-1). This iterates through the BSP tree recursively, starting from the root node. (todo: link to bsp article) During the iteration, HWR_Subsector is called for all subsectors that are visible from the current view.
|
|
|
|
|
|
HWR_Subsector renders the floor and ceiling planes of the subsector by calling HWR_RenderPlane. Planes belonging to FOFs are also rendered. The polyobjects occupying the subsector are rendered entirely in this function. The sector's sprites are checked and retrieved, but their actual rendering will happen later in the process. Finally the linesegs belonging to the subsector are processed by calling HWR_AddLine for them.
|
|
|
|
|
|
HWR_Addline handles all linesegs that are being rendered. At the start the orientation of the seg is checked and lines that face away from the camera are ignored, since they cannot be seen. Segs determined to be not visible by the culling system are also skipped. Single-sided linesegs and thok barriers are added to the culling system, so anything behind them will be skipped. Finally, if the seg is possibly visible, HWR_ProcessSeg is called to render it.
|
|
|
|
|
|
HWR_ProcessSeg renders all wall pieces belonging to a lineseg. That means bottom, middle and top textures, skywalls and fof walls.
|
|
|
|
|
|
After the topmost HWR_RenderBSPNode call has returned, sprites (gathered from HWR_Subsector) are rendered. Sprites are first sorted so that they are rendered from back to front. This is done in order to display translucent sprites correctly. If models are enabled and available, they will replace the sprites they apply to.
|
|
|
|
|
|
After sprites the translucent surfaces are rendered. While the level geometry was being rendered in HWR_RenderBSPNode, all walls and planes that are translucent were added to a list instead of immediately rendering them. These surfaces are called "drawnodes" in the code. (note: drawnodes are also used in software mode but they do not mean exactly the same thing) The drawnode list is also sorted before rendering for correct translucency.
|
|
|
|
|
|
Finally, after rendering the contents of the level, currently enabled postprocessing effects are applied to the screen. This includes screen flashing (armageddon shield blast) and screen waving. (underwater and heat wave) |
|
|
\ No newline at end of file |