Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for copy-screen-to-bitmap #153

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ board_build.f_cpu = 240000000L
board_build.f_flash = 80000000L
framework = arduino
lib_deps =
https://github.com/avalonbits/vdp-gl.git#1.0.3
https://github.com/AgonConsole8/vdp-gl.git#copy-to-bitmap
fbiego/ESP32Time@^2.0.0
build_flags =
-DBOARD_HAS_PSRAM
Expand Down
2 changes: 1 addition & 1 deletion video/vdu_buffered.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ void VDUStreamProcessor::bufferClear(uint16_t bufferId) {
// This is used for creating buffers to redirect output to
//
std::shared_ptr<WritableBufferStream> VDUStreamProcessor::bufferCreate(uint16_t bufferId, uint32_t size) {
if (bufferId == 0 || bufferId == 65535) {
if (bufferId == 65535) {
debug_log("bufferCreate: bufferId %d is reserved\n\r", bufferId);
return nullptr;
}
Expand Down
138 changes: 96 additions & 42 deletions video/vdu_sprites.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _VDU_SPRITES_H_

#include <fabgl.h>
#include <cmath>

#include "buffers.h"
#include "graphics.h"
Expand All @@ -10,7 +11,7 @@

// Sprite Engine, VDU command handler
//
void VDUStreamProcessor::vdu_sys_sprites(void) {
void VDUStreamProcessor::vdu_sys_sprites() {
auto cmd = readByte_t();

switch (cmd) {
Expand All @@ -22,20 +23,37 @@ void VDUStreamProcessor::vdu_sys_sprites(void) {
}
} break;

case 1: // Send bitmap data
case 2: { // Define bitmap in single color
case 1: { // Create new bitmap from stream (RGBA8888) or screen (Native, RGB222)
auto rw = readWord_t(); if (rw == -1) return;
auto rh = readWord_t(); if (rh == -1) return;

if (rw == 0 && rh == 0) {
// TODO support defining bitmap from screen area
// as per Acorn GXR
// which defines area with last two graphics move commands
debug_log("vdu_sys_sprites: bitmap %d - zero size\n\r", getCurrentBitmapId());
if (rh == 0) {
if (rw <= 255) {
// capture bitmap from screen as per GXR
// area defined from last two graphics move commands
// bitmap ID sent in first rw byte
createBitmapFromScreen(rw + BUFFERED_BITMAP_BASEID);
} else {
// invalid bitmap size definition for sending bitmap data stream
debug_log("vdu_sys_sprites: bitmap %d - zero size\n\r", getCurrentBitmapId());
}
return;
}

receiveBitmap(cmd, rw, rh);
receiveBitmap(getCurrentBitmapId(), rw, rh);
} break;

case 2: { // Define bitmap in single color
auto rw = readWord_t(); if (rw == -1) return;
auto rh = readWord_t(); if (rh == -1) return;
uint32_t color;
auto remaining = readIntoBuffer((uint8_t *)&color, sizeof(uint32_t));
if (remaining > 0) {
debug_log("vdu_sys_sprites: failed to receive color data\n\r");
return;
}

createEmptyBitmap(getCurrentBitmapId(), rw, rh, color);
} break;

case 3: { // Draw bitmap to screen (x,y)
Expand Down Expand Up @@ -148,8 +166,14 @@ void VDUStreamProcessor::vdu_sys_sprites(void) {
case 0x21: { // Create bitmap from buffer
auto width = readWord_t(); if (width == -1) return;
auto height = readWord_t(); if (height == -1) return;
auto format = readByte_t(); if (format == -1) return;
createBitmapFromBuffer(getCurrentBitmapId(), format, width, height);
if (height == 0) {
// capture bitmap from the screen, as per GXR
// buffer ID sent in "width" word, format byte not required/ignored
createBitmapFromScreen(width);
} else {
auto format = readByte_t(); if (format == -1) return;
createBitmapFromBuffer(getCurrentBitmapId(), format, width, height);
}
} break;

case 0x26: { // add sprite frame for bitmap (long ID)
Expand All @@ -174,41 +198,67 @@ void VDUStreamProcessor::vdu_sys_sprites(void) {
}
}

void VDUStreamProcessor::receiveBitmap(uint8_t cmd, uint16_t width, uint16_t height) {
auto bufferId = getCurrentBitmapId();

void VDUStreamProcessor::receiveBitmap(uint16_t bufferId, uint16_t width, uint16_t height) {
// clear the buffer
bufferClear(bufferId);
// receive the data
if (bufferWrite(bufferId, sizeof(uint32_t) * width * height) != 0) {
// timed out, or couldn't allocate buffer - so abort
return;
}
// create RGBA8888 bitmap from buffer
createBitmapFromBuffer(bufferId, 0, width, height);
}

void VDUStreamProcessor::createBitmapFromScreen(uint16_t bufferId) {
bufferClear(bufferId);
// get screen rectangle from last two graphics cursor positions
auto x1 = p1.X;
auto y1 = p1.Y;
auto x2 = p2.X;
auto y2 = p2.Y;
auto width = x2 - x1;
auto height = y2 - y1;
// normalize to positive values
if (width < 0) {
width = -width;
x1 = x2;
}
if (height < 0) {
height = -height;
y1 = y2;
}
auto size = width * height;
if (size == 0) {
debug_log("vdu_sys_sprites: bitmap %d - zero size\n\r", bufferId);
return;
}

uint32_t size = sizeof(uint32_t) * width * height;

if (cmd == 1) {
// receive the data
if (bufferWrite(bufferId, size) != 0) {
// timed out, or couldn't allocate buffer - so abort
return;
}
// create RGBA8888 bitmap from buffer
createBitmapFromBuffer(bufferId, 0, width, height);
} else if (cmd == 2) {
uint32_t color;
auto remaining = readIntoBuffer((uint8_t *)&color, sizeof(uint32_t));
if (remaining > 0) {
debug_log("vdu_sys_sprites: failed to receive color data\n\r");
return;
}
// create a new buffer of appropriate size
auto buffer = bufferCreate(bufferId, size);
if (!buffer) {
debug_log("vdu_sys_sprites: failed to create buffer\n\r");
return;
}
auto dataptr = (uint32_t *)buffer->getBuffer();
for (auto n = 0; n < width*height; n++) dataptr[n] = color;
// create RGBA8888 bitmap from buffer
createBitmapFromBuffer(bufferId, 0, width, height);
// create a new buffer of appropriate size, and set as a native format bitmap
auto buffer = bufferCreate(bufferId, size);
if (!buffer) {
debug_log("vdu_sys_sprites: failed to create buffer\n\r");
return;
}
return;
createBitmapFromBuffer(bufferId, 3, width, height);
// Copy screen area to buffer
canvas->copyToBitmap(x1, y1, getBitmap(bufferId).get());
}

void VDUStreamProcessor::createEmptyBitmap(uint16_t bufferId, uint16_t width, uint16_t height, uint32_t color) {
bufferClear(bufferId);

// create a new buffer of appropriate size
uint32_t size = width * height;
auto buffer = bufferCreate(bufferId, sizeof(uint32_t) * size);
if (!buffer) {
debug_log("vdu_sys_sprites: failed to create buffer\n\r");
return;
}
auto dataptr = (uint32_t *)buffer->getBuffer();
for (auto n = 0; n < size; n++) dataptr[n] = color;
// create RGBA8888 bitmap from buffer
createBitmapFromBuffer(bufferId, 0, width, height);
}

void VDUStreamProcessor::createBitmapFromBuffer(uint16_t bufferId, uint8_t format, uint16_t width, uint16_t height) {
Expand Down Expand Up @@ -242,6 +292,10 @@ void VDUStreamProcessor::createBitmapFromBuffer(uint16_t bufferId, uint8_t forma
pixelFormat = PixelFormat::Mask;
bytesPerPixel = 1/8;
break;
case 3: // Native
pixelFormat = PixelFormat::Native;
bytesPerPixel = 1.;
break;
default:
pixelFormat = PixelFormat::RGBA8888;
bytesPerPixel = 4.;
Expand Down
6 changes: 4 additions & 2 deletions video/vdu_stream_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ class VDUStreamProcessor {
void setVolumeEnvelope(uint8_t channel, uint8_t type);
void setFrequencyEnvelope(uint8_t channel, uint8_t type);

void vdu_sys_sprites(void);
void receiveBitmap(uint8_t cmd, uint16_t width, uint16_t height);
void vdu_sys_sprites();
void receiveBitmap(uint16_t bufferId, uint16_t width, uint16_t height);
void createBitmapFromScreen(uint16_t bufferId);
void createEmptyBitmap(uint16_t bufferId, uint16_t width, uint16_t height, uint32_t color);
void createBitmapFromBuffer(uint16_t bufferId, uint8_t format, uint16_t width, uint16_t height);

void vdu_sys_hexload(void);
Expand Down