Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use canvas in emscripten

I am working on a webassembly program. I can set the canvas size using emscripten_set_canvas_size (althrough I read that I need to switch to a new API as this one will be depreciated)...

But my question is: How do I set the pixels on said canvas? My program generates an array of 32 bit color for the canvas and I need to transfert said bits from my internal memory to the canvas. How can I do this?

Alternatively, if I can just get the memory pointer to the canvas's data, I can write directly in said memory...

I would like, if possible, to do this without having to ressort to any other API (GL, SDL...) all I need is to transfert the colors to the canvas as fast as possible... Nothing more than that.

Ideally, I am looking for a short example program along the lines of:

#include <...>
  uint32_t screen[320*320];
 static void main_loop()
 {
   memset(screen, 0, 320*320*4); // Clear screen
   for (int x=0; x<320; x++)
     for (int y=0; y<320; y++)
       screen[320*(x|y) + (x&y)]= 0xffffff; // set pixel(x or y, x and y) to white... (will draw a serpinsky triangle)
   Copy_ToCanvas(screen);  // THIS IS THE FUNCTION THAT I AM LOOKING FOR
 }

int main()
{
  emscripten_set_canvas_size(320, 320);
  emscripten_set_main_loop(main_loop, 100, true);
  return 0;
} 

Thanks, Cyrille

like image 818
user3256556 Avatar asked Jun 12 '18 14:06

user3256556


2 Answers

Without SDL, low level code is needed.

void Copy_ToCanvas(uint32_t* ptr, int w, int h) {
  EM_ASM_({
      let data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
      let context = Module['canvas'].getContext('2d');
      let imageData = context.getImageData(0, 0, $1, $2);
      imageData.data.set(data);
      context.putImageData(imageData, 0, 0);
    }, ptr, w, h);
}

static void main_loop()
{
  memset(screen, 0, 320*320*4); // Clear screen
  for (int x=0; x<320; x++)
    for (int y=0; y<320; y++)
      screen[320*(x|y) + (x&y)]= 0xffffffff; // set pixel(x or y, x and y) to white... (will draw a serpinsky triangle)
  Copy_ToCanvas(screen, 320, 320);
}
like image 107
zakki Avatar answered Oct 10 '22 03:10

zakki


Just a note, the useful answer above won't display correctly, as the memset() call doesn't clear the browser screen to black. Apparently, you have to explicitly set the alpha channel. So instead of memset(),

    int screen[320*320],idx=0;
    for (int x=0; x<320*320; x++)
        screen[idx++] = 0xff000000;
like image 33
rshaw Avatar answered Oct 10 '22 05:10

rshaw