Skip to content

These docs were made completely by AI, so they might be right, or wrong, you'll need to test them yourself. This was made for a easier understanding of everything. So use at your own risk. If anything is wrong, please don't hurt to make a PR on the page you have a problem with. ON GITHUB

Rendering Pipeline

The LCE rendering pipeline turns the game world into pixels through several systems working together. GameRenderer runs each frame, LevelRenderer manages chunk geometry, EntityRenderDispatcher routes entity drawing, TileRenderer builds block face geometry, and Tesselator is the low-level vertex buffer that everything feeds into.

GameRenderer::render(float a, bool bFirst) is the per-frame entry point, called once per split-screen viewport. The a parameter is the interpolation alpha between ticks, and bFirst is true for the first viewport rendered that frame.

Within a single frame, the pipeline roughly goes through these steps:

  1. Camera setup with setupCamera(), which configures the projection matrix, applies FOV, and positions the camera via moveCameraToPlayer()
  2. Frustum culling with Frustum::getFrustum(), which pulls clip planes from the current model-view-projection matrices
  3. World rendering with renderLevel(), which draws the world in multiple passes
  4. GUI rendering with setupGuiScreen(), which switches to orthographic projection for HUD and menu overlays

Inside renderLevel(), the world gets drawn in this order:

  1. Sky. LevelRenderer::renderSky() draws the sky dome, sun, moon, and stars using pre-built display lists (skyList, starList, darkList). Moon phases come from TN_TERRAIN_MOON_PHASES.
  2. Halo ring. LevelRenderer::renderHaloRing() draws the horizon halo effect using haloRingList.
  3. Opaque pass (layer 0). LevelRenderer::render() with layer=0 renders all opaque block geometry. This is the big one with most of the vertex data.
  4. Entities. LevelRenderer::renderEntities() iterates every visible entity and dispatches to the right EntityRenderer.
  5. Particles. ParticleEngine::render() draws standard particles, then ParticleEngine::renderLit() draws lit particles.
  6. Weather. GameRenderer::renderSnowAndRain() draws rain and snow particle sheets.
  7. Translucent pass (layer 1). LevelRenderer::render() with layer=1 renders translucent geometry (water, glass, ice).
  8. Clouds. LevelRenderer::renderClouds() or renderAdvancedClouds() draws the cloud layer.
  9. Block selection. LevelRenderer::renderHitOutline() draws the wireframe around the targeted block, and renderHit() draws the crack overlay.
  10. Held item. GameRenderer::renderItemInHand() draws the first-person hand and item.
  11. Screen effects. ItemInHandRenderer::renderScreenEffect() draws overlays like the pumpkin blur, underwater tint, and fire overlay when the camera is inside those blocks.

After all that, setupGuiScreen() switches to orthographic projection and Gui::render() draws the HUD: hotbar, health, chat, vignette, and any overlay messages.

GameRenderer manages per-frame state and effects:

MemberPurpose
smoothTurnX / smoothTurnYSmooth camera movement (via SmoothFloat)
smoothDistance / smoothRotation / smoothTilt / smoothRollThird-person camera smoothing
fovOffset / fovOffsetOFOV modification (sprint, bow draw)
cameraRoll / cameraRollOCamera roll effect (damage)
lightTexture[4]One light texture per level for split-screen
fov[4] / oFov[4] / tFov[4]Per-player FOV tracking
blr / blg (and blrt / blgt)Fog colour blending
renderDistanceCurrent render distance
zoom / zoom_x / zoom_yZoom state for map rendering
fr / fg / fbFog color components
isInCloudsWhether the camera is inside the cloud layer
cameraPos4J-added camera position vector
rainSoundTimeTicks until next rain sound

Key methods:

  • tick(bool bFirst) updates FOV, rain sounds, light textures each game tick
  • pick(float a) does raycasting to figure out what the player is looking at
  • bobHurt(float a) applies screen shake when damaged
  • bobView(float a) applies view bobbing while walking
  • renderItemInHand(float a, int eye) draws the held item
  • renderSnowAndRain(float a) renders weather particle sheets
  • tickLightTexture() / updateLightTexture(float a) updates the light-map texture based on time of day and dimension
  • setupFog(int i, float alpha) configures distance fog per render pass
  • setupClearColor(float a) sets the background clear color based on the current fog color
  • getFov(float a, bool applyEffects) calculates the current FOV including sprint and potion effects
  • getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects) 4J-added helper that gets both FOV and aspect ratio at once
  • getNightVisionScale(shared_ptr<Player>, float a) returns the brightness boost from the night vision potion
  • zoomRegion(double zoom, double xa, double ya) / unZoomRegion() zoom in for map rendering
  • updateAllChunks() forces all dirty chunks to rebuild immediately (used during loading)

