Skip to content

Commit b13f681

Browse files
committed
Add basic framebuffer support to the Emscripten port
Sends contents to the JS side (at least when the OpenFirmware boot device screen calls sys_gui_event).
1 parent 4d95058 commit b13f681

4 files changed

Lines changed: 161 additions & 14 deletions

File tree

src/system/ui/js/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ AUTOMAKE_OPTIONS = foreign
22

33
noinst_LIBRARIES = libui.a
44

5-
libui_a_SOURCES = gui.cc
5+
libui_a_SOURCES = gui.cc sysdisplay.cc
66

77
AM_CPPFLAGS = -I ../../..

src/system/ui/js/gui.cc

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
11
#include "system/display.h"
22
#include "system/ui/gui.h"
33

4-
void sys_gui_init()
5-
{
6-
}
4+
#include "sysjs.h"
5+
6+
void sys_gui_init() {}
77

8-
bool sys_gui_open_file_dialog(String &ret, const String &title, const String &filespec, const String &filespecname, const String &home, bool existing)
9-
{
8+
bool sys_gui_open_file_dialog(String &ret, const String &title, const String &filespec, const String &filespecname, const String &home, bool existing) {
9+
printf("sys_gui_open_file_dialog called with title: %s, filespec: %s, filespecname: %s, home: %s, existing: %d\n", title.contentChar(), filespec.contentChar(), filespecname.contentChar(), home.contentChar(), existing);
10+
return false; // Placeholder return value
1011
}
1112

12-
int sys_gui_messagebox(const String &title, const String &text, int buttons)
13-
{
13+
int sys_gui_messagebox(const String &title, const String &text, int buttons) {
14+
printf("sys_gui_messagebox called with title: %s, text: %s, buttons: %d\n", title.contentChar(), text.contentChar(), buttons);
15+
return 0; // Placeholder return value
1416
}
1517

16-
void sys_gui_event()
17-
{
18+
void sys_gui_event() {
19+
static_cast<JSSystemDisplay*>(gDisplay)->blit();
1820
}
1921

20-
void initUI(const char *title, const DisplayCharacteristics &aCharacteristics, int redraw_ms, const KeyboardCharacteristics &keyCharacteristics, bool fullscreen)
21-
{
22+
void initUI(const char *title, const DisplayCharacteristics &aCharacteristics, int redraw_ms, const KeyboardCharacteristics &keyCharacteristics, bool fullscreen) {
23+
gDisplay = allocSystemDisplay(title, aCharacteristics, redraw_ms);
24+
// gMouse = allocSystemMouse();
25+
// gKeyboard = allocSystemKeyboard();
2226

2327
}
2428

25-
void doneUI()
26-
{
29+
void doneUI() {
30+
printf("doneUI\n");
2731
}
2832

src/system/ui/js/sysdisplay.cc

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include <cstring>
2+
#include <emscripten.h>
3+
#include <memory>
4+
5+
#include "sysjs.h"
6+
7+
JSSystemDisplay::JSSystemDisplay(
8+
const DisplayCharacteristics &chr, int redraw_ms)
9+
: SystemDisplay(chr, redraw_ms) {
10+
mClientChar = chr;
11+
int frameBufferSize =
12+
mClientChar.width * mClientChar.height * mClientChar.bytesPerPixel;
13+
gFrameBuffer = (byte*)malloc(frameBufferSize);
14+
memset(gFrameBuffer, 0, frameBufferSize);
15+
16+
jsFrameBufferSize = mClientChar.width * mClientChar.height * 4;
17+
jsFrameBuffer.reset(new byte[jsFrameBufferSize]);
18+
19+
damageFrameBufferAll();
20+
21+
EM_ASM_({ workerApi.didOpenVideo($0, $1); }, mClientChar.width, mClientChar.height);
22+
}
23+
24+
void JSSystemDisplay::blit() {
25+
// See comments in SDLSystemDisplay::displayShow for the need for the +3.
26+
if (gDamageAreaFirstAddr > gDamageAreaLastAddr+3) {
27+
EM_ASM({ workerApi.blit(0, 0); });
28+
return;
29+
}
30+
31+
// TODO: take into account damage area and only blit that part.
32+
healFrameBuffer();
33+
34+
byte *jsFrameBuffer = this->jsFrameBuffer.get();
35+
int frameBufferSize =
36+
mClientChar.width * mClientChar.height * mClientChar.bytesPerPixel;
37+
38+
// Invert endianess and generate the RGBA that the JS side expects.
39+
if (mClientChar.bytesPerPixel == 2) {
40+
for (int src = 0, dst = 0; src < frameBufferSize; src += 2, dst += 4) {
41+
uint16 pixel555 = gFrameBuffer[src + 1] | (gFrameBuffer[src] << 8);
42+
uint8 red5 = (pixel555 & 0x7c00) >> 10;
43+
uint8 green5 = (pixel555 & 0x3e0) >> 5;
44+
uint8 blue5 = (pixel555 & 0x1f);
45+
46+
uint8 red8 = (red5 * 255 + 15) / 31;
47+
uint8 green8 = (green5 * 255 + 15) / 31;
48+
uint8 blue8 = (blue5 * 255 + 15) / 31;
49+
50+
jsFrameBuffer[dst + 0] = red8;
51+
jsFrameBuffer[dst + 1] = green8;
52+
jsFrameBuffer[dst + 2] = blue8;
53+
jsFrameBuffer[dst + 3] = 0xff;
54+
}
55+
} else {
56+
// Offset by 1 to go from ARGB to RGBA and ensure that the alpha is set,
57+
// the Mac defaults to it being 0, which the browser renders as
58+
// transparent.
59+
uint32 *jsFrameBuffer32 = reinterpret_cast<uint32 *>(jsFrameBuffer);
60+
byte *jsFrameBufferAlpha = jsFrameBuffer + 3;
61+
uint32 *frameBuffer32 = reinterpret_cast<uint32 *>(gFrameBuffer + 1);
62+
uint32 frameBufferSize32 = frameBufferSize / 4;
63+
for (int i = 0; i < frameBufferSize32; i++) {
64+
*jsFrameBuffer32++ = *frameBuffer32++;
65+
*jsFrameBufferAlpha = 0xFF;
66+
jsFrameBufferAlpha += 4;
67+
}
68+
}
69+
70+
EM_ASM_({ workerApi.blit($0, $1); }, jsFrameBuffer, jsFrameBufferSize);
71+
}
72+
73+
void JSSystemDisplay::finishMenu() {
74+
}
75+
76+
void JSSystemDisplay::updateTitle() {
77+
}
78+
79+
void JSSystemDisplay::displayShow() {
80+
blit();
81+
}
82+
83+
void JSSystemDisplay::convertCharacteristicsToHost(DisplayCharacteristics &aHostChar, const DisplayCharacteristics &aClientChar) {
84+
aHostChar = aClientChar;
85+
aHostChar.bytesPerPixel = 4;
86+
aHostChar.scanLineLength = aHostChar.bytesPerPixel * aHostChar.width;
87+
}
88+
89+
bool JSSystemDisplay::changeResolution(const DisplayCharacteristics &aCharacteristics) {
90+
mClientChar = aCharacteristics;
91+
gFrameBuffer = (byte*)realloc(
92+
gFrameBuffer,
93+
mClientChar.width * mClientChar.height * mClientChar.bytesPerPixel);
94+
95+
jsFrameBufferSize = mClientChar.width * mClientChar.height * 4;
96+
jsFrameBuffer.reset(new byte[jsFrameBufferSize]);
97+
98+
EM_ASM_({ workerApi.didOpenVideo($0, $1); }, mClientChar.width, mClientChar.height);
99+
damageFrameBufferAll();
100+
return true;
101+
}
102+
103+
void JSSystemDisplay::getHostCharacteristics(Container &modes) {
104+
DisplayCharacteristics *hostChar = new DisplayCharacteristics();
105+
convertCharacteristicsToHost(*hostChar, mClientChar);
106+
modes.insert(hostChar);
107+
}
108+
109+
void JSSystemDisplay::setMouseGrab(bool enable) {
110+
::printf("JSSystemDisplay::setMouseGrab\n");
111+
}
112+
113+
SystemDisplay *allocSystemDisplay(const char *title, const DisplayCharacteristics &chr, int redraw_ms) {
114+
return new JSSystemDisplay(chr, redraw_ms);
115+
}

src/system/ui/js/sysjs.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef __SYSJS_H__
2+
#define __SYSJS_H__
3+
4+
#include <memory>
5+
6+
#include "system/display.h"
7+
8+
class JSSystemDisplay: public SystemDisplay {
9+
public:
10+
JSSystemDisplay(const DisplayCharacteristics &chr, int redraw_ms);
11+
12+
void blit();
13+
14+
virtual void finishMenu();
15+
virtual void updateTitle();
16+
virtual void displayShow();
17+
virtual void convertCharacteristicsToHost(DisplayCharacteristics &aHostChar, const DisplayCharacteristics &aClientChar);
18+
virtual bool changeResolution(const DisplayCharacteristics &aCharacteristics);
19+
virtual void getHostCharacteristics(Container &modes);
20+
virtual void setMouseGrab(bool enable);
21+
private:
22+
std::unique_ptr<byte[]> jsFrameBuffer;
23+
int jsFrameBufferSize;
24+
};
25+
26+
SystemDisplay *allocSystemDisplay(const char *title, const DisplayCharacteristics &chr, int redraw_ms);
27+
28+
#endif

0 commit comments

Comments
 (0)