Graphics
Scripter's Rift engine offers various 2D and 3D graphics primitives under the Graphics
namespace revolving around the primitive CommandBuffer
.
Command buffer
Command buffer is the way we schedule rendering of in-game graphics, by default only the immediate command buffer exists which can be fetched by calling Graphics.GetImmediate()
or simply by using the object that is passed in the Render
event; however you can also create an instance by calling Graphics.CreateCommandBuffer()
which is very useful for caching complex drawings.
-- Render event gets invoked every frame with the immediate buffer.
Event<CommandBuffer> Event.OnRender
-- Gets the immediate command buffer.
CommandBuffer Graphics.GetImmediate()
-- Creates a new command buffer.
CommandBuffer Graphics.CreateCommandBuffer()
You can queue drawings to an offscreen buffer and then push them at once to the immediate queue by using the member function insert
. Insert optionally takes a transformation matrix and a multiplied color that gets applied to all vertices in the buffer. The underlying renderer may optimize this operation to a zero-copy queue so make sure not to modify and insert buffer again afterwards.
The in-place equivalent to the insert
function is transform
which has the same semantics as insert
but also accepts an optional range to constraint to.
queue
is an extended version of insert
but instead this
is inserted directly into the immediate buffer's queue and it accepts a number of other arguments.
-- Inserts the queued drawings into another command buffer with transformation.
void CommandBuffer:insert(CommandBuffer src, matrix? transform, Color? tint)
-- Transforms all vertices in the command buffer in-place.
void CommandBuffer:transform(matrix? transform, Color? tint, uint? firstVertex, uint? lastVertex)
-- Queues the buffer to be rendered as a mesh in the renderer context.
bool CommandBuffer:queue(matrix worldTf, matrix? screenTf, Color? tint, vec2? screenBegin, vec2? screenSize, vec2? scissorBegin, vec2? scissorSize)
Command buffer additionally has the following members.
-- Clears the buffer.
void CommandBuffer:clear()
-- Gets the maximum and minimum (x,y,z) computed across all vertices.
-- Note that this is not a fast function.
{vec3, vec3} CommandBuffer:getBoundaries(matrix? transform)
-- Number of vertices in the buffer. -- Alias for #buffer.
uint CommandBuffer.vertexCount
-- Number of index entries for triangles / lines in the buffer.
uint CommandBuffer.triIndexCount
uint CommandBuffer.lineIndexCount
You can see a very basic example of text caching below.
const cbuf = Graphics.CreateCommandBuffer();
cbuf.text2D(vec2(), 0, 'Hello!', 64, Color.RED);
Event.OnRender(gfx => {
// Renders "Hello!" at (100, 100)
gfx.insert(cbuf, Matrix.Translation2D(vec2(100, 100)));
});
Additionally you can also create a command buffer from a Wavefront object using the File.LoadModel
function, which will also load any required texture for the material descriptor automatically.
-- Loads the Wavefront object as a CommandBuffer.
CommandBuffer File.LoadModel(string path)
CommandBuffer
object supports comparison and length as metamethods.
uint CommandBuffer:__len()
Event.OnRender(gfx => {
print(gfx == Graphics.GetImmediate()); // Prints "true"
print(gfx.length() == gfx.vertexCount); // Prints "true"
});
Geometric rendering
Here's a list of all shapes you can use with the CommandBuffer
.
float z
in the 2D primitives is the artifical depth relevant in case it was a projected 3D coordinate, otherwise can be left zero.C<N>
means that its either a table ofN
colors, or a single color to be applied at every edge, color paramters default toColor.WHITE
if not given.R<N>
means that its either a table ofN
radii, or a single radius to be applied at every direction.int? tx
is the texture identifier, which if not passed defaults toGraphics.NULL_TEXTURE
which when sampled outputs the input color.vec2? tdst
andvec2? tsrc
are the coordinates within the texture from 0 to 1.float k
is the thickness in case of non-fill primitives.
-- Null texture that always samples to WHITE.
--
int Graphics.NULL_TEXTURE -- 0
-- Generic drawing primitives for both 2D and 3D.
--
void CommandBuffer:line2D(vec2 src, vec2 dst, float z, C<2>? c, float? k)
void CommandBuffer:line3D(vec3 src, vec3 dst, C<2>? c, float? k)
void CommandBuffer:triangle2D(vec2 p1, vec2 p2, vec2 p3, float z, C<3>? c, float? k)
void CommandBuffer:triangle3D(vec3 p1, vec3 p2, vec3 p3, C<3>? c, float? k)
void CommandBuffer:fillTriangle2D(vec2 p1, vec2 p2, vec2 p3, float z, C<3>? c)
void CommandBuffer:fillTriangle3D(vec3 p1, vec3 p2, vec3 p3, C<3>? c)
void CommandBuffer:quad2D(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float z, C<4>? c, float? k)
void CommandBuffer:quad3D(vec3 p1, vec3 p2, vec3 p3, vec3 p4, C<4>? c, float? k)
void CommandBuffer:fillQuad2D(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float z, C<4>? c, int? tx, vec2? tsrc, vec2? tdst)
void CommandBuffer:fillQuad3D(vec3 p1, vec3 p2, vec3 p3, vec3 p4, C<4>? c, int? tx, vec2? tsrc, vec2? tdst)
void CommandBuffer:quadRounded2D(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float z, R<4> r, C<4>? c, float? k)
void CommandBuffer:quadRounded3D(vec3 p1, vec3 p2, vec3 p3, vec3 p4, R<4> r, C<4>? c, float? k)
void CommandBuffer:fillQuadRounded2D(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float z, R<4> r, C<4>? c, int? tx, vec2? tsrc, vec2? tdst)
void CommandBuffer:fillQuadRounded3D(vec3 p1, vec3 p2, vec3 p3, vec3 p4, R<4> r, C<4>? c, int? tx, vec2? tsrc, vec2? tdst)
void CommandBuffer:circle2D(vec2 pos, float z, R<2> r, C<2>? c, float? k, int? tx, float? percent, int? edges, float? rot)
void CommandBuffer:circle3D(vec3 pos, R<2> r, C<2>? c, float? k, int? tx, float? percent, int? edges, vec3? rot)
void CommandBuffer:fillCircle2D(vec2 pos, float z, R<2> r, C<2>? c, int? tx, float? percent, int? edges, float? rot)
void CommandBuffer:fillCircle3D(vec3 pos, R<2> r, C<2>? c, int? tx, float? percent, int? edges, vec3? rot)
void CommandBuffer:ngon2D(vec2 pos, float z, vec2 scale, int n, C<2>? c, float? k, float? rot)
void CommandBuffer:ngon3D(vec3 pos, vec2 scale, int n, C<2>? c, float? k, vec3? rot)
void CommandBuffer:fillNgon2D(vec2 pos, float z, vec2 scale, int n, C<2>? c, float? rot)
void CommandBuffer:fillNgon3D(vec3 pos, vec2 scale, int n, C<2>? c, vec3? rot)
-- 2D shapes.
--
void CommandBuffer:rect2D(vec2 src, vec2 size, float z, C<4>? c, float? k, float? shift, float? rot)
void CommandBuffer:rectRounded2D(vec2 src, vec2 size, float z, R<4> r, C<4>? c, float? k, float? shift, float? rot)
void CommandBuffer:fillRect2D(vec2 src, vec2 size, float z, C<4>? c, int? tx, vec2? tsrc, vec2? tdst, float? shift, float? rot)
void CommandBuffer:fillRectRounded2D(vec2 src, vec2 size, float z, R<4> r, C<4>? c, int? tx, vec2? tsrc, vec2? tdst, float? shift, float? rot)
-- 3D shapes.
--
void CommandBuffer:pyramid3D(vec3 pos, vec3 scale, C<2>? c, float? k, vec3? rot)
void CommandBuffer:fillPyramid3D(vec3 pos, vec3 scale, C<2>? c, vec3? rot)
-- Box rotated around min
void CommandBuffer:box3D(vec3 min, vec3 max, C<8>? c, float? k, vec3? rot)
void CommandBuffer:fillBox3D(vec3 min, vec3 max, C<8>? c, vec3? rot)
-- Box rotated around center
void CommandBuffer:cbox3D(vec3 min, vec3 max, C<8>? c, float? k, vec3? rot)
void CommandBuffer:fillCbox3D(vec3 min, vec3 max, C<8>? c, vec3? rot)
void CommandBuffer:fillNgonPrism3D(vec3 pos, vec3 scale, int n, C<2>? c, vec3? rot)
void CommandBuffer:fillCylinder3D(vec3 pos, vec3 scale, C<2>? c, float? percent, int? edges, vec3? rot)
void CommandBuffer:fillSphere3D(vec3 pos, vec3 scale, Color? c, float? percentx, float? percenty, int? edges, vec3? rot)
Text rendering
Text can be rendered using the Text2D/Text3D
function similarly to the geometric primitives, its boundaries can also be pre-calculated using Text.Calc
.
-- Text rendering, returns the size of the quad.
--
vec2 CommandBuffer:text2D(vec2 at, float z, string text, float width, Color? col, int? flags, int? lineWrapAfter, float? rot)
vec3 CommandBuffer:text3D(vec3 at, string text, float width, Color? col, int? flags, int? lineWrapAfter, vec3? rot)
-- Calculates the text boundaries and returns the size as a vec2.
--
vec2 Text.Calc(string text, float width, int? flags, int? lineWrapAfter)
-- Text rendering flags.
--
int Text.UPPER -- Forces the text to be uppercase
int Text.LOWER -- Forces the text to be lowercase
int Text.NOCTRL -- Ignores control characters (e.g. new line)
int Text.VCENTER -- Vertically centers the text
int Text.LJUST -- Justifies the text left (default).
int Text.RJUST -- Justifies the text right (default).
int Text.HCENTER -- Horizontally centers the text
int Text.BOLD -- Uses the bold font
int Text.ITALIC -- Uses the italic font
int Text.MONO -- Uses the monospace font
int Text.NOLOCAL -- Disables localized phrases using {{phrase}}
Text input supports special escape codes to change the style of the text within the text.
\b
will switch the text to bold.\v
will switch the text to italic.\f
will reset to the original format.\rRGB
will apply a new color where RGB is in 0 to F.\a
will make the next character render as superscript or subscript if repeated (\a\a
), positioning and scaling follows LaTeX rules. (\x07
in TypeScript as it does not accept Bell escape.)
You can also use any of the FontAwesome v6 Pro icons either via their Unicode codepoint or using their name converted to CONST_CASE
under FontAwesome
namespace. Bold fonts will map to solid shapes.
const text =
'This is a \bvery\f \r0F0\vcool \ftext. y=x\x072\n' +
'\t\t\t\t\v \u{f5ae} crafted with \rF00' +
FontAwesome.HEART +
'\b' +
FontAwesome.HEART;
Event.OnRender(gfx => {
gfx.text2D(vec2(100, 100), 0, text, 32);
gfx.text3D(vec3(2100, 0, 600), text, 32, undefined, undefined, undefined, vec3(0.5));
});