The light texture is a 2D lookup that maps block light and sky light to a final brightness. It is a small texture (16x16 pixels) indexed by (blockLight, skyLight). tickLightTexture() is called once per game tick, and updateLightTexture() rebuilds the texture based on time of day, dimension, and night vision. The lightPixels array stores the CPU-side data, one per local player.

4J keeps one light texture per level to support split-screen players in different dimensions:

static const int NUM_LIGHT_TEXTURES = 4;
int lightTexture[NUM_LIGHT_TEXTURES];
intArray lightPixels[NUM_LIGHT_TEXTURES];
int getLightTexture(int iPad, Level *level);

The turnOnLightLayer(double alpha) and turnOffLightLayer(double alpha) methods bind and unbind the light texture for the current viewport.

GameRenderer supports stereoscopic 3D rendering through the static fields anaglyph3d and anaglyphPass. When enabled, the scene gets rendered twice with color channel separation.

On platforms with MULTITHREAD_ENABLE, GameRenderer runs chunk updates on a background thread:

static C4JThread* m_updateThread;
static C4JThread::EventArray* m_updateEvents;

The EnableUpdateThread() and DisableUpdateThread() methods control this thread. Deferred memory cleanup is handled through lock-free delete stacks for SparseLightStorage, CompressedTileStorage, and SparseDataStorage. The event system uses two events: eUpdateCanRun signals the thread to start work, and eUpdateEventIsFinished signals that the thread has completed.

static vector<byte *> m_deleteStackByte;
static vector<SparseLightStorage *> m_deleteStackSparseLightStorage;
static vector<CompressedTileStorage *> m_deleteStackCompressedTileStorage;
static vector<SparseDataStorage *> m_deleteStackSparseDataStorage;
static CRITICAL_SECTION m_csDeleteStack;

These delete stacks are protected by a critical section and flushed when FinishedReassigning() is called after a chunk reassignment pass.

LevelRenderer implements LevelListener and takes care of managing the render chunk grid and drawing the world. It keeps one set of chunks per split-screen player.

static const int CHUNK_XZSIZE = 16;
static const int CHUNK_SIZE = 16;
static const int CHUNK_Y_COUNT = Level::maxBuildHeight / CHUNK_SIZE;

Chunks are 16x16x16 blocks. The render grid is allocated based on PLAYER_RENDER_AREA (400 chunks for standard worlds, or calculated from PLAYER_VIEW_DISTANCE = 18 for large worlds).

Each player gets their own chunk array (ClipChunkArray chunks[4]), their own level pointer (MultiPlayerLevel *level[4]), their own TileRenderer (tileRenderer[4]), and their own last camera position (xOld[4], yOld[4], zOld[4]).

PlatformMAX_COMMANDBUFFER_ALLOCATIONS
Xbox One512 MB
PS4 (Orbis)448 MB
PS3110 MB
Windows 642047 MB
Other (Xbox 360, Vita)55 MB

Each chunk in the global grid has a flag byte with these bits:

FlagValueMeaning
CHUNK_FLAG_COMPILED0x01Geometry has been built
CHUNK_FLAG_DIRTY0x02Needs rebuild
CHUNK_FLAG_EMPTY00x04Layer 0 is empty
CHUNK_FLAG_EMPTY10x08Layer 1 is empty
CHUNK_FLAG_EMPTYBOTH0x0cBoth layers empty (convenience combo)
CHUNK_FLAG_NOTSKYLIT0x10Not lit by sky
CHUNK_FLAG_CRITICAL0x20Critical chunk (Vita only)
CHUNK_FLAG_CUT_OUT0x40Has cut-out textures (Vita only)

Reference counting uses the upper bits (3-bit or 2-bit depending on platform) to track how many split-screen viewports reference a chunk. On Vita with _CRITICAL_CHUNKS, the ref count is only 1 bit (CHUNK_FLAG_REF_MASK = 0x01, CHUNK_FLAG_REF_SHIFT = 7) because the critical and cut-out flags steal the extra bits. On other platforms it’s 3 bits (CHUNK_FLAG_REF_MASK = 0x07, CHUNK_FLAG_REF_SHIFT = 5).

The global chunk flag storage is a flat unsigned char array (globalChunkFlags). Methods like getGlobalChunkFlag(), setGlobalChunkFlag(), clearGlobalChunkFlag(), incGlobalChunkRefCount(), and decGlobalChunkRefCount() provide typed access.

Dirty chunks are tracked using a lock-free stack (XLockFreeStack<int> dirtyChunksLockFreeStack), protected by a critical section (m_csDirtyChunks). When a block changes, setDirty() or tileChanged() flags the affected chunks and pushes their indices onto the stack.

The dirtyChunkPresent flag is a quick check. If no dirty chunk has been found in the last FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS (250ms), the system forces a scan. The lastDirtyChunkFound timestamp tracks when the last dirty chunk was processed.

LevelRenderer::render() takes a layer parameter. Layer 0 renders opaque geometry, layer 1 renders translucent geometry (water, glass, ice). The renderChunks() method goes through the visible chunk list and dispatches their display lists.

The level renderer maintains several pre-built display lists:

FieldContent
starListStar geometry for the night sky
skyListSky dome hemisphere
darkListDark hemisphere for the bottom of the sky
haloRingListHorizon halo ring effect
cloudListCloud mesh (4J added, built by createCloudMesh())

These are built once during construction and reused every frame.

OffsettedRenderList is a utility class that manages collections of OpenGL display lists offset to a specific world position. The level renderer keeps an array of these:

static const int RENDERLISTS_LENGTH = 4;
OffsettedRenderList renderLists[RENDERLISTS_LENGTH];

Each OffsettedRenderList stores an offset position (xOff, yOff, zOff), a list of display list IDs, and whether it has been rendered. The init() method sets the position, add() appends a display list, and render() applies the offset translation and calls all the lists.

MethodPurpose
render()Main world render for a given layer
renderEntities()Draw all visible entities
renderSky()Render sky dome, sun, moon, stars
renderHaloRing()Render the halo ring effect
renderClouds() / renderAdvancedClouds()Cloud rendering (simple and fancy)
renderHit() / renderHitOutline()Block selection outline and crack overlay
renderDestroyAnimation()Block-breaking progress animation
cull()Mark chunks visible/hidden via frustum culling
updateDirtyChunks()Rebuild chunks that have been modified
renderSameAsLast()Re-render the same chunk set as the previous frame (optimization)
resortChunks()Re-sort the chunk array when the camera moves to a new chunk
allChanged()Mark all chunks dirty (used on world load or texture pack change)
setLevel()Bind a level to a specific player index
clear()Remove all chunks and tile entities
levelEvent()Handle level events (sounds, particles from block interactions)
destroyTileProgress()Update block-breaking progress for the crack overlay
registerTextures()Register block-breaking textures with the icon system
playSound()Bridge game sound events to the audio system
playStreamingMusic()Bridge music events to the audio system
addParticle() / addParticleInternal()Spawn particles from game logic

The destroyingBlocks hash map stores BlockDestructionProgress objects keyed by destruction ID. Each entry tracks the block position and the current crack stage (0-9). The breakingTextures array holds the 10 crack overlay icons used by renderDestroyAnimation().

gatherStats1() and gatherStats2() return debug strings with rendering statistics:

  • Total chunks, offscreen chunks, occluded chunks, rendered chunks, empty chunks
  • Total entities, rendered entities, culled entities

An inner class that provides temporary collision for recently destroyed blocks while their render chunks are being rebuilt:

class DestroyedTileManager {
void destroyingTileAt(Level*, int x, int y, int z);
void updatedChunkAt(Level*, int x, int y, int z, int veryNearCount);
void addAABBs(Level*, AABB*, AABBList*);
void tick();
};

Each RecentTile entry stores the block position, the level, a list of collision boxes, a timeout counter, and a rebuilt flag. The critical section m_csDestroyedTiles protects the list since game logic and chunk rebuilding happen on different threads.

When _LARGE_WORLDS is defined, LevelRenderer uses multi-threaded chunk rebuilding:

static const int MAX_CONCURRENT_CHUNK_REBUILDS = 4;
static Chunk permaChunk[MAX_CONCURRENT_CHUNK_REBUILDS];
static C4JThread *rebuildThreads[MAX_CHUNK_REBUILD_THREADS];

The PLAYER_VIEW_DISTANCE is 18 chunks, giving a render area of 18 * 18 * 4 = 1296 chunks. Chunk flags get a critical section (m_csChunkFlags) for thread safety. The rebuildChunkThreadProc() static method runs on worker threads and calls Chunk::rebuild() on the thread’s permaChunk instance.

On PS3, the culling work gets offloaded to SPU cores:

