shithub: lua9

ref: 9cd8f1f0e8a962efd05a1bfc7f8b4068bcb8d526
dir: lua9/lua9.c

View raw version
#include <u.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <draw.h>
#include <event.h>
#include <keyboard.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

#define IMAGE_META "Image"
#define DISPLAY_META "Display"
#define FONT_META "Font"

typedef struct ImagePtr ImagePtr;
typedef struct DisplayPtr DisplayPtr;
typedef struct FontPtr FontPtr;

struct ImagePtr {
	Image *p;
};

struct DisplayPtr {
	Display *p;
};

struct FontPtr {
	Font *p;
};

static lua_State *state;
static int ridx, tidx;

void eresized(int new) {
	if(new && getwindow(display, Refnone) < 0){
		fprintf(stderr, "cannot reattach to window: %r");
		exit(1);
	}
	lua_rawgeti(state, LUA_REGISTRYINDEX, ridx);
	lua_rawgeti(state, -1, tidx);
	lua_call(state, 0, 0);
	lua_pop(state, 2);
}

static void create_globals(lua_State *L) {
	ImagePtr *i;
	DisplayPtr *d;
	FontPtr *f;

	i = (ImagePtr*)lua_newuserdatauv(L, sizeof(ImagePtr), 1);
	luaL_getmetatable(L, IMAGE_META);
	lua_setmetatable(L, -2);
	i->p = screen;
	lua_setglobal(L, "screen");
	d = (DisplayPtr*)lua_newuserdata(L, sizeof(DisplayPtr));
	luaL_getmetatable(L, DISPLAY_META);
	lua_setmetatable(L, -2);
	d->p = display;
	lua_setglobal(L, "display");
	f = (FontPtr*)lua_newuserdata(L, sizeof(FontPtr));
	luaL_getmetatable(L, FONT_META);
	lua_setmetatable(L, -2);
	f->p = font;
	lua_setglobal(L, "font");
}

static int l_initdraw(lua_State *L) {
	const char *n;
	char buf[256];
	
	n = luaL_checkstring(L, -1);
	lua_newtable(L);
	ridx = luaL_ref(L, LUA_REGISTRYINDEX);
	lua_rawgeti(L, LUA_REGISTRYINDEX, ridx);
	lua_getglobal(L, "eresized");
	if(lua_isfunction(L, -1) == 0){
		lua_pushstring(L, "eresized function not declared");
		lua_error(L);
	}
	tidx = luaL_ref(L, -2);
	lua_pop(L, 1);
	if(initdraw(nil, nil, n) < 0){
		snprintf(buf, sizeof buf, "initdraw failed: %r");
		lua_pushstring(L, buf);
		lua_error(L);
	}
	state = L;
	create_globals(L);
	return 0;
}

static int l_einit(lua_State *L) {
	lua_Integer i;

	i = luaL_checknumber(L, -1);
	einit((ulong)i);
	return 0;
}

static int l_event(lua_State *L) {
	Event ev;
	int e;

	e = event(&ev);
	lua_pushnumber(L, e);
	lua_newtable(L);
	lua_pushinteger(L, ev.kbdc);
	lua_setfield(L, -2, "kbdc");
	return 2;
}

static Point l_getpoint(lua_State *L, int index)
{
	Point p;

	lua_pushstring(L, "x");
	lua_gettable(L, index);
	p.x = luaL_checkinteger(L, -1);
	lua_pushstring(L, "y");
	lua_gettable(L, index);
	p.y = luaL_checkinteger(L, -1);
	lua_pop(L, 2);
	return p;
}

static Point l_checkpoint(lua_State *L, int index)
{
	if(lua_istable(L, index) == 0)
		luaL_argerror(L, index, "draw: point table expected");
	return l_getpoint(L, index);
}

static Point l_optpoint(lua_State *L, int index)
{
	if(lua_istable(L, index) == 0)
		return ZP;
	return l_getpoint(L, index);
}

static Rectangle l_getrect(lua_State *L, int index)
{
	Rectangle r;
	int t;

	lua_pushstring(L, "min");
	lua_gettable(L, index);
	lua_pushstring(L, "x");
	lua_gettable(L, -2);
	r.min.x = luaL_checkinteger(L, -1);
	lua_pushstring(L, "y");
	t = lua_gettable(L, -3);
	r.min.y = luaL_checkinteger(L, -1);
	lua_pop(L, 3); /* table | x | y */
	lua_pushstring(L, "max");
	lua_gettable(L, index);
	lua_pushstring(L, "x");
	lua_gettable(L, -2);
	r.max.x = luaL_checkinteger(L, -1);
	lua_pushstring(L, "y");
	lua_gettable(L, -3);
	r.max.y = luaL_checkinteger(L, -1);
	lua_pop(L, 3);
	return r;
}

