Skip to content
Vladislav edited this page Jun 25, 2023 · 10 revisions

This is library for efficient usage of GPU resources and rendering data on screen as fast as possible. MineOS, it's software and internal interface libraries are based on screen library.

It's main concept is very simple: there are 6 tables stored in the RAM and containing information about pixels on the screen. The first 3 tables stores what is displayed at the moment, and the other 3 tables - what user is drawing at the moment

This is library for efficient usage of GPU resources and rendering data on screen as fast as possible. MineOS, it's software and internal interface libraries are based on screen library.

It's main concept is very simple: there are 6 tables stored in the RAM and containing information about pixels on the screen. The first 3 tables stores what is displayed at the moment, and the other 3 tables - what user is drawing to screen buffer in this moment. After performing all the drawing operations, user calls the screen.update() method: library will automatically detect changed pixels, group them into an temporary buffer by color values to reduce GPU calls, and finally will display result on screen.

Compared with standard linear rendering, the rendering with this library time is reduced by hundreds and thousands of times. The picture below shows this:

1

The price of such speed is an increased consumption of RAM. To minimize it, library uses the one-dimensional structure of the pixel data tables instead of the three-dimensional one. To obtain pixel data, special methods are used that convert screen coordinates to screen buffer indices and vice versa, more about this is written below in Auxiliary methods section.

In addition, this library doesn't access any component table directly, replacing them with constants aliases and avoiding calculation of table hashes: for example, instead of instead of gpu.setBackground(...) library uses internal GPUSetBackground(...) function. With a competent implementation, this extremely increases performance without overloading Lua GC.

Components bindings

screen.setGPUAddress(string address)

Sets the GPU component address that sould be used for drawing operations. Content of buffer will be cleared with black pixels and whitespace symbol

screen.getGPUAddress(): string address

Returns address of currently used GPU component

screen.setScreenAddress(string address, [boolean reset])

Binds GPU used by library to given screen component address. Content of buffer will be cleared with black pixels and whitespace symbol. The optional parameter reset will also reset the screen resolution to the maximum

screen.getScreenAddress(): string address

Returns address of currently bound screen

Screen resolution

screen.getResolution(): int width, int height

Returns screen buffer resolution. There's also screen.getWidth() and screen.getHeight() methods for your convenience

screen.setResolution(int width, int height)

Sets screen buffer and GPU resolution. Content of buffer will be cleared with black pixels and whitespace symbol

screen.getMaxResolution(): int width, int height

Returns largets suported screen resolution

screen.getScreenAspectRatio(): int width, int height

Returns multiblock screen sturcture size in blocks

screen.getScaledResolution([ float [0.1; 1.0] scale ]): int width, int height

Returns "best" screen resolution that can be fitted on multiblock screen structure with smallest possible "black lines" size. Optional scale argument will apply multiplication factor when while calculating result. You can use result like this:

1

Color depth

screen.setColorDepth(int depth)

Sets currenlty used GPU color depth

screen.getColorDepth(): int depth

Returns currenlty used GPU color depth

screen.getMaxColorDepth()): int depth

Returns largest supported GPU color depth

Rendering

screen.update([boolean force])

Checks of what pixels need to be drawn and draws them on screen. If optional argument force is specified, then the contents of screen buffer will be drawn completely and without checking changes.

screen.setDrawLimit(int x1, int y1, int x2, int y2)

Sets buffer draw limit to the specified values. In this case, any operations that go beyond the limits will be ignored. By default, the buffer always has a drawing limit in the ranges x ∈ [1; screen.width] and y ∈ [1; screen.height].

screen.getDrawLimit(): int x1, int y1, int x2, int y2

Returns currently set draw limit.

screen.copy(int x, int y, int width, int height): table pixelData

Copies content of specified area from screen buffer and returns it as a table. Later it can be used with screen.paste(...).

screen.paste(int x, int y, int pixelData)

Pastes the copied contents of screen buffer to the specified coordinates.

screen.set(int x, int y, 24-bit int background, 24-bit int foreground, string symbol)

Sets values of specified pixel on screen to given ones.

screen.get(int x, int y): 24-bit int background, 24-bit int foreground, string symbol

Returns values of specified pixel on screen.

screen.drawRectangle(int x, int y, int width, int height, 24-bit int background, 24-bit int foreground, string symbol, *float [0.0; 1.0] transparency)

Draws the rectangular area with the specified pixel data. If optional transparency parameter is specified, the rectangle will "cover" existing pixel data like a glass with given transparency.

screen.clear([24-bit int color, *float [0.0; 1.0] transparency])

Works like screen.drawRectangle(...), but applies immediately to all the pixels in the screen. If arguments are not passed, then the buffer is filled with the standard black color and the whitespace symbol.

screen.drawText(int x, int y, 24-bit int color, string text, float [0.0; 1.0] transparency)