void cull_SPU(int playerIndex, Culler *culler, float a);
void waitForCull_SPU();
C4JSpursJobQueue::Port* m_jobPort_CullSPU;
C4JSpursJobQueue::Port* m_jobPort_FindNearestChunk;
bool m_bSPUCullStarted[4];

This lets the PS3 run visibility tests in parallel across its Cell processor’s SPU units while the PPU handles other work.

The Chunk class (not to be confused with LevelChunk in Minecraft.World) represents a 16x16x16 renderable section of the world.

FieldPurpose
x, y, zWorld position of this chunk
xRender, yRender, zRenderRender position
xRenderOffs, yRenderOffs, zRenderOffsOffset for rendering
xm, ym, zmCenter position
bbBounding box for culling
clipChunkPointer to the ClipChunk visibility data
idDisplay list ID
levelBack-pointer to the level
assignedWhether this chunk is currently assigned to a level

The ClipChunk companion struct stores:

  • chunk pointer
  • globalIdx for flag lookups
  • visible flag set during culling
  • aabb[6] float array for the bounding box
  • xm, ym, zm center position
  • rebuild() builds all tiles in the chunk into display lists using TileRenderer. On large worlds, each rebuild thread has its own Tesselator instance via thread-local storage (tlsIdx).
  • makeCopyForRebuild(Chunk *source) copies position and assignment data so a permaChunk can stand in for the real chunk during multi-threaded rebuild
  • cull(Culler*) tests visibility against the current frustum
  • distanceToSqr(Entity) / squishedDistanceToSqr(Entity) used for sorting and prioritizing which chunks to rebuild first
  • setDirty() / clearDirty() flag a chunk for rebuild
  • setPos() repositions the chunk in the world
  • getList(int layer) returns the display list ID for a given render layer
  • emptyFlagSet(int layer) checks if a layer has been flagged empty
  • reset() / _delete() cleans up display lists

On PS3, rebuild_SPU() offloads chunk building to SPU cores.

The static updates counter tracks the total number of chunk rebuilds.

Tesselator is the core vertex submission system. It collects vertices into an integer array and flushes them as OpenGL-style draw calls.

static const int MAX_MEMORY_USE = 16 * 1024 * 1024; // 16 MB
static const int MAX_FLOATS = MAX_MEMORY_USE / 4 / 2;

The Tesselator tracks what vertex attributes are active:

FieldPurpose
hasColorWhether vertex colors are being submitted
hasTextureWhether primary UVs are active
hasTexture2Whether secondary (lightmap) UVs are active
hasNormalWhether normals are being submitted
_noColorDisable color output
modePrimitive mode (GL_QUADS, GL_TRIANGLES, etc.)
tesselatingGuard against nested begin/end
mipmapEnableWhether mipmapping is active for this batch
countNumber of draw calls flushed
MethodPurpose
begin() / begin(int mode)Start a new primitive batch
end()Flush the batch to the GPU
vertex(float x, float y, float z)Submit a vertex position
vertexUV(float x, float y, float z, float u, float v)Submit position + texture coords
tex(float u, float v)Set current texture coordinates
tex2(int tex2)Set secondary texture coordinates (lightmap)
color(...)Set vertex color (multiple overloads: float/int/byte, with or without alpha)
normal(float x, float y, float z)Set vertex normal
offset(float xo, float yo, float zo)Set position offset applied to all vertices
addOffset(float x, float y, float z)Add to existing offset
noColor()Disable color output
useCompactVertices(bool)Enable compact vertex format (Xbox 360 optimization)
useProjectedTexture(bool)Enable projected texture pixel shader
setMipmapEnable(bool)Toggle mipmapping for the current batch
hasMaxVertices()Check if the buffer is full

Tesselator uses thread-local storage so each thread can have its own instance:

static void CreateNewThreadStorage(int bytes);
static Tesselator *getInstance();
static DWORD tlsIdx;

This is needed for multi-threaded chunk building where each thread submits vertices independently.

The useCompactFormat360 flag enables a special compressed vertex format for Xbox 360. When active, the packCompactQuad() method packs four vertices worth of position, color, UV, and lightmap data into a tighter format:

unsigned int m_ix[4],m_iy[4],m_iz[4];
unsigned int m_clr[4];
unsigned int m_u[4], m_v[4];
unsigned int m_t2[4];

An inner Bounds class automatically tracks the axis-aligned bounding box of submitted vertices:

class Bounds {
float boundingBox[6]; // min xyz, max xyz
void reset();
void addVert(float x, float y, float z);
void addBounds(Bounds& ob);
};

