View on GitHub

FOnline Engine

Flexible cross-platform isometric game engine

Frontend and Rendering

Engine-owned documentation. This page describes the reusable application, input, audio, window, and rendering abstractions under Source/Frontend/ plus the client render-target bridge in Source/Client/.

Purpose

The frontend layer is the boundary between the platform and the engine runtime. It owns windows, frame boundaries, input queues, touch/gamepad translation, audio device access, renderer selection, and low-level render backend objects. The client runtime consumes this layer through stable interfaces instead of calling SDL, OpenGL, Direct3D, or Web APIs directly.

Read this page together with:

Source paths inspected

Layer map

The frontend/rendering split has three layers:

  1. Application layer (Application, AppWindow, AppInput, AppAudio, AppRender) owns platform services and frame boundaries.
  2. Renderer layer (Renderer and its backends) owns GPU/null rendering resources: textures, draw buffers, effects, matrices, scissor state, presentation, and resize handling.
  3. Client drawing layer (SpriteManager, RenderTargetManager, EffectManager, MapView) builds engine/game drawing operations on top of the renderer abstraction.

This keeps most client code renderer-agnostic. The client asks for sprites, effects, draw buffers, render targets, and input events; the selected backend decides how those are implemented.

Application initialization

InitApp() and LoadAppSettings() in Source/Frontend/ApplicationInit.cpp prepare global settings and application services before the client/server/tool app creates its engine object.

Notable responsibilities:

Application initialization is intentionally shared by more than the graphical client. Server, mapper, editor, testing, and package flows may use different flags or window modes, but they should still go through the shared frontend setup where applicable.

Application services

Source/Frontend/Application.h defines the public frontend surface.

Application

Application owns process-level frontend state:

AppWindow / IAppWindow

Window responsibilities include:

AppInput / IAppInput

Input responsibilities include:

The client turns these lower-level events into script events in ClientEngine::ProcessInputEvent().

AppAudio / IAppAudio

Audio responsibilities include:

Headless and stub modes

Two non-normal modes are important for tools, tests, CI, and platform staging:

The stub layer is not a full renderer. It exists so tests and non-graphical flows can exercise engine logic without assuming that a real GPU/window/audio device is available. When a test depends on visible rendering, it should say so explicitly instead of relying on stub behavior.

Rendering abstraction

Source/Frontend/Rendering.h defines the renderer-facing types:

Source/Frontend/Rendering.cpp owns backend-independent helper behavior, including draw-buffer allocation checks and effect configuration parsing. It reads effect sections such as Effect and EffectInfo, pass counts, blend settings, and script-visible buffers before backend-specific code consumes shader files.

Render backends

Null renderer

Source/Frontend/Rendering-Null.cpp implements Null_Renderer, Null_Texture, Null_DrawBuffer, and Null_Effect.

Use it for tests, headless flows, and validation that should not require a GPU. It still validates dimensions, buffer counts, render-target state, and texture region access, so it is useful for catching many API misuse errors.

OpenGL renderer

Source/Frontend/Rendering-OpenGL.cpp implements the OpenGL/WebGL path.

Important behaviors:

OpenGL is the path to inspect for WebAssembly/WebGL behavior. Pair renderer changes with WebDebugging.md validation.

Direct3D renderer

Source/Frontend/Rendering-Direct3D.cpp implements the Direct3D 11 path.

Important behaviors:

Direct3D changes are Windows-specific and should be validated through a Windows embedding-project build/debug flow.

Render targets and client bridge

Source/Client/RenderTarget.h and Source/Client/RenderTarget.cpp are the client-side bridge from high-level drawing code to backend textures.

RenderTargetManager responsibilities:

MapView, SpriteManager, ModelSpriteFactory, and ParticleSpriteFactory all rely on render targets for map layers, light buffers, model/particle atlas rendering, hit testing, and offscreen composition.

Effects and shader data

RenderEffect owns standard buffers used by render paths:

EffectManager in Source/Client/EffectManager.h loads minimal/default effects, resolves script-selected effects, writes script-value buffers, and performs per-frame updates. When adding an effect feature, document whether the change belongs in:

Platform packages and BuildTools relationship

BuildTools/cmake/stages/Packages.cmake participates in package target generation. Platform package workflows decide which app/runtime artifacts are packaged, but renderer/backend availability still comes from configured source, compile definitions, third-party dependencies, and platform toolchains.

Keep these boundaries clear:

Do not document one embedding project’s generated target names as universal engine target names.

Frontend/rendering validation tests

Use Source/Tests/Test_Rendering.cpp as the smallest current engine-local test surface for renderer API behavior that should not require a real GPU. The test exercises the null renderer path, draw-buffer limits, texture creation, render-target creation, and invalid-argument checks. Pair it with platform-specific manual/debug validation when changing OpenGL/WebGL or Direct3D backend code.

Validation checklist

When changing frontend or rendering behavior, verify: