Skip to content
MarkL edited this page Mar 1, 2014 · 4 revisions

Introduction

A rendering engine is responsible for all low-level rendering tasks in CorsixTH. Its most important roles are:

  1. Creating a canvas to render onto (typically a window).
  2. Loading Theme Hospital sprite sheets.
  3. Drawing individual sprites onto a canvas.

Higher-level constructs like fonts, maps, and animations are all built on top of sprite sheets, and are thus implemented independently from the rendering engine.

A rendering engine must provide two APIs; one for C++ code, and one for Lua code.

Built-in rendering engines

At the moment, CorsixTH has a number of rendering engines. The engine is chosen at compile time by defining the appropriate flag in config.h.

Name Notes Define Header C++ API Lua API
SDL The "standard" rendering engine, which should work everywhere. CORSIX_TH_USE_SDL_RENDERER th_gfx_sdl.h th_gfx_sdl.cpp sdl_video.cpp
DirectX 9 Windows only, capable of using video hardware for faster rendering than SDL. CORSIX_TH_USE_DX9_RENDERER th_gfx_dx9.h th_gfx_dx9.cpp dx9_video.cpp
OpenGL Finished, but there are many graphical glitches. CORSIX_TH_USE_OGL_RENDERER th_gfx_ogl.h th_gfx_ogl.cpp ogl_video.cpp

The AnimView tool uses its own rendering engine rather than one of the above. The AnimView rendering engine is used for research purposes, and renders onto a wxImage. It has a different C++ API to the above engines, and no Lua API.

C++ API

A rendering engine must define the following types:

struct THClipRect;
struct THRenderTarget;

A clip rectangle must have signed members x and y, and unsigned members w and h, though it can have others. There are no rules on the members of a THRenderTarget.

A rendering engine must provide the following two functions for manipulating the clip rectangle of a render target: void THRenderTarget_GetClipRect(const THRenderTarget* pTarget, THClipRect* pRect); void THRenderTarget_SetClipRect(THRenderTarget* pTarget, const THClipRect* pRect);

A rendering engine must provide the following two functions, though they do not have to do anything: void THRenderTarget_StartNonOverlapping(THRenderTarget* pTarget); void THRenderTarget_FinishNonOverlapping(THRenderTarget* pTarget); When in non-overlapping mode, it doesn't matter what order sprites are drawn onto the given render target. This means that the rendering engine is free to re-order draw operations into a more optimal order, though it doesn't have to.

A rendering engine must provide a {{{THPalette}}} class with at least the following members:

class THPalette
{
public:
  bool loadFromTHFile(const unsigned char* pData, size_t iDataLength);
  void assign(THRenderTarget* pTarget, bool bTransparent) const;
};

The loadFromTHFile method takes up to 768 bytes of data, which is composed of 1 or more RGB triplets. Each triplet is up of three bytes, each in the range 0 to 63 (not 0 to 255). The assign method is used to change the palette of a render target, though rendering engines are not required to support changing the palette of a render target after the target has been created.

The most important class which a rendering engine must provide is THSpriteSheet, which must have at least the following members:

class THSpriteSheet
{
public:
  void setPalette(const THPalette* pPalette);
  bool loadFromTHFile(const unsigned char* pTableData, size_t iTableDataLength,
                        const unsigned char* pChunkData, size_t iChunkDataLength,
                        bool bComplexChunks, THRenderTarget* pEventualCanvas);
  void setSpriteAltPaletteMap(unsigned int iSprite, const unsigned char* pMap);
  unsigned int getSpriteCount() const;
  bool getSpriteSize(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const;
  void getSpriteSizeUnchecked(unsigned int iSprite, unsigned int* pX, unsigned int* pY) const;
  void drawSprite(THRenderTarget* pCanvas, unsigned int iSprite, int iX, int iY, unsigned long iFlags);
};

TODO: Describe methods

Lua API

TODO

Clone this wiki locally