static Rectangle l_checkrect(lua_State *L, int index)
{
	if(lua_istable(L, index) == 0)
		luaL_argerror(L, index, "draw: rectangle table expected");
	return l_getrect(L, index);
}

static Image* l_checkimage(lua_State *L, int index)
{
	ImagePtr *p;

	p = (ImagePtr*)luaL_checkudata(L, index, IMAGE_META);
	luaL_argcheck(L, p != NULL, index, "draw: Image expected");
	return p->p;
}

static Image* l_optimage(lua_State *L, int index)
{
	if(lua_isnil(L, index))
		return nil;
	return l_checkimage(L, index);
}

static Font* l_checkfont(lua_State *L, int index)
{
	FontPtr *p;

	p = (FontPtr*)luaL_checkudata(L, index, FONT_META);
	luaL_argcheck(L, p != NULL, index, "draw: Font expected");
	return p->p;
}

static int l_draw(lua_State *L) {
	Image *dst, *src, *mask;
	Point p;
	Rectangle r;

	dst  = l_checkimage(L, 1);
	r    = l_checkrect(L, 2);
	src  = l_checkimage(L, 3);
	mask = l_optimage(L, 4);
	p    = l_checkpoint(L, 5);
	draw(dst, r, src, mask, p);
	return 0;
}

static int l_line(lua_State *L) {
	Image *dst, *src;
	Point p0, p1, sp;
	int end0, end1, thick;

	dst   = l_checkimage(L, 1);
	p0    = l_checkpoint(L, 2);
	p1    = l_checkpoint(L, 3);
	end0  = luaL_checkinteger(L, 4);
	end1  = luaL_checkinteger(L, 5);
	thick = luaL_checkinteger(L, 6);
	src   = l_checkimage(L, 7);
	sp    = l_checkpoint(L, 8);
	line(dst, p0, p1, end0, end1, thick, src, sp);
	return 0;
}

static int l_ellipse(lua_State *L)
{
	Image *dst, *src;
	Point c, sp;
	int a, b, thick;

	dst   = l_checkimage(L, 1);
	c     = l_checkpoint(L, 2);
	a     = luaL_checkinteger(L, 3);
	b     = luaL_checkinteger(L, 4);
	thick = luaL_checkinteger(L, 5);
	src   = l_checkimage(L, 6);
	sp    = l_checkpoint(L, 7);
	ellipse(dst, c, a, b, thick, src, sp);
	return 0;
}

static int l_fillellipse(lua_State *L)
{
	Image *dst, *src;
	Point c, sp;
	int a, b;

	dst   = l_checkimage(L, 1);
	c     = l_checkpoint(L, 2);
	a     = luaL_checkinteger(L, 3);
	b     = luaL_checkinteger(L, 4);
	src   = l_checkimage(L, 5);
	sp    = l_checkpoint(L, 6);
	fillellipse(dst, c, a, b, src, sp);
	return 0;
}

static int l_string(lua_State *L) {
	Image *dst, *src;
	Font *f;
	Point p, sp;
	const char *s;

	dst = l_checkimage(L, 1);
	p   = l_checkpoint(L, 2);
	src = l_checkimage(L, 3);
	sp  = l_optpoint(L, 4);
	f   = l_checkfont(L, 5);
	s   = luaL_checkstring(L, 6);
	string(dst, p, src, sp, f, s);
	return 0;
}

/* Image metatable */
static int l_image_gc(lua_State *L) {
	ImagePtr *i;

	i = (ImagePtr*)luaL_checkudata(L, 1, IMAGE_META);
	luaL_argcheck(L, i != NULL, 1, "draw: Image expected");
	if(i->p == screen) {
		lua_pushboolean(L, 0);
		return 1;
	}
	/* TODO freeimage */
	lua_pushboolean(L, 1);
	return 1;
}

static int l_image_tostring(lua_State *L) {
	void *p;
	char buf[64];

	p = lua_touserdata(L, 1);
	snprintf(buf, sizeof buf, "image: %p", p);
	lua_pushstring(L, buf);
	return 1;
}

static void l_pushrect(lua_State *L, Rectangle r)
{
	lua_newtable(L);
	lua_newtable(L);
	lua_pushinteger(L, r.min.x);
	lua_setfield(L, -2, "x");
	lua_pushinteger(L, r.min.y);
	lua_setfield(L, -2, "y");
	lua_setfield(L, -2, "min");
	lua_newtable(L);
	lua_pushinteger(L, r.max.x);
	lua_setfield(L, -2, "x");
	lua_pushinteger(L, r.max.y);
	lua_setfield(L, -2, "y");
	lua_setfield(L, -2, "max");
}

