Livt packages
Eccelerators.Matrix
Version 1.0.1
Reusable RGB matrix drawing, color conversion, animation pacing, and HUB75 display components for Livt.
Published files (48)
- Hub75
- BrightnessColorConverter.lvt
- ColorGain.lvt
- ColorPipeline.lvt
- GammaColorConverter.lvt
- IColorConverter.lvt
- IdentityColorConverter.lvt
- IMatrixBitmap.lvt
- IMatrixDisplay.lvt
- IMatrixLayout.lvt
- IMatrixRenderer.lvt
- MatrixColor.lvt
- MatrixFramePacer.lvt
- MatrixPainter.lvt
- MatrixPictureSequence.lvt
- MatrixRenderer.lvt
- WhiteBalanceColorConverter.lvt
src/MatrixRenderer.lvt
namespace Eccelerators.Matrix
/**
* Render complete RGB888 images with optional context-derived frame deadlines.
* Owns a pacer; borrows display, bitmap and converter only during Render.
* One serialized client shares the context. Zero FRAME_TIME disables pacing;
* missed deadlines coalesce and rendering time limits the achievable frame rate.
*/
component MatrixRenderer<FRAME_TIME: Time = 0ns> : IMatrixRenderer
{
static assert FRAME_TIME >= 0ns, "Frame time must not be negative"
// Owned deadline source, independent of the scheduled drawing operation.
pacer: MatrixFramePacer<FRAME_TIME>
/**
* Construct the pacer in the inherited context; deadlines begin at construction.
*/
new()
{
pacer = new MatrixFramePacer<FRAME_TIME>()
}
/**
* Clear to black, clip and convert source pixels, wait for a deadline when
* enabled, and return Present's result. No source frames are advanced here.
* Use IdentityColorConverter to preserve source colors.
*/
override fn Render(display: IMatrixDisplay, bitmap: IMatrixBitmap, converter: IColorConverter) bool
{
var width = display.GetWidth()
var height = display.GetHeight()
var imageWidth = bitmap.GetWidth()
var imageHeight = bitmap.GetHeight()
display.Clear(0 as logic[24])
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
if (x < imageWidth && y < imageHeight) {
var pixel = bitmap.GetPixel(x, y)
var converted = converter.Convert(pixel)
display.SetPixel(x, y, converted)
}
}
}
static if (FRAME_TIME > 0ns) {
pacer.WaitNext()
}
return display.Present()
}
/**
* Repeat the source from the origin across the logical canvas. Return the
* display's presentation result; an empty source produces a black image.
*/
override fn RenderTiled(display: IMatrixDisplay, bitmap: IMatrixBitmap, converter: IColorConverter) bool
{
var width = display.GetWidth()
var height = display.GetHeight()
var imageWidth = bitmap.GetWidth()
var imageHeight = bitmap.GetHeight()
display.Clear(0 as logic[24])
if (imageWidth > 0 && imageHeight > 0) {
var sourceY = 0
for (var y = 0; y < height; y++) {
var sourceX = 0
for (var x = 0; x < width; x++) {
var pixel = bitmap.GetPixel(sourceX, sourceY)
var converted = converter.Convert(pixel)
display.SetPixel(x, y, converted)
if (sourceX == imageWidth - 1) {
sourceX = 0
} else {
sourceX++
}
}
if (sourceY == imageHeight - 1) {
sourceY = 0
} else {
sourceY++
}
}
}
static if (FRAME_TIME > 0ns) {
pacer.WaitNext()
}
return display.Present()
}
/**
* Render into one logical panel tile, clipping the source to that tile and
* leaving other tiles black. An invalid tile produces a black image.
*/
override fn RenderPanel(display: IMatrixDisplay, layout: IMatrixLayout, panelX: int, panelY: int,
bitmap: IMatrixBitmap, converter: IColorConverter) bool
{
var panelWidth = layout.GetPanelWidth()
var panelHeight = layout.GetPanelHeight()
var imageWidth = bitmap.GetWidth()
var imageHeight = bitmap.GetHeight()
display.Clear(0 as logic[24])
if (panelX >= 0 && panelX < layout.GetPanelColumns() && panelY >= 0 && panelY < layout.GetPanelRows()) {
for (var y = 0; y < panelHeight; y++) {
for (var x = 0; x < panelWidth; x++) {
if (x < imageWidth && y < imageHeight) {
var pixel = bitmap.GetPixel(x, y)
var converted = converter.Convert(pixel)
display.SetPixel(panelX * panelWidth + x, panelY * panelHeight + y, converted)
}
}
}
}
static if (FRAME_TIME > 0ns) {
pacer.WaitNext()
}
return display.Present()
}
}