The bounds are used during chunk rebuilding to compute tight AABBs for culling.

On Vita, Tesselator includes:

  • setAlphaCutOut(bool) defers alpha-tested primitives to a second array (_array2, vertices2, p2)
  • getCutOutFound() checks if any cut-out primitives were deferred
  • tileQuad(...) is a fast path for compressed tile quads with per-vertex color and lightmap
  • tileRainQuad(...) is a fast path for rain particle quads
  • tileParticleQuad(...) is a fast path for particle quads

These fast paths skip the per-vertex state tracking and write directly into the vertex buffer, which is a big win on the Vita’s limited CPU.

TileRenderer handles converting block state to geometry. It has specialized methods for every block shape.

TileRenderer has three constructors:

TileRenderer(LevelSource* level, int xMin, int yMin, int zMin, unsigned char *tileIds);
TileRenderer(LevelSource* level);
TileRenderer();

The first form is used during chunk rebuilding and takes the chunk’s position and a tile ID cache for fast lookups. Each split-screen player gets their own TileRenderer instance.

The tile shape (bounding box within a block) is controlled by:

MethodPurpose
setShape(float x0, y0, z0, x1, y1, z1)Set the render bounds
setShape(Tile *tt)Copy bounds from a tile’s bounding box
setFixedShape(...)Set bounds that won’t change
clearFixedShape()Clear fixed bounds
setFixedTexture(Icon*)Override texture for all faces
clearFixedTexture()Clear texture override
setColorWhether to apply biome coloring

The tileShapeX0/X1/Y0/Y1/Z0/Z1 fields define the render bounds in 0-1 space within the block.

MethodBlock type
tesselateBlockInWorld()Standard cubes
tesselateWaterInWorld()Water (with height calculation)
tesselateTorchInWorld()Torches
tesselateCrossInWorld()Flowers, tall grass
tesselateRailInWorld()Rails
tesselateStairsInWorld()Stairs
tesselateDoorInWorld()Doors
tesselateFenceInWorld()Fences
tesselateThinFenceInWorld()Glass panes, iron bars
tesselatePistonBaseInWorld()Piston bases
tesselatePistonExtensionInWorld()Piston extensions
tesselateBedInWorld()Beds
tesselateFireInWorld()Fire
tesselateDustInWorld()Redstone dust
tesselateLadderInWorld()Ladders
tesselateVineInWorld()Vines
tesselateCactusInWorld()Cactus
tesselateLeverInWorld()Levers
tesselateDiodeInWorld()Repeaters/comparators
tesselateBrewingStandInWorld()Brewing stands
tesselateCauldronInWorld()Cauldrons
tesselateAnvilInWorld()Anvils
tesselateLilypadInWorld()Lily pads
tesselateCocoaInWorld()Cocoa pods
tesselateStemInWorld()Melon/pumpkin stems
tesselateTreeInWorld()Logs
tesselateQuartzInWorld()Quartz pillars
tesselateTripwireSourceInWorld()Tripwire hooks
tesselateTripwireInWorld()Tripwire
tesselateWallInWorld()Cobblestone walls
tesselateEggInWorld()Dragon egg
tesselateFenceGateInWorld()Fence gates
tesselateAirPortalFrameInWorld()End portal frames
tesselateFlowerPotInWorld()Flower pots
tesselateRowInWorld()Crop rows

tesselateInWorld() is the main entry point that dispatches to the right specialized method based on the tile’s render shape. It has forceData and forceEntity parameters that 4J added so tile entity renderers (like pistons) can override the block data.

tesselateInWorldNoCulling() skips face culling. This is used for blocks that need all faces drawn regardless of neighboring blocks (like pistons in motion).

tesselateInWorldFixedTexture() uses a fixed texture override for all faces. This is used for the block-breaking crack overlay.

tesselateBlockInWorldWithAmbienceOcclusionTexLighting() handles smooth lighting by sampling light values from neighboring blocks and blending them across faces. It takes base color floats for biome tinting.

The ambient occlusion system caches a huge number of intermediate values:

  • ll prefixed fields: light levels at 27 sample positions around the block (corners, edges, faces)
  • cc prefixed fields: combined color values at those same positions
  • llTrans prefixed fields: translucency flags at those positions
  • tc1-tc4 and c1r/g/b through c4r/g/b: per-corner blended colors

The blend() helper method combines light values with weighted averaging.

Individual face methods handle oriented quads:

  • renderFaceUp(), renderFaceDown(), renderNorth(), renderSouth(), renderWest(), renderEast()

