shithub: slug

Download patch

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");