static int l_image_index(lua_State *L) {
	Image *i;
	const char *s;

	i = l_checkimage(L, 1);
	s = luaL_checkstring(L, 2);
	if(!strncmp(s, "r", 1)) {
		l_pushrect(L, i->r);
	} else if(!strncmp(s, "clipr", 5)) {
		l_pushrect(L, i->clipr);
	} else if(!strncmp(s, "chan", 4)) {
		lua_pushinteger(L, i->chan);
	} else if(!strncmp(s, "depth", 5)) {
		lua_pushinteger(L, i->depth);
	} else if(!strncmp(s, "repl", 4)) {
		lua_pushinteger(L, i->repl);
	} else {
		return 0;
	}
	return 1;
}

static const struct luaL_Reg image_funcs[] = {
	{ "__gc", l_image_gc },
	{ "__tostring", l_image_tostring },
	{ "__index", l_image_index },
	{ NULL, NULL },
};

static int l_display_gc(lua_State *L) {
	/* we do not GC the display */
	lua_pushboolean(L, 0);
	return 1;
}

static int l_display_tostring(lua_State *L) {
	void *p;
	char buf[64];

	p = lua_touserdata(L, 1);
	snprintf(buf, sizeof buf, "display: %p", p);
	lua_pushstring(L, buf);
	return 1;
}

static ImagePtr* to_image(lua_State *L, Image *img) {
	ImagePtr *i;

	i = (ImagePtr*)lua_newuserdata(L, sizeof(ImagePtr));
	luaL_getmetatable(L, IMAGE_META);
	lua_setmetatable(L, -2);
	i->p = img;
	return i;
}

static int l_display_index(lua_State *L) {
	DisplayPtr *d;
	const char *s;

	d = (DisplayPtr*)luaL_checkudata(L, 1, DISPLAY_META);
	luaL_argcheck(L, d != NULL, 1, "draw: Display expected");
	s = luaL_checkstring(L, 2);
	if(strncmp(s, "white", 5) == 0) {
		to_image(L, d->p->white);
		return 1;
	} else if(strncmp(s, "black", 5) == 0) {
		to_image(L, d->p->black);
		return 1;
	}
	return 0;
}

static const struct luaL_Reg display_funcs[] = {
	{ "__gc", l_display_gc },
	{ "__tostring", l_display_tostring },
	{ "__index", l_display_index },
	{ NULL, NULL },
};

static int l_font_gc(lua_State *L) {
	/* TODO */
	lua_pushboolean(L, 0);
	return 1;
}

static int l_font_tostring(lua_State *L) {
	void *p;

	p = lua_touserdata(L, 1);
	lua_pushfstring(L, "font: %p", p);
	return 1;
}

static const struct luaL_Reg font_funcs[] = {
	{ "__gc", l_font_gc },
	{ "__tostring", l_font_tostring },
//	{ "__index", l_display_index },
	{ NULL, NULL },
};

static void create_metatable(lua_State *L, const char *name, luaL_Reg *funcs) {
	luaL_newmetatable(L, name);
	luaL_setfuncs(L, funcs, 0);
	lua_pushliteral (L, "__metatable");
	lua_pushliteral (L, "draw: you're not allowed to get this metatable");
	lua_settable (L, -3);
}

static const struct luaL_Reg drawlib [] = {
	{ "initdraw",    l_initdraw },
	{ "einit",       l_einit },
	{ "event",       l_event },
	{ "draw",        l_draw },
	{ "line",        l_line },
	{ "ellipse",     l_ellipse },
	{ "fillellipse", l_fillellipse },
	{ "string",      l_string },
	{ NULL, NULL }
};

static void l_pushglobal(lua_State *L, const char *name, int value, int index)
{
	lua_pushnumber(L, value);
	lua_setfield(L, index, name);	
}

int luaopen_drawlib (lua_State *L) {
	create_metatable(L, IMAGE_META, image_funcs);
	create_metatable(L, DISPLAY_META, display_funcs);
	create_metatable(L, FONT_META, font_funcs);
	luaL_newlib(L, drawlib);
	lua_pushnumber(L, Emouse);
	lua_setfield(L, -2, "Emouse");
	lua_pushnumber(L, Ekeyboard);
	lua_setfield(L, -2, "Ekeyboard");
	l_pushglobal(L, "Endsquare", Endsquare, -2);
	l_pushglobal(L, "Enddisc", Enddisc, -2);
	l_pushglobal(L, "Endarrow", Endarrow, -2);
	l_pushglobal(L, "Endmask", Endmask, -2);

	return 1;
}


int
main(int argc, char *argv[])
{
	lua_State *L;
	char *f = NULL;
	int r;

	L = luaL_newstate();
	luaL_openlibs(L);
    	luaL_requiref(L, "draw", luaopen_drawlib, 1);
    	lua_pop(L, 1);
	if(argc > 1)
		f = argv[1];
	r = luaL_dofile(L, f);
	lua_close(L);
	return f == LUA_OK;
}