Each one takes a tile, position, and texture Icon*, and writes four vertices to the Tesselator.

The northFlip, southFlip, eastFlip, westFlip, upFlip, downFlip fields control UV rotation per face, using the constants FLIP_NONE, FLIP_CW, FLIP_CCW, FLIP_180.

TileRenderer keeps a per-chunk cache for getLightColor(), getShadeBrightness(), and isTranslucentAt() results. The cache is a flat array indexed by block position relative to the chunk, with bit-packed validity flags:

static const unsigned int cache_getLightColor_valid = 0x80000000;
static const unsigned int cache_isTranslucentAt_valid = 0x40000000;
static const unsigned int cache_isSolidBlockingTile_valid = 0x20000000;
static const unsigned int cache_getLightColor_mask = 0x00f000f0;
static const unsigned int cache_isTranslucentAt_flag = 0x00000001;
static const unsigned int cache_isSolidBlockingTile_flag = 0x00000002;

The tileIds array provides fast tile ID lookup within the chunk without going through the LevelSource interface.

MethodPurpose
renderBlock()Render a single block into an item display (inventory/hand)
renderCube()Render a tile as a simple cube with alpha
renderTile()Render a tile with data and brightness
canRender(int renderShape)Check if a render shape is supported
getTexture()Get the texture Icon for a tile face (several overloads)
getTextureOrMissing()Get a texture or the missing texture fallback
getWaterHeight()Calculate the visual water level at a position

Pistons have three dedicated methods:

  • tesselatePistonBaseForceExtended() renders the piston base as if extended
  • tesselatePistonBaseInWorld() renders the base based on its actual state
  • tesselatePistonExtensionInWorld() renders the extending arm

The arm rendering has three directional helpers: renderPistonArmUpDown(), renderPistonArmNorthSouth(), renderPistonArmEastWest().

Anvils use a multi-piece system. tesselateAnvilPiece() renders one piece of the anvil geometry and returns a height offset. The render parameter controls whether to actually draw or just calculate bounds.

This singleton routes entity rendering to the right EntityRenderer subclass based on entity type (eINSTANCEOF). It keeps a map from entity type to renderer:

typedef unordered_map<eINSTANCEOF, EntityRenderer*, ...> classToRendererMap;

The render() method calculates the entity’s interpolated position and hands off to the right renderer. prepare() needs to be called each frame to set up the camera, textures, font, and options context.

Key state:

FieldPurpose
xOff, yOff, zOffCamera-relative offset (static)
xPlayer, yPlayer, zPlayerCamera world position
playerRotY, playerRotXCamera rotation
cameraEntityThe entity acting as the camera
isGuiRenderWhether we’re rendering for a GUI (inventory preview)
texturesTexture manager
itemInHandRendererFor rendering held items
levelCurrent level
optionsGame options

The staticCtor() method builds the renderer map, creating an instance of each EntityRenderer subclass and mapping it to the right eINSTANCEOF type.

EntityRenderer is the base class for all entity renderers. It provides:

MethodPurpose
render()Pure virtual: draw the entity
postRender()Draw shadows, fire overlay after the entity
bindTexture()Bind a texture by name or ID, with optional HTTP fallback
renderFlame()Draw fire overlay on burning entities
renderShadow()Draw ground shadow beneath entity
renderTileShadow()Helper for shadow projection onto a block face
renderFlat()Static helper for flat quad rendering
getModel()Return the model (virtual, overridden by subclasses)
init()Store the dispatcher reference
getFont()Get the font for name tag rendering
registerTerrainTextures()Register block textures for falling blocks etc.

MobRenderer extends it with mob-specific logic: body rotation interpolation, armor overlay rendering, name tag rendering, death animation (flip degrees), overlay colors (damage flash, suffocation), and baby scaling.

The MobRenderer::render() method follows this sequence:

  1. Calculate interpolated body rotation via rotlerp()
  2. Calculate walk position (wp) and walk speed (ws)
  3. Calculate the bob timer
  4. Calculate head rotation relative to body
  5. Call setupPosition() to translate to the entity’s position
  6. Call setupRotations() to apply body rotation and death animation
  7. Call scale() for baby mob scaling
  8. Call model->prepareMobModel() to set entity-specific state
  9. Call renderModel() which calls model->render()
  10. Loop through armor layers, calling prepareArmor() and prepareArmorOverlay() for each
  11. Call additionalRendering() for class-specific extras
  12. Call renderName() for name tags
