#define _XOPEN_SOURCE 500 #include "res.h" #include "lupi.h" #include #include #include #ifndef _WIN32 #include #include #include #include #include #include #include #include #include #include #include int fb_ready = 0; int fb_file; struct fb_var_screeninfo fb_vinfo; struct fb_fix_screeninfo fb_finfo; char *fb_ptr = 0; char *colbuf = 0; ushort *chrbuf = 0; int fb_cw, fb_ch, fb_bpp, fb_bypp, fb_xo, fb_yo, fb_pitch; int fb_rot = 0; int palette[256]; float pal_yuv[768]; #define XY_TO_FB(x, y) (((fb_yo + (y)) * fb_pitch) + ((fb_xo + (x)) * fb_bypp)) #define XY_TO_COLBUF(x, y, z) (((((y) * fb_cw) + (x)) * 2) + (z)) #define XY_TO_CHRBUF(x, y) (((y) * fb_cw) + (x)) static inline int fb_xrot(int x, int y) { switch (fb_rot) { default: return x; case 1: return fb_vinfo.xres - y - 1; case 2: return fb_vinfo.xres - x - 1; case 3: return y; } } static inline int fb_yrot(int x, int y) { switch (fb_rot) { default: return y; case 1: return x; case 2: return fb_vinfo.yres - y - 1; case 3: return fb_vinfo.yres - x - 1; } } static inline int fb_cxrot(int x, int y) { switch (fb_rot) { default: return x; case 1: return (fb_vinfo.xres >> 4) - y - 1; case 2: return (fb_vinfo.xres >> 3) - x - 1; case 3: return y; } } static inline int fb_cyrot(int x, int y) { switch (fb_rot) { default: return y; case 1: return x; case 2: return (fb_vinfo.yres >> 4) - y - 1; case 3: return (fb_vinfo.yres >> 3) - x - 1; } } static inline float yuv_y(int r, int g, int b) { float rf = r/255.0f; float gf = g/255.0f; float bf = b/255.0f; return 0.299f * r + 0.587f * g + 0.114f * b; } static inline float yuv_u(int r, int g, int b) { float rf = r/255.0f; float gf = g/255.0f; float bf = b/255.0f; return -0.147f * r - 0.289f * g + 0.436f * b; } static inline float yuv_v(int r, int g, int b) { float rf = r/255.0f; float gf = g/255.0f; float bf = b/255.0f; return 0.615f * r - 0.515f * g - 0.100f * b; } static int l_set_palette (lua_State *L) { int i = lua_tonumber(L, 1); int pal = lua_tonumber(L, 2); if(i >= 0 && i < 256) { // calculate yuv int r = (pal >> 16) & 0xFF; int g = (pal >> 8) & 0xFF; int b = pal & 0xFF; pal_yuv[i*3] = yuv_y(r, g, b); pal_yuv[i*3+1] = yuv_u(r, g, b); pal_yuv[i*3+2] = yuv_v(r, g, b); // set palette color if (fb_bpp == 16) { palette[i] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3); } else { palette[i] = pal; } } return 0; } static int l_get_nearest (lua_State *L) { int nck = 0; float ncv = 1000000; int i; int col = lua_tonumber(L, 1); int r = (col >> 16) & 0xFF; int g = (col >> 8) & 0xFF; int b = (col) & 0xFF; float coly = yuv_y(r, g, b); float colu = yuv_u(r, g, b); float colv = yuv_v(r, g, b); float dist,dy,du,dv; for (i = 0; i < 256; i++) { if (palette[i] == col) { lua_pushnumber(L, i); return 1; } dy = coly - pal_yuv[i*3]; du = colu - pal_yuv[i*3+1]; dv = colv - pal_yuv[i*3+2]; dist = dy*dy + du*du + dv*dv; if (dist < ncv) { nck = i; ncv = dist; } } lua_pushnumber(L, nck); return 1; } static int fb_copy(int x, int y, int w, int h, int x2, int y2) { int i, j; char* tmp = (char*) malloc(w*h*fb_bypp); for (j = 0; j < h; j++) { char* ptr = &fb_ptr[XY_TO_FB((x), ((y) + (j)))]; memcpy(&tmp[w*j*fb_bypp], ptr, w*fb_bypp); } for (j = 0; j < h; j++) { char* ptr = &fb_ptr[XY_TO_FB((x2), (y2 + (j)))]; memcpy(ptr, &tmp[w*j*fb_bypp], w*fb_bypp); } free(tmp); } static inline int fb_draw_16(int x, int y, ushort bg, ushort fg, int chr, int cwd) { int table[4]; int px, py; int c = 0; if (fb_rot > 0) { short* ptr = (short*) &fb_ptr; for (py = 0; py < 16; py++) { if (cwd == 2) { c = (res_unifont[chr * 33 + 2 + (py * 2)] << 8) | res_unifont[chr * 33 + 1 + (py * 2)]; } else if (cwd == 1) { c = res_unifont[chr * 33 + 1 + py]; } for (px = (cwd == 2 ? 15 : 7); px >= 0; px--) { *((short*) &fb_ptr[XY_TO_FB( fb_xrot((x * 8) + px, (y * 16) + py), fb_yrot((x * 8) + px, (y * 16) + py) )]) = (c & 1) ? fg : bg; c >>= 1; } } } else { table[0] = bg << 16 | bg; table[1] = fg << 16 | bg; table[2] = bg << 16 | fg; table[3] = fg << 16 | fg; /* for (py = 0; py < 16; py++) { if (cwd == 2) { c = (res_unifont[chr * 33 + 2 + (py * 2)] << 8) | res_unifont[chr * 33 + 1 + (py * 2)]; } else if (cwd == 1) { c = res_unifont[chr * 33 + 1 + py]; } ptr = (short*) (&fb_ptr[XY_TO_FB((x * 8), ((y * 16) + py))]); for (px = (cwd == 2 ? 15 : 7); px >= 0; px--) { ptr[px] = (c & 1) ? fg : bg; c >>= 1; } } */ int* ptr = (int*) (&fb_ptr[XY_TO_FB((x * 8), ((y * 16)))]); for (py = 0; py < 16; py++) { if (cwd == 2) { c = (res_unifont[chr * 33 + 2 + (py * 2)] << 8) | res_unifont[chr * 33 + 1 + (py * 2)]; ptr[7] = table[(c & 3)]; c >>= 2; ptr[6] = table[(c & 3)]; c >>= 2; ptr[5] = table[(c & 3)]; c >>= 2; ptr[4] = table[(c & 3)]; c >>= 2; ptr[3] = table[(c & 3)]; c >>= 2; ptr[2] = table[(c & 3)]; c >>= 2; ptr[1] = table[(c & 3)]; c >>= 2; ptr[0] = table[(c & 3)]; c >>= 2; } else if (cwd == 1) { c = res_unifont[chr * 33 + 1 + py]; ptr[3] = table[(c & 3)]; c >>= 2; ptr[2] = table[(c & 3)]; c >>= 2; ptr[1] = table[(c & 3)]; c >>= 2; ptr[0] = table[(c & 3)]; c >>= 2; } ptr += fb_pitch >> 2; } } } static inline int fb_draw_32(int x, int y, int bg, int fg, int chr, int cwd) { int px, py; int c = 0; int* ptr; if (fb_rot > 0) { for (py = 0; py < 16; py++) { if (cwd == 2) { c = (res_unifont[chr * 33 + 2 + (py * 2)] << 8) | res_unifont[chr * 33 + 1 + (py * 2)]; } else if (cwd == 1) { c = res_unifont[chr * 33 + 1 + py]; } for (px = (cwd == 2 ? 15 : 7); px >= 0; px--) { *((int*) &fb_ptr[XY_TO_FB( fb_xrot((x * 8) + px, (y * 16) + py), fb_yrot((x * 8) + px, (y * 16) + py) )]) = (c & 1) ? fg : bg; c >>= 1; } } } else { ptr = (int*) (&fb_ptr[XY_TO_FB((x * 8), ((y * 16) + py))]); for (py = 0; py < 16; py++) { if (cwd == 2) { c = (res_unifont[chr * 33 + 2 + (py * 2)] << 8) | res_unifont[chr * 33 + 1 + (py * 2)]; } else if (cwd == 1) { c = res_unifont[chr * 33 + 1 + py]; } for (px = (cwd == 2 ? 15 : 7); px >= 0; px--) { ptr[px] = (c & 1) ? fg : bg; c >>= 1; } ptr += fb_pitch >> 2; } } } static int fb_draw(int x, int y, int bg, int fg, int chr) { if (x < 0 || x >= fb_cw || y < 0 || y >= fb_ch || bg < 0 || bg >= 256 || fg < 0 || fg >= 256 || chr < 0 || chr >= 65536) { return 0; } colbuf[XY_TO_COLBUF(x, y, 0)] = (char) bg; colbuf[XY_TO_COLBUF(x, y, 1)] = (char) fg; chrbuf[XY_TO_CHRBUF(x, y)] = (ushort) chr; int cwd = res_unifont[chr * 33]; if (cwd == 2 && x < (fb_cw - 1)) { chrbuf[XY_TO_CHRBUF(x + 1, y)] = (ushort) 0; } if (fb_bpp == 32) { fb_draw_32(x,y,palette[bg],palette[fg],chr,cwd); } else if (fb_bpp == 16) { fb_draw_16(x,y,(ushort) palette[bg],(ushort) palette[fg],chr,cwd); } return 0; } static int l_fbput (lua_State *L) { int x = lua_tonumber(L, 1); int y = lua_tonumber(L, 2); int bg = lua_tonumber(L, 3); int fg = lua_tonumber(L, 4); int chr = lua_tonumber(L, 5); return fb_draw(x, y, bg, fg, chr); } static int l_fbcopy (lua_State *L) { int x = lua_tonumber(L, 1); int y = lua_tonumber(L, 2); int w = lua_tonumber(L, 3); int h = lua_tonumber(L, 4); int tx = x+lua_tonumber(L, 5); int ty = y+lua_tonumber(L, 6); int j, px = x<<3, py = y<<4, pw = w<<3, ph = h<<4, ptx = tx<<3, pty = ty<<4; char* tmpcol = (char*) malloc(w*h*2); char* tmpchr = (char*) malloc(w*h*2); if (fb_rot == 1 || fb_rot == 3) { j = pw; pw = ph; ph = j; } j = fb_xrot(px, py); py = fb_yrot(px, py); px = j; j = fb_xrot(ptx, pty); pty = fb_yrot(ptx, pty); ptx = j; if (fb_rot == 1 || fb_rot == 2) { px -= pw-1; ptx -= pw-1; } if (fb_rot == 3 || fb_rot == 2) { py -= ph-1; pty -= ph-1; } for (j = 0; j < h; j++) { memcpy(&tmpcol[j*w*2], &colbuf[XY_TO_COLBUF(x, y+j, 0)], w * 2); memcpy(&tmpchr[j*w*2], &chrbuf[XY_TO_CHRBUF(x, y+j)], w * 2); } fb_copy(px, py, pw, ph, ptx, pty); for (j = 0; j < h; j++) { memcpy(&colbuf[XY_TO_COLBUF(tx, ty+j, 0)], &tmpcol[j*w*2], w * 2); memcpy(&chrbuf[XY_TO_CHRBUF(tx, ty+j)], &tmpchr[j*w*2], w * 2); } free(tmpcol); free(tmpchr); } static int l_fbfill (lua_State *L) { int x1 = lua_tonumber(L, 1); int y1 = lua_tonumber(L, 2); int x2 = lua_tonumber(L, 3); int y2 = lua_tonumber(L, 4); int bg = lua_tonumber(L, 5); int fg = lua_tonumber(L, 6); int chr = lua_tonumber(L, 7); int i, j; for (i = y1; i <= y2; i++) { for (j = x1; j <= x2; j++) { fb_draw(j, i, bg, fg, chr); } } return 0; } static int l_get_width (lua_State *L) { lua_pushnumber(L, fb_cw); return 1; } static int l_get_height (lua_State *L) { lua_pushnumber(L, fb_ch); return 1; } static int l_fb_getbg (lua_State *L) { int x = lua_tonumber(L, 1); int y = lua_tonumber(L, 2); if (x >= 0 && y >= 0 && x < fb_cw && y < fb_ch) { lua_pushnumber(L, colbuf[XY_TO_COLBUF(x, y, 0)]); } else { lua_pushnumber(L, 0); } return 1; } static int l_fb_getfg (lua_State *L) { int x = lua_tonumber(L, 1); int y = lua_tonumber(L, 2); if (x >= 0 && y >= 0 && x < fb_cw && y < fb_ch) { lua_pushnumber(L, colbuf[XY_TO_COLBUF(x, y, 1)]); } else { lua_pushnumber(L, 0); } return 1; } static int l_fb_get (lua_State *L) { int x = lua_tonumber(L, 1); int y = lua_tonumber(L, 2); if (x >= 0 && y >= 0 && x < fb_cw && y < fb_ch) { lua_pushnumber(L, chrbuf[XY_TO_CHRBUF(x, y)]); } else { lua_pushnumber(L, 0); } return 1; } #endif static int l_fb_ready (lua_State *L) { #ifndef _WIN32 lua_pushboolean(L, fb_ready); #else lua_pushboolean(L, 0); #endif return 1; } void fb_start(lua_State *L) { #ifndef _WIN32 fb_file = open("/dev/fb0", O_RDWR); if (fb_file == -1) { printf("Error: cannot open framebuffer device"); exit(1); return; } if (ioctl(fb_file, FBIOGET_FSCREENINFO, &fb_finfo) == -1) { printf("Error reading fixed information"); exit(1); return; } if (ioctl(fb_file, FBIOGET_VSCREENINFO, &fb_vinfo) == -1) { printf("Error reading variable information"); exit(1); return; } fb_vinfo.bits_per_pixel = 16; if (fb_rot == 1 || fb_rot == 3) { fb_cw = fb_vinfo.yres / 8; fb_ch = fb_vinfo.xres / 16; } else { fb_cw = fb_vinfo.xres / 8; fb_ch = fb_vinfo.yres / 16; } if (ioctl(fb_file, FBIOPUT_VSCREENINFO, &fb_vinfo) == -1) { fb_vinfo.bits_per_pixel = 32; if (ioctl(fb_file, FBIOPUT_VSCREENINFO, &fb_vinfo) == -1) { printf("Error setting 32 or 16BPP mode"); exit(1); return; } } fb_bpp = fb_vinfo.bits_per_pixel; fb_bypp = fb_bpp >> 3; fb_pitch = fb_vinfo.xres_virtual * fb_bypp; fb_xo = fb_vinfo.xoffset; fb_yo = fb_vinfo.yoffset; fb_ptr = (char *)mmap(0, fb_vinfo.xres * fb_vinfo.yres * fb_bypp, PROT_READ | PROT_WRITE, MAP_SHARED, fb_file, 0); if ((intptr_t)fb_ptr == -1) { printf("Failed to map framebuffer device to memory"); exit(1); return; } colbuf = (char *)malloc(2 * fb_cw * fb_ch); chrbuf = (ushort *)malloc(2 * fb_cw * fb_ch); fb_ready = 1; #endif struct luaL_Reg fblib[] = { #ifndef _WIN32 {"setPalette", l_set_palette}, {"getWidth", l_get_width}, {"getHeight", l_get_height}, {"put", l_fbput}, {"copy", l_fbcopy}, {"fill", l_fbfill}, {"getBackground", l_fb_getbg}, {"getForeground", l_fb_getfg}, {"get", l_fb_get}, {"getNearest", l_get_nearest}, #endif {"isReady", l_fb_ready}, {NULL, NULL} }; luaL_openlib(L, "framebuffer", fblib, 0); }