reicast, websockets & opengl (es) streaming
For some reason, I was always fascinated with the idea of dreamcast on the cloud. The initial idea was to use amazon g2 instances + the grid api, but it felt like too much work for today, and my debit card was empty too.
Since reicast already has a websocket server build in (for some future debugger/profiler UI), using websockets seemed like a great idea.
So…
Idea 1 - glreadpixels + websocket + libjpeg turbo + img tag
This one failed pretty fast. libjpeg turbo is quite big and didn’t seem very cooperative on getting included under my makefile. Plus, I had to make it work with Visual Studio, and meh.
Idea 2 - glreadpixels + websocket + bmp + img tag
Right. Streaming over localhost -for now- so bmp it is. Some quick googling directed me to a fine post which had clean, working bmp generation code.
The magic: in gles.cpp, global scope:
//yes, globals are evil for your soul.
int bmp_filesize;
u8* bmp_pdata;
In gl_swap(), before eglSwapBuffers:
{
int w = screen_width;
int h = screen_height;
int filesize = bmp_filesize = 54 + 3*w*h;
if (!bmp_pdata)
bmp_pdata = new u8[14 + 40 + filesize];
u8* img = bmp_pdata + 14 + 40;
glReadPixels(0,0,screen_width,screen_height,GL_RGB, GL_UNSIGNED_BYTE,img);
// ... BMP header generation ...
}
Woohoo, it works! It stopped after 50 frames or so though. Then I realised some connection-limit code had to be commented out. Good.
This resulted in reicast crashing as soon as complex bitmaps got rendered. Complex images get deflated to more than 64K, and that was the problem. So I disabled compression.
Yay. Dreamcast bios menu! The swapped colors are to be expected (bmp/rgb vs ogl/bgr), but otherwise it worked. For a minute. Then memory leaks from blob URLs killed it. Another dead end.
Idea 3 - glreadpixels + websocket + webgl
Thinking of another way to render the images, webgl poped into mind. It must have glTexture2D. It must support arraybuffers. Right? And .bmps are just bitmaps if you skip the headers.
socket_di.onmessage = function got_packet(msg) {
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGB,
512, 512, 0,
gl.RGB, gl.UNSIGNED_BYTE,
new Uint8Array(msg.data, 54)
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
};
Works! Rotating dreamcast cube over localhost. Must be useful for something. Maybe for that pvr 3d debugger idea..
I’ll cleanup the code, make it properly handle NPOTs, get rid of the rotation and it should end up in the reicast git somewhere next week.