ClassEntity
PlayerRendererPlayers (local and remote)
ChickenRendererChickens
CowRendererCows
CreeperRendererCreepers
PigRendererPigs
SheepRendererSheep
WolfRendererWolves
SquidRendererSquids
SpiderRendererSpiders and cave spiders
GhastRendererGhasts
SlimeRendererSlimes
LavaSlimeRendererMagma cubes
EndermanRendererEndermen
SilverfishRendererSilverfish
BlazeRendererBlazes
EnderDragonRendererEnder Dragon
SnowManRendererSnow golems
VillagerRendererVillagers
VillagerGolemRendererIron golems
OzelotRendererOcelots/cats
MushroomCowRendererMooshrooms
ZombieRendererZombies
HumanoidMobRendererSkeletons (with SkeletonModel), pig zombies (with ZombieModel)
GiantMobRendererGiants
ArrowRendererArrows
BoatRendererBoats
MinecartRendererMinecarts
TntRendererPrimed TNT
FallingTileRendererFalling blocks
ItemRendererDropped items
ItemSpriteRendererThrown projectiles (snowballs, ender pearls, eyes of ender, eggs, potions, exp bottles)
ExperienceOrbRendererXP orbs
PaintingRendererPaintings
FishingHookRendererFishing bobbers
FireballRendererFireballs, small fireballs, dragon fireballs
EnderCrystalRendererEnder crystals
LightningBoltRendererLightning
ItemFrameRendererItem frames
DefaultRendererFallback renderer

TileEntityRenderDispatcher routes tile entity rendering in a similar way to EntityRenderDispatcher. Specialized renderers:

ClassTile entity
ChestRendererChests
EnderChestRendererEnder chests
EnchantTableRendererEnchanting tables (with book model)
SignRendererSigns
MobSpawnerRendererMob spawners
PistonPieceRendererPiston extensions
SkullTileRendererMob heads
TheEndPortalRendererEnd portals

The Camera class provides static helpers for camera positioning:

MethodPurpose
Camera::prepare()Sets up camera orientation matrices. Takes a player and a mirror flag for anaglyph rendering.
Camera::getCameraPos()Returns the interpolated camera world position as a Vec3*
Camera::getCameraTilePos()Returns the block position of the camera as a TilePos*
Camera::getBlockAt()Checks what block type the camera is inside (for underwater/lava/fire effects)

Camera offset fields for particle and entity rendering:

FieldPurpose
xaCamera right axis X
yaCamera up axis Y
zaCamera forward axis Z
xa2Camera right axis (second component)
za2Camera forward axis (second component)
xPlayerOffs, yPlayerOffs, zPlayerOffsPlayer position offset

The modelview and projection static FloatBuffer pointers store the current GL matrices for frustum extraction.

Three Culler implementations control visibility:

class Culler {
virtual bool isVisible(AABB *bb) = 0;
virtual bool cubeInFrustum(double x0, y0, z0, x1, y1, z1) = 0;
virtual bool cubeFullyInFrustum(double x0, y0, z0, x1, y1, z1) = 0;
virtual void prepare(double xOff, yOff, zOff) = 0;
};

Standard frustum culling against view planes. Stores a FrustumData* and camera offsets (xOff, yOff, zOff). The prepare() method calls Frustum::getFrustum() to extract the six frustum planes from the current GL matrices.

Stores the six frustum planes (RIGHT, LEFT, BOTTOM, TOP, BACK, FRONT), each with four components (A, B, C, D representing the plane equation). Methods:

MethodPurpose
pointInFrustum()Test a single point
sphereInFrustum()Test a bounding sphere
cubeInFrustum()Test if a box partially overlaps the frustum
cubeFullyInFrustum()Test if a box is entirely inside the frustum
isVisible(AABB*)Test an AABB for visibility

The Frustum subclass adds calculateFrustum() which reads the GL projection and modelview matrices, computes the combined clip matrix, and extracts the six planes. normalizePlane() normalizes each plane after extraction.

Viewport-based culling that builds six frustum-like faces from the player’s position and rotation. Each face is represented by a Face inner class with center, direction, and cull offset. The inFront() method tests whether a point or box is on the visible side of a face.

No culling (renders everything). All visibility tests return true. Used during loading or when culling is disabled.

The Lighting class provides static methods for fixed-function lighting:

MethodPurpose
Lighting::turnOn()Enables standard 3D lighting with two directional lights
Lighting::turnOff()Disables lighting
Lighting::turnOnGui()Enables lighting tuned for GUI model rendering (flatter, more even)

The getBuffer() helpers pack light parameters into FloatBuffer objects for GL calls.

