Subscreens: Difference between revisions
No edit summary |
|||
| (2 intermediate revisions by the same user not shown) | |||
| Line 5: | Line 5: | ||
Common uses include: | Common uses include: | ||
* Split screen multi player. | |||
* Picture-in-picture displays. | * Picture-in-picture displays. | ||
* Mirrors, monitors, and video marquees. | * Mirrors, monitors, and video marquees. | ||
| Line 47: | Line 48: | ||
== Allocating a subscreen == | == Allocating a subscreen == | ||
=== allocscreen === | === allocscreen() === | ||
<syntaxhighlight lang="c" line="1"> | <syntaxhighlight lang="c" line="1"> | ||
void screen = allocscreen(width, height); | void screen = allocscreen(width, height); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>width</code> | |||
| Yes | |||
| None | |||
| Requested surface width in pixels. OpenBOR rounds this value down to a multiple of four. | |||
|- | |||
| <code>height</code> | |||
| Yes | |||
| None | |||
| Requested surface height in pixels. | |||
|} | |||
<code>allocscreen()</code> creates a script-owned screen in 32-bit pixel format and clears its pixels to 0. The returned handle can be passed to screen drawing, inspection, queue capture, and composition functions. | <code>allocscreen()</code> creates a script-owned screen in 32-bit pixel format and clears its pixels to 0. The returned handle can be passed to screen drawing, inspection, queue capture, and composition functions. | ||
Returns the new screen handle. Allocation failure reports an error and does not return a valid handle. | |||
OpenBOR stores screen rows at widths divisible by four. Requested widths are rounded down to the nearest multiple of four, so creators should choose an aligned width deliberately. | OpenBOR stores screen rows at widths divisible by four. Requested widths are rounded down to the nearest multiple of four, so creators should choose an aligned width deliberately. | ||
| Line 81: | Line 101: | ||
Do not release a subscreen immediately after submitting it with <code>drawscreen()</code>. The queued entry still refers to that surface until the frame is rendered. | Do not release a subscreen immediately after submitting it with <code>drawscreen()</code>. The queued entry still refers to that surface until the frame is rendered. | ||
==== free() ==== | |||
Releases a script-owned subscreen when its useful lifetime ends. | |||
<syntaxhighlight lang="c" line="1"> | |||
free(screen); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Script-owned handle returned by <code>allocscreen()</code>. | |||
|} | |||
Replace every stored copy of the released handle with <code>NULL()</code>. Never release <code>vscreen</code>, another engine-owned screen, or a subscreen still referenced by the current sprite queue. See <code>[[free()]]</code> for general object-lifetime rules. | |||
The following scripts allocate a reusable panel at level start, rebuild and submit it during updates, then release it at level end. | The following scripts allocate a reusable panel at level start, rebuild and submit it during updates, then release it at level end. | ||
| Line 134: | Line 176: | ||
Target-screen functions write pixels as soon as they are called. They do not enter the sprite queue and do not accept a Z value. Later calls appear above earlier calls wherever their pixels overlap. | Target-screen functions write pixels as soon as they are called. They do not enter the sprite queue and do not accept a Z value. Later calls appear above earlier calls wherever their pixels overlap. | ||
Use <code>rgbcolor()</code> to construct portable 32-bit colors. | |||
=== drawspritetoscreen() === | |||
Draws a sprite immediately into a selected screen. | |||
<syntaxhighlight lang="c" line="1"> | |||
drawspritetoscreen(sprite, screen, x, y); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>sprite</code> | |||
| Yes | |||
| None | |||
| Sprite handle returned by <code>loadsprite()</code> or supplied by another graphics API. | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Destination screen handle. | |||
|- | |||
| <code>x</code> | |||
| Yes | |||
| None | |||
| Horizontal position of the sprite's stored center point. | |||
|- | |||
| <code>y</code> | |||
| Yes | |||
| None | |||
| Vertical position of the sprite's stored center point. | |||
|} | |||
Sprite comes before screen - the argument order differs from every other target-screen drawing function. The current common drawmethod applies immediately, allowing individual sprites to be scaled, rotated, flipped, tinted, clipped, or blended while the composition is built. | |||
The sprite and screen must remain valid while the call runs. Once drawn, the resulting pixels belong to the subscreen - later release of the source sprite does not erase pixels already written there. | |||
=== drawstringtoscreen() === | |||
Draws text immediately into a selected screen. | |||
<syntaxhighlight lang="c" line="1"> | |||
drawstringtoscreen(screen, x, y, font, value); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Destination screen handle. | |||
|- | |||
| <code>x</code> | |||
| Yes | |||
| None | |||
| Horizontal text position in target-screen coordinates. | |||
|- | |||
| <code>y</code> | |||
| Yes | |||
| None | |||
| Vertical text position in target-screen coordinates. | |||
|- | |||
| <code>font</code> | |||
| Yes | |||
| None | |||
| OpenBOR font index used to render the value. | |||
|- | |||
| <code>value</code> | |||
| Yes | |||
| None | |||
| Text or value converted to text for drawing. | |||
|} | |||
Common drawmethod transformations do not apply to this function. Transform the completed subscreen with <code>drawscreen()</code> when text and surrounding artwork should scale, rotate, or distort together. | |||
=== drawdottoscreen() === | |||
Draws one pixel immediately into a selected screen. | |||
<syntaxhighlight lang="c" line="1"> | |||
drawdottoscreen(screen, x, y, color, blend); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Destination screen handle. | |||
|- | |||
| <code>x</code> | |||
| Yes | |||
| None | |||
| Horizontal pixel coordinate. | |||
|- | |||
| <code>y</code> | |||
| Yes | |||
| None | |||
| Vertical pixel coordinate. | |||
|- | |||
| <code>color</code> | |||
| Yes | |||
| None | |||
| Packed color, normally created with <code>rgbcolor()</code>. | |||
|- | |||
| <code>blend</code> | |||
| No | |||
| Current method | |||
| Blend mode applied to the pixel. <code>BLEND_MODE_NONE</code> writes without color blending. | |||
|} | |||
Single-pixel drawing is the primitive behind curves, plots, particles, procedural textures, masks, unusual silhouettes, and custom rasterizers. Scripts can calculate any sequence of coordinates and use dots to turn the result into visible geometry. | |||
The following example plots a simple parabola without requiring prepared artwork. | |||
<syntaxhighlight lang="c" line="1"> | |||
void draw_curve(void screen, int origin_x, int origin_y) | |||
{ | |||
int x; | |||
int y; | |||
int no_blend = openborconstant("BLEND_MODE_NONE"); | |||
int color = rgbcolor(96, 224, 255); | |||
for(x = -32; x <= 32; x++) { | |||
y = (x * x) / 32; | |||
drawdottoscreen(screen, | |||
origin_x + x, | |||
origin_y + y, | |||
color, | |||
no_blend); | |||
} | |||
} | |||
</syntaxhighlight> | |||
=== drawlinetoscreen() === | |||
Draws a line immediately between two target-screen coordinates. | |||
<syntaxhighlight lang="c" line="1"> | |||
drawlinetoscreen(screen, x1, y1, x2, y2, color, blend); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Destination screen handle. | |||
|- | |||
| <code>x1</code>, <code>y1</code> | |||
| Yes | |||
| None | |||
| Starting point. | |||
|- | |||
| <code>x2</code>, <code>y2</code> | |||
| Yes | |||
| None | |||
| Ending point. | |||
|- | |||
| <code>color</code> | |||
| Yes | |||
| None | |||
| Packed line color, normally created with <code>rgbcolor()</code>. | |||
|- | |||
| <code>blend</code> | |||
| No | |||
| Current method | |||
| Blend mode applied while rasterizing the line. | |||
|} | |||
Lines support graphs, vectors, wireframes, targeting indicators, lightning, polygon edges, and connectors between dynamic points. Chaining several calls produces open or closed polylines. | |||
=== drawboxtoscreen() === | |||
Draws a filled rectangle immediately into a selected screen. | |||
<syntaxhighlight lang="c" line="1"> | |||
drawboxtoscreen(screen, x, y, width, height, color, blend); | |||
</syntaxhighlight> | |||
{| class="wikitable" | {| class="wikitable" | ||
! | ! Argument | ||
! | ! Required | ||
! | ! Default | ||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Destination screen handle. | |||
|- | |- | ||
| <code> | | <code>x</code>, <code>y</code> | ||
| | | Yes | ||
| | | None | ||
| Upper-left position of the rectangle. | |||
|- | |- | ||
| <code> | | <code>width</code> | ||
| | | Yes | ||
| | | None | ||
| Horizontal size in pixels. | |||
|- | |- | ||
| <code> | | <code>height</code> | ||
| | | Yes | ||
| | | None | ||
| Vertical size in pixels. | |||
|- | |- | ||
| <code> | | <code>color</code> | ||
| | | Yes | ||
| | | None | ||
| Packed fill color, normally created with <code>rgbcolor()</code>. | |||
|- | |- | ||
| <code> | | <code>blend</code> | ||
| | | No | ||
| Blend | | Current method | ||
| Blend mode applied to the filled area. | |||
|} | |} | ||
Boxes provide fast backgrounds, bars, masks, wipes, panels, and solid fields. Four thin boxes or four lines can form an outline when a filled center is not wanted. | |||
=== Combined example === | |||
<syntaxhighlight lang="c" line="1"> | <syntaxhighlight lang="c" line="1"> | ||
| Line 178: | Line 429: | ||
drawstringtoscreen(canvas, 8, 8, 0, "READY"); | drawstringtoscreen(canvas, 8, 8, 0, "READY"); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Clearing and retaining pixels == | == Clearing and retaining pixels == | ||
=== clearscreen === | === clearscreen() === | ||
<syntaxhighlight lang="c" line="1"> | <syntaxhighlight lang="c" line="1"> | ||
clearscreen(screen); | clearscreen(screen); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Screen handle whose pixel data will be reset. | |||
|} | |||
<code>clearscreen()</code> sets every pixel on the supplied surface to 0. It does not release or resize the screen. | <code>clearscreen()</code> sets every pixel on the supplied surface to 0. It does not release or resize the screen. | ||
| Line 228: | Line 489: | ||
== Inspecting a subscreen == | == Inspecting a subscreen == | ||
<code>getgfxproperty()</code> reads dimensions, format information, and pixel values from a subscreen. | === getgfxproperty() === | ||
<code>[[getgfxproperty()]]</code> reads dimensions, format information, and pixel values from a subscreen. | |||
<syntaxhighlight lang="c" line="1"> | |||
void value = getgfxproperty( | |||
screen, | |||
property, | |||
x, | |||
y | |||
); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! Argument | |||
! Required | |||
! Default | |||
! Description | |||
|- | |||
| <code>screen</code> | |||
| Yes | |||
| None | |||
| Subscreen or other compatible graphics handle to inspect. | |||
|- | |||
| <code>property</code> | |||
| Yes | |||
| None | |||
| Property name listed below. | |||
|- | |||
| <code>x</code> | |||
| Pixel only | |||
| None | |||
| Horizontal coordinate used by the <code>pixel</code> property. | |||
|- | |||
| <code>y</code> | |||
| Pixel only | |||
| None | |||
| Vertical coordinate used by the <code>pixel</code> property. | |||
|} | |||
{| class="wikitable" | {| class="wikitable" | ||
| Line 284: | Line 583: | ||
== Capturing the sprite queue == | == Capturing the sprite queue == | ||
=== drawspriteq === | === drawspriteq() === | ||
<syntaxhighlight lang="c" line="1"> | <syntaxhighlight lang="c" line="1"> | ||
drawspriteq(screen, newonly, minz, maxz, dx, dy); | drawspriteq( | ||
screen, | |||
newonly, | |||
minz, | |||
maxz, | |||
dx, | |||
dy | |||
); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 296: | Line 602: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Argument | ! Argument | ||
! Required | |||
! Default | |||
! Description | ! Description | ||
|- | |- | ||
| <code>screen</code> | | <code>screen</code> | ||
| Yes | |||
| None | |||
| Destination surface. Passing an empty or null handle selects <code>vscreen</code>. | | Destination surface. Passing an empty or null handle selects <code>vscreen</code>. | ||
|- | |- | ||
| <code>newonly</code> | | <code>newonly</code> | ||
| No | |||
| <code>0</code> | |||
| When nonzero and the queue is locked, skips entries that were already present at the lock point. Ordinary scripts normally use 0. | | When nonzero and the queue is locked, skips entries that were already present at the lock point. Ordinary scripts normally use 0. | ||
|- | |- | ||
| <code>minz</code> | | <code>minz</code> | ||
| No | |||
| Minimum integer | |||
| Lowest Z value to render, inclusive. | | Lowest Z value to render, inclusive. | ||
|- | |- | ||
| <code>maxz</code> | | <code>maxz</code> | ||
| No | |||
| Maximum integer | |||
| Highest Z value to render, inclusive. | | Highest Z value to render, inclusive. | ||
|- | |- | ||
| <code>dx</code> | | <code>dx</code> | ||
| No | |||
| <code>0</code> | |||
| Horizontal offset added to every rendered queue entry. | | Horizontal offset added to every rendered queue entry. | ||
|- | |- | ||
| <code>dy</code> | | <code>dy</code> | ||
| No | |||
| <code>0</code> | |||
| Vertical offset added to every rendered queue entry. | | Vertical offset added to every rendered queue entry. | ||
|} | |} | ||
| Line 334: | Line 654: | ||
== Submitting a subscreen == | == Submitting a subscreen == | ||
=== drawscreen === | === drawscreen() === | ||
<syntaxhighlight lang="c" line="1"> | <syntaxhighlight lang="c" line="1"> | ||
drawscreen(screen, x, y, z, blend); | drawscreen( | ||
screen, | |||
x, | |||
y, | |||
z, | |||
blend | |||
); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 344: | Line 670: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Argument | ! Argument | ||
! Required | |||
! Default | |||
! Description | ! Description | ||
|- | |- | ||
| <code>screen</code> | | <code>screen</code> | ||
| Yes | |||
| None | |||
| Completed screen handle to submit. | | Completed screen handle to submit. | ||
|- | |- | ||
| <code>x</code> | | <code>x</code> | ||
| Yes | |||
| None | |||
| Horizontal position of the surface in the destination view. | | Horizontal position of the surface in the destination view. | ||
|- | |- | ||
| <code>y</code> | | <code>y</code> | ||
| Yes | |||
| None | |||
| Vertical position of the surface in the destination view. | | Vertical position of the surface in the destination view. | ||
|- | |- | ||
| <code>z</code> | | <code>z</code> | ||
| Yes | |||
| None | |||
| Queue depth. Larger values normally render later and appear above smaller values. | | Queue depth. Larger values normally render later and appear above smaller values. | ||
|- | |- | ||
| <code>blend</code> | | <code>blend</code> | ||
| No | |||
| Current method | |||
| Optional blend mode for the completed surface. | | Optional blend mode for the completed surface. | ||
|} | |} | ||
| Line 418: | Line 756: | ||
Passing an explicit blend argument to <code>drawscreen()</code> starts from the plain method instead of the configured common method. Omit the blend argument when applying common drawmethod transformations, then include background transparency in the drawmethod configuration when zero pixels should remain transparent. | Passing an explicit blend argument to <code>drawscreen()</code> starts from the plain method instead of the configured common method. Omit the blend argument when applying common drawmethod transformations, then include background transparency in the drawmethod configuration when zero pixels should remain transparent. | ||
== Layering and nested composition == | == Advanced composition techniques == | ||
=== Layering and nested composition === | |||
Subscreens can participate in several composition passes. Completed surfaces can be queued with <code>drawscreen()</code>, captured into another surface with <code>drawspriteq()</code>, transformed, and submitted again. This enables nested interfaces, monitor-within-monitor effects, layered masks, and recursive visual processing. | Subscreens can participate in several composition passes. Completed surfaces can be queued with <code>drawscreen()</code>, captured into another surface with <code>drawspriteq()</code>, transformed, and submitted again. This enables nested interfaces, monitor-within-monitor effects, layered masks, and recursive visual processing. | ||
| Line 426: | Line 766: | ||
Use separate source and destination surfaces for feedback effects when a pass needs to read the previous result while building the next one. Alternating between two buffers avoids reading and writing the same pixel storage during one composition step. | Use separate source and destination surfaces for feedback effects when a pass needs to read the previous result while building the next one. Alternating between two buffers avoids reading and writing the same pixel storage during one composition step. | ||
== | === Orthogonal water passes and affine transformation === | ||
Water drawmethod effects transform a surface along its scan direction. One pass can apply perspective scaling, graduated size, and wave displacement across that axis. Rotating the source 90 degrees turns the perpendicular axis into the scan direction for a second pass. | |||
Full affine transformation can therefore be assembled with two subscreens. Render the source through a water or perspective pass into the first surface, rotate that result 90 degrees while capturing it into the second surface, then apply the corresponding water pass across the newly oriented axis. Rotate or position the final result as needed. Combining the two orthogonal passes provides independent control over both axes instead of limiting the effect to one set of scan lines. | |||
Relevant drawmethod properties include <code>DRAWMETHOD_PROPERTY_WATER_MODE</code>, <code>DRAWMETHOD_PROPERTY_WATER_PERSPECTIVE</code>, <code>DRAWMETHOD_PROPERTY_WATER_SIZE_BEGIN</code>, <code>DRAWMETHOD_PROPERTY_WATER_SIZE_END</code>, and the water wave amplitude, length, speed, and time properties. The same process can produce shearing, nonlinear stretching, rolling landscapes, curved marquees, rippling reflections, heat shimmer, or flag-like motion. | |||
Intermediate passes should use a controlled Z range so <code>drawspriteq()</code> captures only the intended surface. Keep temporary passes outside the visible final composition or remove them only within a rendering workflow where clearing those entries is known to be safe. | |||
=== Split-screen views === | |||
Two or more subscreens can act as independent viewports. Render action around each widely separated player into a dedicated surface, then place those surfaces side by side or in a stacked arrangement. The subscreen boundaries clip each local view automatically. | |||
Typical two-player split-screen uses two half-width surfaces and follows this sequence: | |||
# Clear or prepare both view surfaces. | |||
# Render the first player's nearby action with coordinates relative to the first local camera. | |||
# Render the second player's nearby action with coordinates relative to the second local camera. | |||
# Submit both surfaces at the same high Z value. | |||
# Draw a divider, frame, names, health displays, and other per-view interface elements above them. | |||
Queue capture works when the required subjects and layers are already present. Fully independent cameras may instead require scripted scene drawing or controlled render passes so action outside the engine's current camera remains available. Opaque view surfaces or backing boxes prevent the ordinary single-camera image from showing through uncovered pixels. | |||
The same design extends to three- or four-player layouts, temporary boss cameras, remote security feeds, spectator views, and dynamic splits that merge when players move close together. | |||
=== Manual double and double-double buffering === | |||
Script-level double buffering uses two same-sized subscreens for one composition. The front surface remains stable for presentation while the back surface receives the next completed image. Swapping their handles after construction avoids clearing or partially rewriting the surface currently referenced by the drawing queue. | |||
Two independently buffered compositions use four surfaces - effectively a custom double-double buffer. This is useful for split-screen views, stereo or anaglyph pairs, simultaneous feedback effects, or any design where two outputs each need a stable prior image and an isolated next image. | |||
<syntaxhighlight lang="c" line="1"> | |||
void left_front; | |||
void left_back; | |||
void right_front; | |||
void right_back; | |||
void allocate_view_buffers() | |||
{ | |||
if(left_front == NULL()) { | |||
left_front = allocscreen(160, 240); | |||
left_back = allocscreen(160, 240); | |||
right_front = allocscreen(160, 240); | |||
right_back = allocscreen(160, 240); | |||
} | |||
} | |||
void swap_view_buffers() | |||
{ | |||
void temporary; | |||
temporary = left_front; | |||
left_front = left_back; | |||
left_back = temporary; | |||
temporary = right_front; | |||
right_front = right_back; | |||
right_back = temporary; | |||
} | |||
</syntaxhighlight> | |||
Build the next left and right images in <code>left_back</code> and <code>right_back</code>, submit those completed surfaces, then swap the handles without writing to the queued surfaces again during that frame. The former front surfaces become writable back buffers on the next update. | |||
This method operates inside OpenBOR's own presentation pipeline and does not replace the engine's platform-level video buffering. Four surfaces also consume four times the memory of one equally sized surface, so dimensions should stay close to the required view areas. | |||
=== Additional patterns === | |||
{| class="wikitable" | {| class="wikitable" | ||
| Line 446: | Line 852: | ||
| Rotation or scaling | | Rotation or scaling | ||
| Assemble the scene at convenient local coordinates and transform the complete result with one <code>drawscreen()</code> call. | | Assemble the scene at convenient local coordinates and transform the complete result with one <code>drawscreen()</code> call. | ||
|- | |||
| Full affine or multi-axis distortion | |||
| Combine two capture surfaces, rotate one pass 90 degrees, and apply water or perspective processing along both orientations. | |||
|- | |||
| Split-screen multiplayer | |||
| Render action around distant players into separate clipped surfaces, then arrange the views with independent interface layers. | |||
|- | |||
| Double-double buffering | |||
| Maintain front and back surfaces for each of two independent compositions, building the next images without disturbing the displayed pair. | |||
|- | |- | ||
| Mosaic transition | | Mosaic transition | ||
| Line 458: | Line 873: | ||
| Multilayer mask | | Multilayer mask | ||
| Build color, mask, and effect passes separately, then combine them through queued captures and blend modes. | | Build color, mask, and effect passes separately, then combine them through queued captures and blend modes. | ||
|- | |||
| Freeze frame or instant replay | |||
| Capture selected queue layers once, retain the result, then pan, tint, scale, or annotate the frozen surface while gameplay continues or pauses. | |||
|- | |||
| Minimap or radar | |||
| Draw simplified positions, paths, and regions with dots, lines, boxes, and icons in a small retained surface. | |||
|- | |||
| Movie post-processing | |||
| Use a subscreen as the [[Movie Player|movie]] target, then frame, tint, scale, distort, or combine the video with other graphics. | |||
|- | |||
| Progressive procedural image | |||
| Generate an expensive map, texture, chart, or effect across several updates, retaining completed pixels between work steps. | |||
|- | |||
| Layer-specific color grading | |||
| Capture a selected Z range, apply tint or channel changes to the completed surface, then composite it back without altering unrelated layers. | |||
|} | |} | ||
| Line 541: | Line 971: | ||
| Submits a completed screen to the main drawing queue. Blend is optional. | | Submits a completed screen to the main drawing queue. Blend is optional. | ||
|- | |- | ||
| <code>getgfxproperty(screen, property, ...)</code> | | <code>[[getgfxproperty()|getgfxproperty(screen, property, ...)]]</code> | ||
| Reads dimensions, pixel format, palette, or pixel data. | | Reads dimensions, pixel format, palette, or pixel data. | ||
|- | |- | ||
| <code>free(screen)</code> | | <code>[[free()|free(screen)]]</code> | ||
| Releases a script-owned subscreen after its useful lifetime ends. | | Releases a script-owned subscreen after its useful lifetime ends. | ||
|} | |} | ||
Latest revision as of 22:18, 16 August 2026
Subscreens are script-allocated, off-screen 32-bit drawing surfaces. Scripts can compose sprites, text, primitive shapes, and selected parts of the sprite queue on a subscreen, then submit the completed result to the main drawing queue with drawscreen().
Unlike queued draw commands, pixels written to a subscreen remain there until they are cleared, overwritten, or the screen is released. This retained surface makes subscreens useful both as composition workspaces and as temporary graphic caches.
Common uses include:
- Split screen multi player.
- Picture-in-picture displays.
- Mirrors, monitors, and video marquees.
- Animated title and menu compositions.
- Full-screen rotation or scaling.
- Localized color and distortion effects.
- Layer capture and recomposition.
- Custom HUD elements.
- Scripted cutscenes.
- Perspective and landscape effects.
- Temporary graphic caches.
- Anaglyphs, mosaic transitions, multilayer masking, and other composite effects.
- Feedback effects such as trails and “Predator”-style invisibility.
- Movie containers.
How subscreens work
Subscreen rendering normally follows five stages.
| Stage | Purpose |
|---|---|
| Allocate | Create a 32-bit surface with allocscreen(). Reusable surfaces should be allocated once during setup.
|
| Build | Write sprites, text, dots, lines, and boxes directly to the surface. drawspriteq() can also render selected queued layers into it.
|
| Process | Retain, clear, redraw, recolor, scale, rotate, clip, or otherwise transform the composition as needed. |
| Submit | Use drawscreen() to place the completed surface in the main depth-sorted drawing queue.
|
| Release | Call free() when the script-owned surface is no longer needed.
|
Drawing into a subscreen is immediate. Drawing the completed subscreen with drawscreen() is queued. Call order controls overlap inside the surface, while the Z value passed to drawscreen() controls where the completed surface appears among other queued graphics.
Allocating a subscreen
allocscreen()
void screen = allocscreen(width, height);
| Argument | Required | Default | Description |
|---|---|---|---|
width
|
Yes | None | Requested surface width in pixels. OpenBOR rounds this value down to a multiple of four. |
height
|
Yes | None | Requested surface height in pixels. |
allocscreen() creates a script-owned screen in 32-bit pixel format and clears its pixels to 0. The returned handle can be passed to screen drawing, inspection, queue capture, and composition functions.
Returns the new screen handle. Allocation failure reports an error and does not return a valid handle.
OpenBOR stores screen rows at widths divisible by four. Requested widths are rounded down to the nearest multiple of four, so creators should choose an aligned width deliberately.
void panel = allocscreen(320, 120);
int actual_width = getgfxproperty(panel, "width");
int actual_height = getgfxproperty(panel, "height");
Keep the handle for as long as the surface is needed. Repeatedly allocating and releasing the same working surface during normal updates creates needless allocation work.
Memory use
Pixel storage requires approximately:
width * height * 4 bytes
For example, a 320 by 120 subscreen requires about 153 kilobytes of pixel storage before allocation overhead. Surface dimensions should match the composition rather than the full display unless a full-screen effect is actually required.
Lifetime and ownership
Surfaces returned by allocscreen() belong to the script and should be released with free() after their useful lifetime ends. Engine-owned screens such as vscreen are borrowed handles and must never be passed to free().
Do not release a subscreen immediately after submitting it with drawscreen(). The queued entry still refers to that surface until the frame is rendered.
free()
Releases a script-owned subscreen when its useful lifetime ends.
free(screen);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Script-owned handle returned by allocscreen().
|
Replace every stored copy of the released handle with NULL(). Never release vscreen, another engine-owned screen, or a subscreen still referenced by the current sprite queue. See free() for general object-lifetime rules.
The following scripts allocate a reusable panel at level start, rebuild and submit it during updates, then release it at level end.
level.c
void main()
{
void panel = allocscreen(160, 48);
setglobalvar("subscreen_panel", panel);
}
updated.c
void main()
{
void panel = getglobalvar("subscreen_panel");
int no_blend = openborconstant("BLEND_MODE_NONE");
if(isempty(panel)) {
return;
}
clearscreen(panel);
drawboxtoscreen(panel, 0, 0, 160, 48,
rgbcolor(24, 28, 36), no_blend);
drawlinetoscreen(panel, 0, 0, 159, 0,
rgbcolor(255, 192, 64), no_blend);
drawstringtoscreen(panel, 8, 8, 0, "Subscreen example");
drawscreen(panel, 80, 24, 1000, no_blend);
}
endlevel.c
void main()
{
void panel = getglobalvar("subscreen_panel");
if(!isempty(panel)) {
free(panel);
setglobalvar("subscreen_panel", NULL());
}
}
Drawing into a subscreen
Target-screen functions write pixels as soon as they are called. They do not enter the sprite queue and do not accept a Z value. Later calls appear above earlier calls wherever their pixels overlap.
Use rgbcolor() to construct portable 32-bit colors.
drawspritetoscreen()
Draws a sprite immediately into a selected screen.
drawspritetoscreen(sprite, screen, x, y);
| Argument | Required | Default | Description |
|---|---|---|---|
sprite
|
Yes | None | Sprite handle returned by loadsprite() or supplied by another graphics API.
|
screen
|
Yes | None | Destination screen handle. |
x
|
Yes | None | Horizontal position of the sprite's stored center point. |
y
|
Yes | None | Vertical position of the sprite's stored center point. |
Sprite comes before screen - the argument order differs from every other target-screen drawing function. The current common drawmethod applies immediately, allowing individual sprites to be scaled, rotated, flipped, tinted, clipped, or blended while the composition is built.
The sprite and screen must remain valid while the call runs. Once drawn, the resulting pixels belong to the subscreen - later release of the source sprite does not erase pixels already written there.
drawstringtoscreen()
Draws text immediately into a selected screen.
drawstringtoscreen(screen, x, y, font, value);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Destination screen handle. |
x
|
Yes | None | Horizontal text position in target-screen coordinates. |
y
|
Yes | None | Vertical text position in target-screen coordinates. |
font
|
Yes | None | OpenBOR font index used to render the value. |
value
|
Yes | None | Text or value converted to text for drawing. |
Common drawmethod transformations do not apply to this function. Transform the completed subscreen with drawscreen() when text and surrounding artwork should scale, rotate, or distort together.
drawdottoscreen()
Draws one pixel immediately into a selected screen.
drawdottoscreen(screen, x, y, color, blend);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Destination screen handle. |
x
|
Yes | None | Horizontal pixel coordinate. |
y
|
Yes | None | Vertical pixel coordinate. |
color
|
Yes | None | Packed color, normally created with rgbcolor().
|
blend
|
No | Current method | Blend mode applied to the pixel. BLEND_MODE_NONE writes without color blending.
|
Single-pixel drawing is the primitive behind curves, plots, particles, procedural textures, masks, unusual silhouettes, and custom rasterizers. Scripts can calculate any sequence of coordinates and use dots to turn the result into visible geometry.
The following example plots a simple parabola without requiring prepared artwork.
void draw_curve(void screen, int origin_x, int origin_y)
{
int x;
int y;
int no_blend = openborconstant("BLEND_MODE_NONE");
int color = rgbcolor(96, 224, 255);
for(x = -32; x <= 32; x++) {
y = (x * x) / 32;
drawdottoscreen(screen,
origin_x + x,
origin_y + y,
color,
no_blend);
}
}
drawlinetoscreen()
Draws a line immediately between two target-screen coordinates.
drawlinetoscreen(screen, x1, y1, x2, y2, color, blend);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Destination screen handle. |
x1, y1
|
Yes | None | Starting point. |
x2, y2
|
Yes | None | Ending point. |
color
|
Yes | None | Packed line color, normally created with rgbcolor().
|
blend
|
No | Current method | Blend mode applied while rasterizing the line. |
Lines support graphs, vectors, wireframes, targeting indicators, lightning, polygon edges, and connectors between dynamic points. Chaining several calls produces open or closed polylines.
drawboxtoscreen()
Draws a filled rectangle immediately into a selected screen.
drawboxtoscreen(screen, x, y, width, height, color, blend);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Destination screen handle. |
x, y
|
Yes | None | Upper-left position of the rectangle. |
width
|
Yes | None | Horizontal size in pixels. |
height
|
Yes | None | Vertical size in pixels. |
color
|
Yes | None | Packed fill color, normally created with rgbcolor().
|
blend
|
No | Current method | Blend mode applied to the filled area. |
Boxes provide fast backgrounds, bars, masks, wipes, panels, and solid fields. Four thin boxes or four lines can form an outline when a filled center is not wanted.
Combined example
void canvas = getglobalvar("composition_canvas");
void marker = getglobalvar("composition_marker");
int no_blend = openborconstant("BLEND_MODE_NONE");
clearscreen(canvas);
drawboxtoscreen(canvas, 0, 0, 128, 64,
rgbcolor(16, 20, 28), no_blend);
drawlinetoscreen(canvas, 8, 48, 120, 16,
rgbcolor(64, 192, 255), no_blend);
drawdottoscreen(canvas, 64, 32,
rgbcolor(255, 255, 255), no_blend);
drawspritetoscreen(marker, canvas, 64, 32);
drawstringtoscreen(canvas, 8, 8, 0, "READY");
Clearing and retaining pixels
clearscreen()
clearscreen(screen);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Screen handle whose pixel data will be reset. |
clearscreen() sets every pixel on the supplied surface to 0. It does not release or resize the screen.
Clear before rebuilding a composition when the new frame should replace the old one. Skip the clear deliberately when earlier pixels should remain, such as paint tools, accumulated maps, trails, damage marks, or feedback effects.
Static content can be drawn once and submitted many times. Dynamic content only needs regeneration when its underlying state changes.
void panel;
int panel_dirty = 1;
void rebuild_panel()
{
int no_blend = openborconstant("BLEND_MODE_NONE");
clearscreen(panel);
drawboxtoscreen(panel, 0, 0, 192, 64,
rgbcolor(20, 24, 32), no_blend);
drawstringtoscreen(panel, 12, 12, 0, "OPTIONS");
panel_dirty = 0;
}
void main()
{
int no_blend = openborconstant("BLEND_MODE_NONE");
if(panel == NULL()) {
panel = allocscreen(192, 64);
}
if(panel_dirty) {
rebuild_panel();
}
drawscreen(panel, 64, 40, 1000, no_blend);
}
Inspecting a subscreen
getgfxproperty()
getgfxproperty() reads dimensions, format information, and pixel values from a subscreen.
void value = getgfxproperty(
screen,
property,
x,
y
);
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Subscreen or other compatible graphics handle to inspect. |
property
|
Yes | None | Property name listed below. |
x
|
Pixel only | None | Horizontal coordinate used by the pixel property.
|
y
|
Pixel only | None | Vertical coordinate used by the pixel property.
|
| Property | Return | Subscreen behavior |
|---|---|---|
width
|
Integer | Actual allocated width after four-pixel alignment. |
height
|
Integer | Allocated height. |
srcwidth
|
Integer | Same value as width for a screen.
|
srcheight
|
Integer | Same value as height for a screen.
|
centerx
|
Integer | Returns 0 for a screen. |
centery
|
Integer | Returns 0 for a screen. |
palette
|
Pointer | Returns the screen's palette pointer. Indexed palette data is normally unnecessary for a 32-bit subscreen. |
pixelformat
|
Integer | Returns the native screen format. Script-allocated subscreens use 32-bit format. |
pixel
|
Integer | Returns the packed pixel value at the supplied X and Y coordinates. Out-of-bounds coordinates return 0. |
The pixel property requires coordinates.
int width = getgfxproperty(screen, "width");
int height = getgfxproperty(screen, "height");
int sample = getgfxproperty(screen, "pixel", 4, 6);
Pixel inspection supports procedural masks, collision-like image tests, analysis tools, and effects that react to generated artwork.
Capturing the sprite queue
drawspriteq()
drawspriteq(
screen,
newonly,
minz,
maxz,
dx,
dy
);
drawspriteq() renders entries from the current sprite queue into a supplied screen. This turns already-queued scenery, entities, effects, primitives, and other surfaces into pixels that can be retained or processed as one composition.
Only the first argument is required. Optional arguments default to 0 for newonly, the full Z range, and 0 for both offsets.
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Destination surface. Passing an empty or null handle selects vscreen.
|
newonly
|
No | 0
|
When nonzero and the queue is locked, skips entries that were already present at the lock point. Ordinary scripts normally use 0. |
minz
|
No | Minimum integer | Lowest Z value to render, inclusive. |
maxz
|
No | Maximum integer | Highest Z value to render, inclusive. |
dx
|
No | 0
|
Horizontal offset added to every rendered queue entry. |
dy
|
No | 0
|
Vertical offset added to every rendered queue entry. |
The next example captures a 160 by 96 area from queue layers 100 through 900, shifts the selected scene into local subscreen coordinates, then places it as a monitor display.
void monitor = getglobalvar("monitor_screen");
int no_blend = openborconstant("BLEND_MODE_NONE");
clearscreen(monitor);
drawspriteq(monitor, 0, 100, 900, -80, -40);
drawscreen(monitor, 144, 16, 1200, no_blend);
Captured entries remain in the queue. They will still render normally unless another operation intentionally changes or clears the queue. Routine scripts should avoid clearspriteq() because native backgrounds, entities, shadows, and interface elements share the same queue.
Queue capture reflects only entries available when drawspriteq() runs. Scripts that need native game layers normally perform the capture from updated.c, after those layers have been queued and before the final queue render.
Submitting a subscreen
drawscreen()
drawscreen(
screen,
x,
y,
z,
blend
);
drawscreen() adds the completed surface to the main sprite queue. The blend argument is optional.
| Argument | Required | Default | Description |
|---|---|---|---|
screen
|
Yes | None | Completed screen handle to submit. |
x
|
Yes | None | Horizontal position of the surface in the destination view. |
y
|
Yes | None | Vertical position of the surface in the destination view. |
z
|
Yes | None | Queue depth. Larger values normally render later and appear above smaller values. |
blend
|
No | Current method | Optional blend mode for the completed surface. |
Supplying the blend argument has an important transparency effect. OpenBOR starts from the plain drawmethod, applies the selected blend, and treats zero-valued pixels as transparent. Passing BLEND_MODE_NONE therefore gives an unblended surface whose cleared background remains transparent.
Omitting the blend argument copies the current common drawmethod instead. Under the default common method, zero-valued pixels are copied with the rest of the rectangular surface and may appear as an opaque black background.
int no_blend = openborconstant("BLEND_MODE_NONE");
/* Transparent zero-valued background, without color blending. */
drawscreen(panel, 40, 20, 1000, no_blend);
/* Uses the current common drawmethod as configured. */
drawscreen(panel, 40, 20, 1000);
Choose the form intentionally. Rectangular full-screen images may need opaque zero pixels, while irregular interfaces and effects usually need transparent cleared areas.
Transforming the completed surface
The common drawmethod can transform an entire composition when it is submitted. This is one of the most powerful subscreen techniques: many detailed internal elements can rotate, scale, flip, clip, tint, fade, repeat, or distort together as one surface.
Queued entries receive a copy of the common drawmethod when drawscreen() is called. Configure the shared method, submit the surface, then restore the default state.
void common = openborvariant("drawmethod_common");
void defaults = openborvariant("drawmethod_default");
int config = openborconstant("DRAWMETHOD_CONFIG_ENABLED")
| openborconstant("DRAWMETHOD_CONFIG_BACKGROUND_TRANSPARENCY");
copy_drawmethod(common, defaults);
set_drawmethod_property(common,
openborconstant("DRAWMETHOD_PROPERTY_CONFIG"),
config);
set_drawmethod_property(common,
openborconstant("DRAWMETHOD_PROPERTY_CENTER_X"),
80);
set_drawmethod_property(common,
openborconstant("DRAWMETHOD_PROPERTY_CENTER_Y"),
48);
set_drawmethod_property(common,
openborconstant("DRAWMETHOD_PROPERTY_SCALE_X"),
384);
set_drawmethod_property(common,
openborconstant("DRAWMETHOD_PROPERTY_SCALE_Y"),
384);
set_drawmethod_property(common,
openborconstant("DRAWMETHOD_PROPERTY_ROTATE"),
16);
drawscreen(monitor, 160, 100, 1200);
copy_drawmethod(common, defaults);
Scale values use 256 as 100 percent, so 384 produces 150 percent scaling. See Drawmethod for the full property set, including channel control, tinting, clipping, repetition, and water or perspective effects.
Passing an explicit blend argument to drawscreen() starts from the plain method instead of the configured common method. Omit the blend argument when applying common drawmethod transformations, then include background transparency in the drawmethod configuration when zero pixels should remain transparent.
Advanced composition techniques
Layering and nested composition
Subscreens can participate in several composition passes. Completed surfaces can be queued with drawscreen(), captured into another surface with drawspriteq(), transformed, and submitted again. This enables nested interfaces, monitor-within-monitor effects, layered masks, and recursive visual processing.
No dedicated drawscreentoscreen() function exists. Screen nesting is performed through the queue: submit one subscreen, then render the applicable Z range into another target with drawspriteq().
Use separate source and destination surfaces for feedback effects when a pass needs to read the previous result while building the next one. Alternating between two buffers avoids reading and writing the same pixel storage during one composition step.
Orthogonal water passes and affine transformation
Water drawmethod effects transform a surface along its scan direction. One pass can apply perspective scaling, graduated size, and wave displacement across that axis. Rotating the source 90 degrees turns the perpendicular axis into the scan direction for a second pass.
Full affine transformation can therefore be assembled with two subscreens. Render the source through a water or perspective pass into the first surface, rotate that result 90 degrees while capturing it into the second surface, then apply the corresponding water pass across the newly oriented axis. Rotate or position the final result as needed. Combining the two orthogonal passes provides independent control over both axes instead of limiting the effect to one set of scan lines.
Relevant drawmethod properties include DRAWMETHOD_PROPERTY_WATER_MODE, DRAWMETHOD_PROPERTY_WATER_PERSPECTIVE, DRAWMETHOD_PROPERTY_WATER_SIZE_BEGIN, DRAWMETHOD_PROPERTY_WATER_SIZE_END, and the water wave amplitude, length, speed, and time properties. The same process can produce shearing, nonlinear stretching, rolling landscapes, curved marquees, rippling reflections, heat shimmer, or flag-like motion.
Intermediate passes should use a controlled Z range so drawspriteq() captures only the intended surface. Keep temporary passes outside the visible final composition or remove them only within a rendering workflow where clearing those entries is known to be safe.
Split-screen views
Two or more subscreens can act as independent viewports. Render action around each widely separated player into a dedicated surface, then place those surfaces side by side or in a stacked arrangement. The subscreen boundaries clip each local view automatically.
Typical two-player split-screen uses two half-width surfaces and follows this sequence:
- Clear or prepare both view surfaces.
- Render the first player's nearby action with coordinates relative to the first local camera.
- Render the second player's nearby action with coordinates relative to the second local camera.
- Submit both surfaces at the same high Z value.
- Draw a divider, frame, names, health displays, and other per-view interface elements above them.
Queue capture works when the required subjects and layers are already present. Fully independent cameras may instead require scripted scene drawing or controlled render passes so action outside the engine's current camera remains available. Opaque view surfaces or backing boxes prevent the ordinary single-camera image from showing through uncovered pixels.
The same design extends to three- or four-player layouts, temporary boss cameras, remote security feeds, spectator views, and dynamic splits that merge when players move close together.
Manual double and double-double buffering
Script-level double buffering uses two same-sized subscreens for one composition. The front surface remains stable for presentation while the back surface receives the next completed image. Swapping their handles after construction avoids clearing or partially rewriting the surface currently referenced by the drawing queue.
Two independently buffered compositions use four surfaces - effectively a custom double-double buffer. This is useful for split-screen views, stereo or anaglyph pairs, simultaneous feedback effects, or any design where two outputs each need a stable prior image and an isolated next image.
void left_front;
void left_back;
void right_front;
void right_back;
void allocate_view_buffers()
{
if(left_front == NULL()) {
left_front = allocscreen(160, 240);
left_back = allocscreen(160, 240);
right_front = allocscreen(160, 240);
right_back = allocscreen(160, 240);
}
}
void swap_view_buffers()
{
void temporary;
temporary = left_front;
left_front = left_back;
left_back = temporary;
temporary = right_front;
right_front = right_back;
right_back = temporary;
}
Build the next left and right images in left_back and right_back, submit those completed surfaces, then swap the handles without writing to the queued surfaces again during that frame. The former front surfaces become writable back buffers on the next update.
This method operates inside OpenBOR's own presentation pipeline and does not replace the engine's platform-level video buffering. Four surfaces also consume four times the memory of one equally sized surface, so dimensions should stay close to the required view areas.
Additional patterns
| Effect | Subscreen pattern |
|---|---|
| Picture-in-picture or monitor | Capture a queue layer range into a small surface, then submit it at the desired interface depth. |
| Mirror or reflection | Capture the applicable scene range, flip or distort the completed surface with the common drawmethod, then submit it behind the foreground. |
| Cached HUD or menu | Draw static panel art once, rebuild only changed values or sections, and submit the retained surface each frame. |
| Localized recolor | Compose the affected elements separately, then apply tint or channel properties when submitting the surface. |
| Rotation or scaling | Assemble the scene at convenient local coordinates and transform the complete result with one drawscreen() call.
|
| Full affine or multi-axis distortion | Combine two capture surfaces, rotate one pass 90 degrees, and apply water or perspective processing along both orientations. |
| Split-screen multiplayer | Render action around distant players into separate clipped surfaces, then arrange the views with independent interface layers. |
| Double-double buffering | Maintain front and back surfaces for each of two independent compositions, building the next images without disturbing the displayed pair. |
| Mosaic transition | Compose or capture the source image, then draw clipped, scaled, or offset portions through controlled passes. |
| Perspective landscape | Build a wide source surface and use drawmethod water, perspective, span, or scale properties during final composition. |
| Trails or invisibility | Retain selected pixels between updates, fade or distort the prior result, and composite the current subject into the next pass. |
| Multilayer mask | Build color, mask, and effect passes separately, then combine them through queued captures and blend modes. |
| Freeze frame or instant replay | Capture selected queue layers once, retain the result, then pan, tint, scale, or annotate the frozen surface while gameplay continues or pauses. |
| Minimap or radar | Draw simplified positions, paths, and regions with dots, lines, boxes, and icons in a small retained surface. |
| Movie post-processing | Use a subscreen as the movie target, then frame, tint, scale, distort, or combine the video with other graphics. |
| Progressive procedural image | Generate an expensive map, texture, chart, or effect across several updates, retaining completed pixels between work steps. |
| Layer-specific color grading | Capture a selected Z range, apply tint or channel changes to the completed surface, then composite it back without altering unrelated layers. |
Performance and queue use
Large subscreens cost memory and fill bandwidth, but a completed surface consumes only one sprite-queue entry when submitted with drawscreen(), allowing subscreens to act as sprite queue multipliers. Keep off-screen surfaces near the size of the content being composed, use widths divisible by four, and redraw only when their contents need to change.
The standard 5,000-entry sprite queue already provides ample headroom for ordinary games, including object-heavy and bullet-heavy designs. Queue consolidation is therefore a useful capability, not a requirement for typical object counts. Subscreens are most valuable for retained composition, whole-surface effects, layer capture, and avoiding repeated construction work.
Pixel cost still applies while building the surface. Hundreds of direct draws merged into one queued item still perform their raster work, and large transformed surfaces require proportionally more memory traffic. Favor smaller working areas, cached static content, and deliberate rebuild points.
Common mistakes
| Symptom | Cause | Correction |
|---|---|---|
| Memory or allocation churn grows during play | The script calls allocscreen() every update.
|
Allocate once, retain the handle, and reuse the same surface. |
| Old pixels remain behind moving artwork | The retained surface is not cleared before a replacement frame is drawn. | Call clearscreen() before rebuilding, unless accumulation is intentional.
|
| Elements appear in the wrong order inside the subscreen | Immediate target-screen drawing has no Z sort. | Issue draw calls from back to front, or queue and capture a sorted range with drawspriteq().
|
drawspritetoscreen() fails or receives the wrong handles
|
The sprite and screen arguments were reversed. | Use drawspritetoscreen(sprite, screen, x, y).
|
| Cleared areas appear as opaque black | drawscreen() copied zero-valued pixels under a common method without background transparency.
|
Pass an explicit blend such as BLEND_MODE_NONE, or enable DRAWMETHOD_CONFIG_BACKGROUND_TRANSPARENCY in the common drawmethod.
|
| Queue capture is empty or incomplete | Required entries had not been queued when drawspriteq() ran, or the Z range excluded them.
|
Capture later in the render setup, commonly from updated.c, and verify minz and maxz.
|
| Engine rendering disappears | The script called clearspriteq() during the normal shared render pass.
|
Leave the shared queue intact unless a controlled custom renderer intentionally replaces it. |
| Invalid pointer errors or unstable rendering occur | The script freed an engine-owned screen, reused a released handle, or released a queued screen before rendering completed. | Free only script-owned surfaces after their final rendered use, then replace stored handles with NULL().
|
Function reference
| Function | Role |
|---|---|
allocscreen(width, height)
|
Allocates and clears a script-owned 32-bit subscreen. |
clearscreen(screen)
|
Sets every pixel on the supplied screen to 0. |
drawspritetoscreen(sprite, screen, x, y)
|
Draws a sprite immediately into a screen. |
drawstringtoscreen(screen, x, y, font, value)
|
Draws text immediately into a screen. |
drawdottoscreen(screen, x, y, color, blend)
|
Draws one pixel immediately into a screen. Blend is optional. |
drawlinetoscreen(screen, x1, y1, x2, y2, color, blend)
|
Draws a line immediately into a screen. Blend is optional. |
drawboxtoscreen(screen, x, y, width, height, color, blend)
|
Draws a filled box immediately into a screen. Blend is optional. |
drawspriteq(screen, newonly, minz, maxz, dx, dy)
|
Renders all or part of the current sprite queue into a selected screen. Arguments after screen are optional. |
drawscreen(screen, x, y, z, blend)
|
Submits a completed screen to the main drawing queue. Blend is optional. |
getgfxproperty(screen, property, ...)
|
Reads dimensions, pixel format, palette, or pixel data. |
free(screen)
|
Releases a script-owned subscreen after its useful lifetime ends. |