Draws the text with given color. The background color under text will remain the same. It is also possible to set the transparency of the text.

screen.drawImage(int x, int y, table picture)

Draws image that was loaded earlier via image.load(...) method. The alpha channel of image is also supported.

screen.drawLine(int x1, int y1, int x2, int y2, 24-bit int background, 24-bit int foreground, string symbol)

Draws a line with specified pixel data from first point to second.

screen.drawEllipse(int centerX, int centerY, int radiusX, int radiusY, 24-bit int foreground, string symbol)

Draws an ellipse with specified pixel data.

screen.blur(int x, int y, int width, int height, int radius, [ 24-bit int blendColor, *float [0.0; 1.0] transparency ])

Applies blur effect with box kernel to given rectangular region with given radius. Optionally, a blend color with transparency can be applied after blurring to create "glassy panel effect".

Note that this method is extremely slow, requires lot of RAM and it should be used only on high-end computers (servers with 4x Tier3 RAM moudles are preferred)

Semi-pixel rendering methods

All semi-pixel methods allow to avoid the effect of doubling pixel height of the console pseudographics using special symbols like "▄". In this case, the transmitted coordinates along the Y axis must belong to the interval [1; screen.height * 2].

screen.semiPixelSet(int x, int y, 24-bit int color)

Sets semi-pixel value in specified coordinates.

screen.drawSemiPixelRectangle(int x, int y, int width, int height, 24-bit int color)

Draws semi-pixel rectangle.

screen.drawSemiPixelLine(int x1, int y1, int x2, int y2, 24-bit int color)

Rasterize a semi-pixel line witch specified color.

screen.drawSemiPixelEllipse(int centerX, int centerY, int radiusX, int radiusY, 24-bit int color)

Draws semi-pixel ellipse with specified color.

screen.drawSemiPixelCurve(table points, 24-bit int color, float accuracy)

Draws the Bezier Curve with specified color. The given points table structure must be like following:

{{x = 32, y = 2}, {x = 2, y = 2}, {x = 2, y = 98}}

The accuracy argument means drawing iteration step. Less accuracy means more realistic curve.

Auxiliary methods

The following methods are used by the library itself or by applications that require maximum performance and calculate the pixel data of the buffer manually. In most cases, they do not come in handy, but they are listed just in case.

screen.flush([int width, int height])

Sets screen buffer resolution to the specified one and fill it with black pixels and whitespace symbol. Unlike screen.setResolution() it does not change the current resolution of the GPU. If optional arguments are not specified, then the buffer size becomes equivalent to the current GPU resolution.

screen.getIndex(int x, int y): int index

Converts screen coordinates to the screen buffer index. For example, a 2x1 pixel has a buffer index equals 4, and a pixel of 3x1 has a buffer index equals 7.

screen.rawSet(int index, 24-bit int background, 24-bit int foreground, string symbol)

Sets specified data values to pixel with specified index.

screen.rawGet(int index): 24-bit int background, 24-bit int foreground, string symbol

Returns data values of pixel with specified index.

screen.getCurrentFrameTables(): table currentFrameBackgrounds, table currentFrameForegrounds, table currentFrameSymbols

Returns current screen buffer frames (that is displayed on screen) that contains pixel data. This method is used in rare cases where maximum performance and manual buffer changing pixel-by-pixel is required.

screen.getNewFrameTables(): table newFrameBackgrounds, table newFrameForegrounds, table newFrameSymbols

Works like screen.getCurrentFrameTables(), but returns frames that user is changing in realtime (before calling screen.update())

Practical example

-- Import required libraries
local screen = require("screen")
local image = require("image")

--------------------------------------------------------------------------------

-- Load image from file and draw it to screen buffer
screen.drawImage(1, 1, image.load("/MineOS/Pictures/Raspberry.pic"))
-- Fill buffer with black color and transparency set to 0.6 to make image "darker"
screen.clear(0x0, 0.6)

-- Draw 10 rectangles filled with random color
local x, y, xStep, yStep = 2, 2, 4, 2
for i = 1, 10 do
	screen.drawRectangle(x, y, 6, 3, math.random(0x0, 0xFFFFFF), 0x0, " ")
	x, y = x + xStep, y + yStep
end

-- Draw yellow semi-pixel ellipse
screen.drawSemiPixelEllipse(22, 22, 10, 10, 0xFFDB40)
-- Draw yellow semi-pixel line
screen.drawSemiPixelLine(2, 36, 35, 3, 0xFFFFFF)
-- Draw green bezier curve with accuracy set to 0.01
screen.drawSemiPixelCurve(
	{
		{ x = 2, y = 63},
		{ x = 63, y = 63},
		{ x = 63, y = 2}
	},
	0x44FF44,
	0.01
)

-- Draw changed pixels on screen
screen.update()

Result:

Clone this wiki locally