ClassPurpose
ItemInHandRendererFirst-person held item with bobbing, swing animation, and screen effects (pumpkin overlay, underwater, fire). Has a Minimap for in-hand map rendering.
ProgressRendererLoading screen progress bars with title, status, and percentage. Uses a critical section for thread safety.
GuiHUD rendering: hotbar, health, chat messages, vignette, pumpkin blur. Keeps per-player chat message lists.
ScreenSizeCalculatorComputes safe-zone-adjusted screen dimensions from raw resolution and options
MinimapIn-game map rendering using MapItemSavedData. Uses a color lookup table (LUT) and supports optimized rendering.
OffsettedRenderListManages display list collections offset to a world position
DirtyChunkSorter / DistanceChunkSorterSort chunks by rebuild priority or distance
MethodPurpose
render(float a)Draw the first-person hand and held item
renderItem()Draw an item held by a mob (used for both first and third person)
renderItem3D()Static method that renders a flat item as a 3D extruded shape
renderScreenEffect()Draw screen overlays (pumpkin, water, fire)
renderTex()Render a full-screen texture overlay
renderWater()Underwater overlay
renderFire()Fire overlay when camera is in fire
tick()Update the hand animation state
itemPlaced() / itemUsed()Trigger the hand swing animation

The height / oHeight fields control the hand position animation. The static list and listGlint fields store display lists for the item and its enchantment glint.

MinecraftConsoles has a bunch of additions to the rendering pipeline compared to LCEMP:

ClassEntityNotes
BatRendererBatsNew mob added in 1.4
CaveSpiderRendererCave spidersGets its own renderer (extends SpiderRenderer) with a separate texture and a smaller scale. In LCEMP, SpiderRenderer handles both.
HorseRendererHorsesFull horse renderer with layered texture caching for markings, armor overlays, and variant types (horse, donkey, mule, zombie, skeleton)
OcelotRendererOcelots/catsGets a dedicated renderer class. In LCEMP this was handled by the generic OzelotRenderer (note the spelling change too, Ozelot to Ocelot).
SkeletonRendererSkeletonsSeparated into its own class (extends HumanoidMobRenderer) with texture switching between normal and wither skeleton. In LCEMP, HumanoidMobRenderer handles both directly.
WitchRenderer / WitchModelWitchesCompletely new mob.
WitherBossRendererWither bossNew boss mob with invulnerability texture, armor overlay, and scaling.
WitherSkullRendererWither skullsProjectile renderer for wither skull attacks.
LeashKnotRenderer / LeashKnotModelLeash knotsRenders the leash fence knot entity.
TntMinecartRendererTNT minecartsCustom renderer that shows the TNT priming animation inside the minecart.
MinecartSpawnerRendererSpawner minecartsRenders the spinning mob inside the spawner minecart.
BeaconRendererBeacon beamTile entity renderer for the beacon’s light beam effect.

TileRenderer gains several new tesselate methods:

  • tesselateBeaconInWorld() for beacon blocks
  • tesselateComparatorInWorld() for redstone comparators
  • tesselateHopperInWorld() for hoppers (two overloads)
  • tesselateRepeaterInWorld() for repeaters (separate from the diode method)
  • tesselateThinPaneInWorld() for stained glass panes

A bunch of _SPU tile files are also added for PS3 SPU offloading of tile geometry building (e.g., CactusTile_SPU.h, DoorTile_SPU.h, FenceTile_SPU.h, etc.).

LevelRenderer gets several helper files broken out:

  • LevelRenderChunks.h for chunk management
  • LevelRenderer_cull.h for culling logic
  • LevelRenderer_FindNearestChunk.h for nearest chunk search
  • LevelRenderer_zSort.h for z-sorting

LivingEntityRenderer is inserted as a new base class between EntityRenderer and MobRenderer. It handles the common mob rendering pipeline: model rendering, positioning, rotations, attack animations, armor layers, name tags, and arrow-stuck-in-entity rendering. This is stuff that was previously jammed directly into MobRenderer in LCEMP.

It adds a ResourceLocation for the enchantment glint texture (ENCHANT_GLINT_LOCATION) and uses shared_ptr<LivingEntity> consistently instead of raw Entity references.

New protected virtual methods on LivingEntityRenderer:

MethodPurpose
renderArrows()Render arrows stuck in the entity
shouldShowName()Whether to display the name tag
renderNameTags()Render name tags with scaling and distance check
renderNameTag()Render a single name tag string

The name tag rendering has distance constants for readability: 16 blocks in fullscreen, 8 blocks in splitscreen or SD.