Additionally, text can be rendered in a console-like fashion using the Engine
APIs below.
-- Submits a user-visible message on the screen.
--
void Engine.Info(string message)
void Engine.Warn(string message)
void Engine.Error(string message)
void Engine.Success(string message)
void Engine.SubmitMessage(Color color, string message)
-- Prints a message on the top left corner of the screen only for this frame.
--
void Engine.Debug(string message)
Textures
As briefly mentioned in the earlier section sprites can be loaded using File.LoadSprites
. The file must be a jpg
, gif
, png
or bmp
file and must consist of one or multiple Dims x Dims
sprites stacked horizontally and vertically, if dimensions of a singular sprite is not provided by the user, it will default to 128x128
. We recommend using a png
file.
-- Loads the given texture as a sprite map and returns the texture id and the width and height of the atlas.
{int, int, int} File.LoadSprites(string path, int? dims)
You can see an example 64x64 spritesheet below. loading this file using File.LoadSprites
would yield {N, 2, 2}
where N is an arbitrary index, and each of the numbered squares map to texture identifier N+k
respectively.

You can also load an image as a single texture using File.LoadTexture
which returns the texture id and the aspect ratio of the source. If Texture.PRESERVE_ASPECT
is not specified, the function will force the texture into a square.
-- Texture loading flags.
--
int Graphics.PRESERVE_ASPECT
int Graphics.CONVERT_TO_MASK
-- Loads the given texture as a singular sprite.
--
{int, float} File.LoadTexture(string path, int? flags)
GIF support
GIF files can be loaded using the File.LoadTexture
but due to their animated nature have some quirks as to the returned texture id and will also yield a static image if loaded using File.LoadSprites
.
The identifier returned is a pseudo-sprite that will be resolved into the sprite for the current frame once passed to any APIs used for drawing. However it does not work with certain lower level APIs involving manually crafted vertices and will not be animated when cached.
You can resolve a specific frame using the Graphics.ResolveFrame
function.
-- Resolves the frame of the given texture at a specific time, if not specified current time.
int Graphics.ResolveFrame(int tx, float? timeInMs)
Advanced rendering
For more advanced rendering needs, CommandBuffer
type also allows pushing of manually crafted vertices using the Poly drawing APIs.
-- Constructs a vertex object given the arguments.
--
Vertex Graphics.Vertex2(vec2 pos, float depth, Color? color, vec2? tpos, int? tx)
Vertex Graphics.Vertex3(vec3 pos, Color? color, vec2? tpos, int? tx)
-- Vertex screen/world coordinates.
--
float Vertex.x
float Vertex.y
float Vertex.z
-- Vertex texture coordinates.
--
float Vertex.u
float Vertex.v
-- Vertex texture ID.
--
uint Vertex.tx
-- Vertex color code.
--
uint Vertex.ccode
-- Vertex color code wrapped as a Color object.
--
Color Vertex.color
-- Vertex screen/world flag. True if this vertex was constructed as Vertex3.
--
bool Vertex.isWorld
-- Accepts a line strip of 2 + N vertices connected end to end.
--
void CommandBuffer:polyLine(Vertex[] vertices)
-- Accepts a triangle strip of 3 + N vertices connected end to end.
--
void CommandBuffer:polyTri(Vertex[] vertices)
-- Accepts pairs of two vertices.
--
void CommandBuffer:polyLineList(Vertex[] vertices)
-- Accepts tuples of three vertices.
--
void CommandBuffer:polyTriList(Vertex[] vertices)
-- Applies a software clipping rectangle over the given index list range.
-- Might produce certain inaccuracies due to space constraints, an actual scissor should be used where possible.
--
void CommandBuffer:softClip(vec2|vec3 rectBegin, vec2|vec3 rectEnd, bool isWorld, uint tri0, uint line0, uint? tri1, uint? line1)
Post-processing
Graphics
namespace exposes a special texture identifier called FB_TEXTURE
, which maps to a texture representing the rendered game frame and is the core primitive for many post-processing effects as it is used for generating blur.
You can find a naîve implementation of a function that blurs a rectangle in the screen space below to further understand its use case.
const GAUSSIAN_KERNEL = [
[0.16210285, 0.09832035, 0.021938235],
[0.09832035, 0.059634306, 0.013306212],
[0.021938235, 0.013306212, 0.0029690173]
];
const DISPERSION = 3;
function blurRect2D(gfx: CommandBuffer, p0: vec2, sz: vec2, z: number, alpha: number) {
gfx.fillRect2D(p0, sz, z, Color.WHITE);
const disp = DISPERSION / Graphics.GetResolution();
const mul = Math.pow(1 - alpha, 2 / GAUSSIAN_KERNEL[0][0]);
for (const i of $range(-2, 2)) {
for (const j of $range(-2, 2)) {
const r = GAUSSIAN_KERNEL[Math.abs(j)][Math.abs(i)];
const delta = vec2(i * disp, j * disp);
// Note: FB texture does not take absolute texture locations but rather offsets from the render location!
gfx.fillRect2D(p0, sz, z, Color.WHITE.alpha(r * mul), Graphics.FB_TEXTURE, delta, delta);
}
}
}
For the sake of simplicity and performance, the CommandBuffer
offers the following blur helpers that abstract away most of the calculation.
-- Framebuffer texture that samples to the rendered game frame.
--
int Graphics.FB_TEXTURE
-- Accelerated blurred quad rendering.
--
void CommandBuffer:blurQuad2D(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float z, C<4>? col, float? dispersion)
void CommandBuffer:blurQuad3D(vec3 p1, vec3 p2, vec3 p3, vec3 p4, C<4>? col, float? dispersion)
void CommandBuffer:blurRect2D(vec2 src, vec2 size, float z, C<4>? col, float? dispersion, float? shift, float? rot)
Core graphics
We also expose the core primitives that we use to render things such as player ESP under CommandBuffer
. You can use these to render UI elements in our style. Primitivates that return bool indicate whether or not it was rendered.
-- Draws a bounding box in engine style, takes bounding box ranges, depth, color gradient
-- for the line (c0, c1), the background color (cb) and the midpoint of lines.
--
bool CommandBuffer:drawBboxFor(Entity ent, Color c0, Color c1, Color cb, float? mp)
void CommandBuffer:drawBbox2(vec2 bbMin, vec2 bbMax, float depth, Color c0, Color c1, Color cb, float? mp)
bool CommandBuffer:drawBbox3(vec3 bbMin, vec3 bbMax, Color c0, Color c1, Color cb, float? mp)
-- Draws a health bar in engine style, takes the bounding box in screen space, depth, health, lerped
-- healths, minimum hp in the bar before it starts compressing and the colors. Health is given as
-- vec4(Health, Armor, Shield, Barrier), lerped health parameter will be outputted the currently rendered rate
-- and it is used for animation.
--
bool CommandBuffer:drawHbarFor(Entity ent, vec2 min, vec2 max, C<4> colors, float? a)
void CommandBuffer:drawHbar(vec2 min, vec2 max, float depth, vec4 health, vec4 lerpHealth, float fullHp, C<4> colors, float? a)
-- Draws a secondary bar in engine style, takes the bounding box in screen space, depth, rate
-- at which its filled and the primary color.
--
bool CommandBuffer:drawSbarFor(Entity ent, vec2 min, vec2 max, Color col)
void CommandBuffer:drawSbar(vec2 min, vec2 max, float depth, float rate, Color col)
-- Draws the default engine skeleton for the given entity with the given primary color.
--
bool CommandBuffer:drawSkeletonFor(Entity ent, C<16> col)
-- Draws a range / field of view indicator.
--
void CommandBuffer:drawRange(vec3 at, float radius, Color? c, float? percent, float? yaw)
-- Draws a pick indicator.
--
void CommandBuffer:drawIndicator(vec2 at, float z, Color c, float scale)
void CommandBuffer:drawIndicatorFor(Entity e, Color c, float? scale)
Frame details
-- Returns true if the given vector is within the screen field of view.
bool Graphics.InView2(vec2)
bool Graphics.InView3(vec3)
-- Returns the screen resolution.
vec2 Graphics.GetResolution()
-- Returns the current view matrix.
matrix Graphics.GetViewMatrix()
-- Returns the current projection matrix.
matrix Graphics.GetProjMatrix()
-- Returns the current view x projection matrix.
matrix Graphics.GetViewProjMatrix()
-- Returns the inverse view projection matrix.
matrix Graphics.GetInvViewProjMatrix()
Renderer configuration
Graphics namespace also exposes a few functions that enables you to configure the renderer's quality and post-processing steps.
-- Default multisample count.
uint Graphics.DEFAULT_MULTISAMPLE_COUNT
-- Default bloom state.
bool Graphics.DEFAULT_BLOOM_STATE
-- Checks support for the multi-sample count.
bool Graphics.CheckMultiSampleCount(uint count)
-- Changes the multi-sample count used, returns false on failure.
bool Graphics.SetMultiSampleCount(uint count)
-- Checks whether or not bloom is enabled.
bool Graphics.GetBloomState()
-- Enables or disables bloom.
bool Graphics.SetBloomState(bool state)