vnc: structure improvements, don't use SDL unless requested

This commit is contained in:
Lephenixnoir 2023-03-26 21:40:11 +02:00
parent b6c782666c
commit 74a7f05e9d
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
1 changed files with 79 additions and 44 deletions

View File

@ -7,6 +7,10 @@
#include <assert.h>
#include <stdbool.h>
/* Size of the calculator display */
#define CALC_WIDTH 396
#define CALC_HEIGHT 224
/* Application globals */
struct app {
/* RFB/VNC client to get framebuffers from VNC server */
@ -56,26 +60,29 @@ static void cleanup(void)
new 16-bit framebuffer to the calculator. */
static void fb_update(rfbClient *client)
{
uint32_t *fb = (void *)client->frameBuffer;
if(app.display_sdl) {
/* Very crude assumption about the SDL surface format and pitch */
memcpy(app.surface->pixels, fb, CALC_WIDTH * CALC_HEIGHT * 4);
SDL_UpdateWindowSurface(app.window);
}
if(app.display_calc && app.calc && app.fb16_be) {
uint8_t *buffer = (void *)app.surface->pixels;
for(int y = 0; y < app.surface->h; y++)
for(int x = 0; x < app.surface->w; x++) {
int offset = y * app.surface->pitch + 4 * x;
int R = buffer[offset + 2];
int G = buffer[offset + 1];
int B = buffer[offset + 0];
if(app.display_calc && app.calc && app.fb16_be) {
for(int y = 0; y < CALC_HEIGHT; y++)
for(int x = 0; x < CALC_WIDTH; x++) {
uint32_t color = fb[CALC_WIDTH * y + x];
int R = (color >> 16) & 0xff;
int G = (color >> 8) & 0xff;
int B = (color & 0xff);
/* Conversion to RGB565 */
int c = ((R & 0xf8) << 8) | ((G & 0xfc) << 3) | ((B & 0xf8) >> 3);
app.fb16_be[396*y + x] = (c >> 8) | (c << 8);
app.fb16_be[CALC_WIDTH * y + x] = (c >> 8) | (c << 8);
}
fxlink_device_start_bulk_OUT(app.calc,
"cgvm", "fb", app.fb16_be, 396*224*2, false);
"cgvm", "fb", app.fb16_be, CALC_WIDTH * CALC_HEIGHT * 2, false);
}
}
@ -175,6 +182,40 @@ static void usage(int rc)
exit(rc);
}
static bool init_rfb_client(rfbClient **client, char *server,
uint32_t *fb)
{
int argc = 4;
char *argv[] = { "cgvm_vnc", "-encodings", "raw", server, NULL };
*client = rfbGetClient(8, 3, 4);
if(!*client) {
fprintf(stderr, "rfbGetClient failed\n");
return false;
}
(*client)->FinishedFrameBufferUpdate = fb_update;
(*client)->width = CALC_WIDTH;
(*client)->height = CALC_HEIGHT;
(*client)->frameBuffer = (void *)fb;
/* Standard 32-bit xRGB */
(*client)->format.bitsPerPixel = 32;
(*client)->format.redShift = 16;
(*client)->format.greenShift = 8;
(*client)->format.blueShift = 0;
(*client)->format.redMax = 0xff;
(*client)->format.greenMax = 0xff;
(*client)->format.blueMax = 0xff;
SetFormatAndEncodings(*client);
if(!rfbInitClient(*client, &argc, argv)) {
fprintf(stderr, "rfbInitClient failed\n");
*client = NULL;
return false;
}
return true;
}
int main(int argc, char **argv)
{
for(int i = 1; i < argc; i++) {
@ -195,39 +236,31 @@ int main(int argc, char **argv)
usage(1);
atexit(cleanup);
/* TODO: Sometimes when calc disconnects process loops and is unkillable */
/* TODO: Sometimes when the calculator disconnects the wait on the RFB
server loops and can't be killed by SIGINT or SIGTERM? */
signal(SIGINT, exit);
/* Create the SDL window regarless of whether display_sdl is set, since we
use its surface as RFB framebuffer */
/* TODO: Use an external framebuffer, don't use SDL unless enabled */
SDL_Init(SDL_INIT_VIDEO);
app.window = SDL_CreateWindow("CG Virtual Monitor test VNC client",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 396, 224, 0);
app.surface = SDL_GetWindowSurface(app.window);
assert(app.surface->format->BytesPerPixel == 4);
//---
// Initialise the RFB client
//---
app.client = rfbGetClient(8, 3, 4);
app.client->FinishedFrameBufferUpdate = fb_update;
app.client->width = 396;
app.client->height = 224;
app.client->frameBuffer = app.surface->pixels;
uint32_t *fb = malloc(CALC_WIDTH * CALC_HEIGHT * 4);
assert(fb && "out of memory");
app.client->format.bitsPerPixel=32;
app.client->format.redShift=app.surface->format->Rshift;
app.client->format.greenShift=app.surface->format->Gshift;
app.client->format.blueShift=app.surface->format->Bshift;
app.client->format.redMax=app.surface->format->Rmask>>app.client->format.redShift;
app.client->format.greenMax=app.surface->format->Gmask>>app.client->format.greenShift;
app.client->format.blueMax=app.surface->format->Bmask>>app.client->format.blueShift;
SetFormatAndEncodings(app.client);
int _argc = 4;
char *_argv[] = { argv[0], "-encodings", "raw", "127.0.0.1", NULL };
if(!rfbInitClient(app.client, &_argc, _argv)) {
fprintf(stderr, "rfbInitClient failed\n");
app.client = NULL;
if(!init_rfb_client(&app.client, "127.0.0.1", fb))
return 1;
/* Create the SDL window if SDL display is requested */
if(app.display_sdl) {
SDL_Init(SDL_INIT_VIDEO);
app.window = SDL_CreateWindow("CG Virtual Monitor test VNC client",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
CALC_WIDTH, CALC_HEIGHT, 0);
app.surface = SDL_GetWindowSurface(app.window);
/* Surely this is gonna be the default everywhere, like surely */
assert(app.surface->format->BytesPerPixel == 4);
assert(app.surface->format->format == SDL_PIXELFORMAT_RGB888);
}
if(app.display_calc) {
@ -241,15 +274,17 @@ int main(int argc, char **argv)
/* Track the list of connected calculators. */
fxlink_device_list_track(&app.devices, app.libusb_ctx);
app.fb16_be = malloc(396 * 224 * 2);
app.fb16_be = malloc(CALC_WIDTH * CALC_HEIGHT * 2);
}
while(1) {
SDL_Event e;
while(SDL_PollEvent(&e)) {
if(e.type == SDL_QUIT) {
fprintf(stderr, "SDL_QUIT: Exiting...\n");
exit(0);
if(app.display_sdl) {
SDL_Event e;
while(SDL_PollEvent(&e)) {
if(e.type == SDL_QUIT) {
fprintf(stderr, "SDL_QUIT: Exiting...\n");
exit(0);
}
}
}