ref: f343830a425bb978a6e78f50232f6ca947af72c2
parent: d85a58ed0b40a8519a18aa828b8b30804d1f3e99
author: phil9 <telephil9@gmail.com>
date: Sun Dec 4 11:39:10 EST 2022
implement direct pixel access api (pixels, loadPixels(), updatePixels())
--- a/a.h
+++ b/a.h
@@ -8,6 +8,14 @@
#include <lauxlib.h>
#include <lualib.h>
+typedef struct Pixels Pixels;
+
+struct Pixels
+{
+ int ndata;
+ uchar data[1];
+};
+
void lset(lua_State*, const char*, int);
void resize(lua_State*, int, int);
@@ -16,12 +24,17 @@
void reset(void);
void registerapi(lua_State*);
+void hsvtorgb(int, int, int, int*, int*, int*);
Image* color(int, int, int, int);
+int registerpixels(lua_State*);
+void lpushpixels(lua_State*);
+
extern int drawing;
extern int looping;
extern int framerate;
extern Image *canvas;
+extern Pixels *pixels;
extern int width;
extern int height;
extern Point origin;
--- a/api.c
+++ b/api.c
@@ -40,7 +40,6 @@
Point origin;
double angle;
-
Tmatrix tstack[255] = {0};
int ntstack;
Style sstack[255] = {0};
@@ -69,6 +68,7 @@
angle = 0.0;
lset(L, "mouseX", 0);
lset(L, "mouseY", 0);
+ lpushpixels(L);
}
void
@@ -138,6 +138,7 @@
height = h;
freeimage(canvas);
canvas = allocimage(display, Rect(0, 0, w, h), screen->chan, 0, DNofill);
+ lpushpixels(L);
resize(L, w, h);
return 0;
}
@@ -546,6 +547,51 @@
return 0;
}
+int
+ccolor(lua_State *L)
+{
+ int r, g, b;
+
+ r = luaL_checkinteger(L, 1);
+ g = luaL_checkinteger(L, 2);
+ b = luaL_checkinteger(L, 3);
+ if(colormode == Chsv)
+ hsvtorgb(r, g, b, &r, &g, &b);
+ lua_newtable(L);
+ lua_pushinteger(L, r);
+ lua_setfield(L, -2, "r");
+ lua_pushinteger(L, g);
+ lua_setfield(L, -2, "g");
+ lua_pushinteger(L, b);
+ lua_setfield(L, -2, "b");
+ return 1;
+}
+
+
+int
+cloadpixels(lua_State *L)
+{
+ char ebuf[ERRMAX];
+
+ if(unloadimage(canvas, canvas->r, pixels->data, pixels->ndata) < 0){
+ errstr(ebuf, sizeof ebuf);
+ return luaL_error(L, "unable to load pixels: %s", ebuf);
+ }
+ return 0;
+}
+
+int
+cupdatepixels(lua_State *L)
+{
+ char ebuf[ERRMAX];
+
+ if(loadimage(canvas, canvas->r, pixels->data, pixels->ndata) < 0){
+ errstr(ebuf, sizeof ebuf);
+ return luaL_error(L, "unable to update pixels: %s", ebuf);
+ }
+ return 0;
+}
+
void
registerfunc(lua_State *L, const char *name, int(*f)(lua_State*))
{
@@ -592,5 +638,8 @@
registerfunc(L, "popStyle", cpopstyle);
registerfunc(L, "push", cpush);
registerfunc(L, "pop", cpop);
+ registerfunc(L, "color", ccolor);
+ registerfunc(L, "loadPixels", cloadpixels);
+ registerfunc(L, "updatePixels", cupdatepixels);
}
--- a/mkfile
+++ b/mkfile
@@ -4,7 +4,7 @@
TARG=slug
LIB=lua/liblua.a.$O
HFILES=a.h
-OFILES=slug.$O api.$O color.$O
+OFILES=slug.$O api.$O color.$O pixels.$O
MAN=/sys/man/1
</sys/src/cmd/mkone
--- /dev/null
+++ b/pixels.c
@@ -1,0 +1,97 @@
+#include "a.h"
+
+Pixels *pixels;
+
+Pixels*
+checkpixels(lua_State *L)
+{
+ void *p;
+
+ p = luaL_checkudata(L, 1, "slug.pixels");
+ luaL_argcheck(L, p != nil, 1, "`pixels` expected");
+ return p;
+}
+
+int
+pixelstostring(lua_State *L)
+{
+ checkpixels(L);
+ lua_pushfstring(L, "pixels(%dx%d)", width, height);
+ return 1;
+}
+
+int
+pixelsget(lua_State *L)
+{
+ Pixels *p;
+ int i;
+
+ p = checkpixels(L);
+ i = luaL_checkinteger(L, 2);
+ luaL_argcheck(L, 1 <= i && i <= (width*height), 2, "index out of range");
+ i = (i-1)*4;
+ lua_newtable(L);
+ lua_pushinteger(L, p->data[i]);
+ lua_setfield(L, -2, "r");
+ lua_pushinteger(L, p->data[i+1]);
+ lua_setfield(L, -2, "g");
+ lua_pushinteger(L, p->data[i+2]);
+ lua_setfield(L, -2, "b");
+ return 1;
+}
+
+int
+pixelsset(lua_State *L)
+{
+ Pixels *p;
+ int i, r, g, b;
+
+ p = checkpixels(L);
+ i = luaL_checkinteger(L, 2);
+ luaL_argcheck(L, 1 <= i && i <= width*height, 2, "index out of range");
+ if(lua_istable(L, 3) == 0)
+ luaL_argerror(L, 3, "color table expected");
+ lua_pushstring(L, "r");
+ lua_gettable(L, 3);
+ r = luaL_checkinteger(L, -1);
+ lua_pushstring(L, "g");
+ lua_gettable(L, 3);
+ g = luaL_checkinteger(L, -1);
+ lua_pushstring(L, "b");
+ lua_gettable(L, 3);
+ b = luaL_checkinteger(L, -1);
+ i = (i-1)*4;
+ p->data[i + 0] = r;
+ p->data[i + 1] = g;
+ p->data[i + 2] = b;
+ return 0;
+}
+
+static const struct luaL_Reg pixelsmethods [] = {
+ { "__tostring", pixelstostring },
+ { "__index", pixelsget },
+ { "__newindex", pixelsset },
+ { nil, nil},
+};
+
+int
+registerpixels(lua_State *L)
+{
+ luaL_newmetatable(L, "slug.pixels");
+ luaL_setfuncs(L, pixelsmethods, 0);
+ lua_pop(L, 1);
+ return 0;
+}
+
+void
+lpushpixels(lua_State *L)
+{
+ int n;
+
+ n = sizeof(Pixels) + (width*height*4-1)*sizeof(uchar);
+ pixels = lua_newuserdata(L, n);
+ luaL_setmetatable(L, "slug.pixels");
+ pixels->ndata = width*height*4;
+ lua_setglobal(L, "pixels");
+}
+
--- /dev/null
+++ b/samples/pixels.lua
@@ -1,0 +1,19 @@
+#!/bin/slug
+
+function setup()
+ size(255, 255)
+ background(0)
+ loadPixels()
+ for y=1,254 do
+ c = color(y, y, y)
+ for x=1, 254 do
+ pixels[x + width * y] = c
+ end
+ end
+ updatePixels()
+end
+
+function draw()
+ noLoop()
+end
+
--- a/slug.c
+++ b/slug.c
@@ -17,6 +17,9 @@
lua_pushboolean(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
luaL_openlibs(L);
+ registerapi(L);
+ registerpixels(L);
+ initstate(L);
r = luaL_dofile(L, argc > 1 ? argv[1] : NULL);
if(r != LUA_OK){
s = luaL_checkstring(L, lua_gettop(L));
@@ -124,8 +127,6 @@
alts[2].c = kc->c;
setfcr(getfcr() & ~(FPZDIV | FPOVFL | FPINVAL));
L = linit(argc, argv);
- registerapi(L);
- initstate(L);
resize(L, width, height);
drawing = 0;
lcall(L, "setup");