summaryrefslogtreecommitdiff
path: root/gpu.lua
diff options
context:
space:
mode:
Diffstat (limited to 'gpu.lua')
-rw-r--r--gpu.lua431
1 files changed, 431 insertions, 0 deletions
diff --git a/gpu.lua b/gpu.lua
new file mode 100644
index 0000000..cf75a05
--- /dev/null
+++ b/gpu.lua
@@ -0,0 +1,431 @@
+local font = dofile(minetest.get_modpath("digistuff")..DIR_DELIM.."gpu-font.lua")
+
+local function explodebits(input)
+ local output = {}
+ for i=0,7,1 do
+ output[i] = input%(2^(i+1)) >= 2^i
+ end
+ return output
+end
+
+local function implodebits(input)
+ local output = 0
+ for i=0,7,1 do
+ output = output + (input[i] and 2^i or 0)
+ end
+ return output
+end
+
+local function tohsv(r,g,b)
+ r = r/255
+ g = g/255
+ b = b/255
+ max = math.max(r,g,b)
+ min = math.min(r,g,b)
+ delta = max-min
+ local hue = 0
+ if delta > 0 then
+ if max == r then
+ hue = (g-b)/delta
+ hue = (hue%6)*60
+ elseif max == g then
+ hue = (b-r)/delta
+ hue = 60*(hue+2)
+ elseif max == b then
+ hue = (r-g)/delta
+ hue = 60*(hue+4)
+ end
+ hue = hue/360
+ end
+ local sat = 0
+ if max > 0 then
+ sat = delta/max
+ end
+ return math.floor(hue*255),math.floor(sat*255),math.floor(max*255)
+end
+
+local function torgb(h,s,v)
+ h = h/255*360
+ s = s/255
+ v = v/255
+ local c = s*v
+ local x = (h/60)%2
+ x = 1-math.abs(x-1)
+ x = x*c
+ local m = v-c
+ local r = 0
+ local g = 0
+ local b = 0
+ if h < 60 then
+ r = c
+ g = x
+ elseif h < 120 then
+ r = x
+ g = c
+ elseif h < 180 then
+ g = c
+ b = x
+ elseif h < 240 then
+ g = x
+ b = c
+ elseif h < 300 then
+ r = x
+ b = c
+ else
+ r = c
+ b = x
+ end
+ r = r+m
+ g = g+m
+ b = b+m
+ return math.floor(r*255),math.floor(g*255),math.floor(b*255)
+end
+
+local function bitwiseblend(srcr,dstr,srcg,dstg,srcb,dstb,mode)
+ local srbits = explodebits(srcr)
+ local sgbits = explodebits(srcg)
+ local sbbits = explodebits(srcb)
+ local drbits = explodebits(dstr)
+ local dgbits = explodebits(dstg)
+ local dbbits = explodebits(dstb)
+ for i=0,7,1 do
+ if mode == "and" then
+ drbits[i] = srbits[i] and drbits[i]
+ dgbits[i] = sgbits[i] and dgbits[i]
+ dbbits[i] = sbbits[i] and dbbits[i]
+ elseif mode == "or" then
+ drbits[i] = srbits[i] or drbits[i]
+ dgbits[i] = sgbits[i] or dgbits[i]
+ dbbits[i] = sbbits[i] or dbbits[i]
+ elseif mode == "xor" then
+ drbits[i] = srbits[i] ~= drbits[i]
+ dgbits[i] = sgbits[i] ~= dgbits[i]
+ dbbits[i] = sbbits[i] ~= dbbits[i]
+ elseif mode == "xnor" then
+ drbits[i] = srbits[i] == drbits[i]
+ dgbits[i] = sgbits[i] == dgbits[i]
+ dbbits[i] = sbbits[i] == dbbits[i]
+ elseif mode == "not" then
+ drbits[i] = not srbits[i]
+ dgbits[i] = not sgbits[i]
+ dbbits[i] = not sbbits[i]
+ elseif mode == "nand" then
+ drbits[i] = not (srbits[i] and drbits[i])
+ dgbits[i] = not (sgbits[i] and dgbits[i])
+ dbbits[i] = not (sbbits[i] and dbbits[i])
+ elseif mode == "nor" then
+ drbits[i] = not (srbits[i] or drbits[i])
+ dgbits[i] = not (sgbits[i] or dgbits[i])
+ dbbits[i] = not (sbbits[i] or dbbits[i])
+ end
+ end
+ return string.format("%02X%02X%02X",implodebits(drbits),implodebits(dgbits),implodebits(dbbits))
+end
+
+local function blend(src,dst,mode,transparent)
+ local srcr = tonumber(string.sub(src,1,2),16)
+ local srcg = tonumber(string.sub(src,3,4),16)
+ local srcb = tonumber(string.sub(src,5,6),16)
+ local dstr = tonumber(string.sub(dst,1,2),16)
+ local dstg = tonumber(string.sub(dst,3,4),16)
+ local dstb = tonumber(string.sub(dst,5,6),16)
+ local op = "normal"
+ if type(mode) == "string" then op = string.lower(mode) end
+ if op == "normal" then
+ return src
+ elseif op == "nop" then
+ return dst
+ elseif op == "overlay" then
+ return (string.upper(src) == string.upper(transparent)) and dst or src
+ elseif op == "add" then
+ local r = math.min(255,srcr+dstr)
+ local g = math.min(255,srcg+dstg)
+ local b = math.min(255,srcb+dstb)
+ return string.format("%02X%02X%02X",r,g,b)
+ elseif op == "sub" then
+ local r = math.max(0,dstr-srcr)
+ local g = math.max(0,dstg-srcg)
+ local b = math.max(0,dstb-srcb)
+ return string.format("%02X%02X%02X",r,g,b)
+ elseif op == "isub" then
+ local r = math.max(0,srcr-dstr)
+ local g = math.max(0,srcg-dstg)
+ local b = math.max(0,srcb-dstb)
+ return string.format("%02X%02X%02X",r,g,b)
+ elseif op == "average" then
+ local r = math.min(255,(srcr+dstr)/2)
+ local g = math.min(255,(srcg+dstg)/2)
+ local b = math.min(255,(srcb+dstb)/2)
+ return string.format("%02X%02X%02X",r,g,b)
+ elseif op == "and" or op == "or" or op == "xor" or op == "xnor" or op == "not" or op == "nand" or op == "nor" then
+ return bitwiseblend(srcr,dstr,srcg,dstg,srcb,dstb,op)
+ elseif op == "tohsv" then
+ return string.format("%02X%02X%02X",tohsv(srcr,srcg,srcb))
+ elseif op == "torgb" then
+ return string.format("%02X%02X%02X",torgb(srcr,srcg,srcb))
+ else
+ return src
+ end
+end
+
+local function runcommand(pos,meta,command)
+ if type(command) ~= "table" then return end
+ if command.command == "createbuffer" then
+ if type(command.buffer) ~= "number" or type(command.xsize) ~= "number" or type(command.ysize) ~= "number" then return end
+ local bufnum = math.floor(command.buffer)
+ if bufnum < 0 or bufnum > 7 then return end
+ local xsize = math.min(64,math.floor(command.xsize))
+ local ysize = math.min(64,math.floor(command.ysize))
+ if xsize < 1 or ysize < 1 then return end
+ local fillcolor = command.fill
+ if type(fillcolor) ~= "string" or string.len(fillcolor) > 7 or string.len(fillcolor) < 6 then fillcolor = "000000" end
+ if string.sub(fillcolor,1,1) == "#" then fillcolor = string.sub(fillcolor,2,7) end
+ if not tonumber(fillcolor,16) then fillcolor = "000000" end
+ local buffer = {}
+ buffer.xsize = xsize
+ buffer.ysize = ysize
+ for y=1,ysize,1 do
+ buffer[y] = {}
+ for x=1,xsize,1 do
+ buffer[y][x] = fillcolor
+ end
+ end
+ meta:set_string("buffer"..bufnum,minetest.serialize(buffer))
+ elseif command.command == "send" then
+ if type(command.buffer) ~= "number" or type(command.channel) ~= "string" then return end
+ local bufnum = math.floor(command.buffer)
+ if bufnum < 0 or bufnum > 7 then return end
+ local buffer = meta:get_string("buffer"..bufnum)
+ if string.len(buffer) == 0 then return end
+ buffer = minetest.deserialize(buffer)
+ if type(buffer) == "table" then
+ digiline:receptor_send(pos,digiline.rules.default,command.channel,buffer)
+ end
+ elseif command.command == "drawrect" then
+ if type(command.buffer) ~= "number" or type(command.x1) ~= "number" or type(command.y1) ~= "number" or type(command.x2) ~= "number" or type(command.y2) ~= "number" then return end
+ local bufnum = math.floor(command.buffer)
+ if bufnum < 0 or bufnum > 7 then return end
+ local x1 = math.min(64,math.floor(command.x1))
+ local y1 = math.min(64,math.floor(command.y1))
+ local x2 = math.min(64,math.floor(command.x2))
+ local y2 = math.min(64,math.floor(command.y2))
+ if x1 < 1 or y1 < 1 or x2 < 1 or y2 < 1 then return end
+ local buffer = meta:get_string("buffer"..bufnum)
+ if string.len(buffer) == 0 then return end
+ buffer = minetest.deserialize(buffer)
+ if type(buffer) ~= "table" then return end
+ x2 = math.min(x2,buffer.xsize)
+ y2 = math.min(y2,buffer.ysize)
+ if x1 > x2 or y1 > y2 then return end
+ local fillcolor = command.fill
+ if type(fillcolor) ~= "string" or string.len(fillcolor) > 7 or string.len(fillcolor) < 6 then fillcolor = "000000" end
+ if string.sub(fillcolor,1,1) == "#" then fillcolor = string.sub(fillcolor,2,7) end
+ if not tonumber(fillcolor,16) then fillcolor = "000000" end
+ local edgecolor = command.edge
+ if type(edgecolor) ~= "string" or string.len(edgecolor) > 7 or string.len(edgecolor) < 6 then edgecolor = fillcolor end
+ if string.sub(edgecolor,1,1) == "#" then edgecolor = string.sub(edgecolor,2,7) end
+ if not tonumber(edgecolor,16) then edgecolor = fillcolor end
+ for y=y1,y2,1 do
+ for x=x1,x2,1 do
+ buffer[y][x] = fillcolor
+ end
+ end
+ if fillcolor ~= edgecolor then
+ for x=x1,x2,1 do
+ buffer[y1][x] = edgecolor
+ buffer[y2][x] = edgecolor
+ end
+ for y=y1,y2,1 do
+ buffer[y][x1] = edgecolor
+ buffer[y][x2] = edgecolor
+ end
+ end
+ meta:set_string("buffer"..bufnum,minetest.serialize(buffer))
+ elseif command.command == "drawpoint" then
+ if type(command.buffer) ~= "number" or type(command.x) ~= "number" or type(command.y) ~= "number" then return end
+ local bufnum = math.floor(command.buffer)
+ if bufnum < 0 or bufnum > 7 then return end
+ local x = math.floor(command.x)
+ local y = math.floor(command.y)
+ if x < 1 or y < 1 then return end
+ local buffer = meta:get_string("buffer"..bufnum)
+ if string.len(buffer) == 0 then return end
+ buffer = minetest.deserialize(buffer)
+ if type(buffer) ~= "table" then return end
+ if x > buffer.xsize or y > buffer.ysize then return end
+ local color = command.color
+ if type(color) ~= "string" or string.len(color) > 7 or string.len(color) < 6 then color = "000000" end
+ if string.sub(color,1,1) == "#" then color = string.sub(color,2,7) end
+ if not tonumber(color,16) then color = "000000" end
+ buffer[y][x] = color
+ meta:set_string("buffer"..bufnum,minetest.serialize(buffer))
+ elseif command.command == "copy" then
+ if type(command.src) ~= "number" or type(command.dst) ~= "number" or type(command.srcx) ~= "number" or type(command.srcy) ~= "number" or type(command.dstx) ~= "number" or type(command.dsty) ~= "number" or type(command.xsize) ~= "number" or type(command.ysize) ~= "number" then return end
+ local src = math.floor(command.src)
+ if src < 0 or src > 7 then return end
+ local dst = math.floor(command.dst)
+ if dst < 0 or dst > 7 then return end
+ local srcx = math.floor(command.srcx)
+ local srcy = math.floor(command.srcy)
+ local dstx = math.floor(command.dstx)
+ local dsty = math.floor(command.dsty)
+ local xsize = math.floor(command.xsize)
+ local ysize = math.floor(command.ysize)
+ if srcx < 1 or srcy < 1 or dstx < 1 or dsty < 1 or xsize < 1 or ysize < 1 then return end
+ local sourcebuffer = meta:get_string("buffer"..src)
+ local destbuffer = meta:get_string("buffer"..dst)
+ if string.len(sourcebuffer) == 0 then return end
+ sourcebuffer = minetest.deserialize(sourcebuffer)
+ if type(sourcebuffer) ~= "table" then return end
+ if string.len(destbuffer) == 0 then return end
+ destbuffer = minetest.deserialize(destbuffer)
+ if type(destbuffer) ~= "table" then return end
+ if srcx + xsize-1 > sourcebuffer.xsize or srcy + ysize-1 > sourcebuffer.ysize then return end
+ if dstx + xsize-1 > destbuffer.xsize or dsty + ysize-1 > destbuffer.ysize then return end
+ local transparent = command.transparent
+ if type(transparent) ~= "string" or string.len(transparent) > 7 or string.len(transparent) < 6 then transparent = "000000" end
+ if string.sub(transparent,1,1) == "#" then transparent = string.sub(transparent,2,7) end
+ if not tonumber(transparent,16) then transparent = "000000" end
+ for y=0,xsize-1,1 do
+ for x=0,xsize-1,1 do
+ local srcpx = sourcebuffer[srcy+y][srcx+x]
+ local destpx = destbuffer[dsty+y][dstx+x]
+ destbuffer[dsty+y][dstx+x] = blend(srcpx,destpx,command.mode,transparent)
+ end
+ end
+ meta:set_string("buffer"..dst,minetest.serialize(destbuffer))
+ elseif command.command == "load" then
+ if type(command.buffer) ~= "number" or type(command.x) ~= "number" or type(command.y) ~= "number" or type(command.data) ~= "table" then return end
+ local bufnum = math.floor(command.buffer)
+ if bufnum < 0 or bufnum > 7 then return end
+ local xstart = math.floor(command.x)
+ local ystart = math.floor(command.y)
+ if xstart < 1 or ystart < 1 then return end
+ local buffer = meta:get_string("buffer"..bufnum)
+ if string.len(buffer) == 0 then return end
+ buffer = minetest.deserialize(buffer)
+ if type(buffer) ~= "table" then return end
+ if type(command.data[1]) ~= "table" then return end
+ if #command.data[1] < 1 then return end
+ local ysize = #command.data
+ local xsize = #command.data[1]
+ if xstart+xsize > buffer.xsize or ystart+ysize > buffer.ysize then return end
+ for y=1,ysize,1 do
+ if type(command.data[y]) == "table" then
+ for x=1,xsize,1 do
+ local color = command.data[y][x]
+ if type(color) == "string" then
+ if string.len(color) == 7 then color = string.sub(color,2,7) end
+ if tonumber(color,16) then
+ buffer[ystart+y-1][xstart+x-1] = color
+ end
+ end
+ end
+ end
+ end
+ meta:set_string("buffer"..bufnum,minetest.serialize(buffer))
+ elseif command.command == "text" then
+ if type(command.buffer) ~= "number" or type(command.x) ~= "number" or type(command.y) ~= "number" or type(command.text) ~= "string" or string.len(command.text) < 1 then return end
+ command.text = string.sub(command.text,1,16)
+ local bufnum = math.floor(command.buffer)
+ if bufnum < 0 or bufnum > 7 then return end
+ local x = math.floor(command.x)
+ local y = math.floor(command.y)
+ if x < 1 or y < 1 then return end
+ local buffer = meta:get_string("buffer"..bufnum)
+ if string.len(buffer) == 0 then return end
+ buffer = minetest.deserialize(buffer)
+ if type(buffer) ~= "table" then return end
+ if x > buffer.xsize or y > buffer.ysize then return end
+ local color = command.color
+ if type(color) ~= "string" or string.len(color) > 7 or string.len(color) < 6 then color = "ff6600" end
+ if string.sub(color,1,1) == "#" then color = string.sub(color,2,7) end
+ if not tonumber(color,16) then color = "ff6600" end
+ for i=1,string.len(command.text),1 do
+ local char = font[string.byte(string.sub(command.text,i,i))]
+ for chary=1,12,1 do
+ for charx=1,5,1 do
+ local startx = x + (i*6-6)
+ if char[chary][charx] and y+chary-1 <= buffer.ysize and startx+charx-1 <= buffer.xsize then
+ local dstpx = buffer[y+chary-1][startx+charx-1]
+ buffer[y+chary-1][startx+charx-1] = blend(color,dstpx,command.mode,"")
+ end
+ end
+ end
+ end
+ meta:set_string("buffer"..bufnum,minetest.serialize(buffer))
+ end
+end
+
+minetest.register_node("digistuff:gpu", {
+ description = "Digilines 2D Graphics Processor",
+ groups = {cracky=3},
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ meta:set_string("formspec","field[channel;Channel;${channel}")
+ end,
+ tiles = {
+ "digistuff_gpu_top.png",
+ "jeija_microcontroller_bottom.png",
+ "jeija_microcontroller_sides.png",
+ "jeija_microcontroller_sides.png",
+ "jeija_microcontroller_sides.png",
+ "jeija_microcontroller_sides.png"
+ },
+ inventory_image = "digistuff_gpu_top.png",
+ drawtype = "nodebox",
+ selection_box = {
+ --From luacontroller
+ type = "fixed",
+ fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
+ },
+ _digistuff_channelcopier_fieldname = "channel",
+ node_box = {
+ --From Luacontroller
+ type = "fixed",
+ fixed = {
+ {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab
+ {-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board
+ {-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC
+ }
+ },
+ paramtype = "light",
+ sunlight_propagates = true,
+ on_receive_fields = function(pos, formname, fields, sender)
+ local name = sender:get_player_name()
+ if minetest.is_protected(pos,name) and not minetest.check_player_privs(name,{protection_bypass=true}) then
+ minetest.record_protection_violation(pos,name)
+ return
+ end
+ local meta = minetest.get_meta(pos)
+ if fields.channel then meta:set_string("channel",fields.channel) end
+ end,
+ digiline =
+ {
+ receptor = {},
+ effector = {
+ action = function(pos,node,channel,msg)
+ local meta = minetest.get_meta(pos)
+ if meta:get_string("channel") ~= channel or type(msg) ~= "table" then return end
+ if type(msg[1]) == "table" then
+ for i=1,32,1 do
+ if type(msg[i]) == "table" then
+ runcommand(pos,meta,msg[i])
+ end
+ end
+ else
+ runcommand(pos,meta,msg)
+ end
+ end
+ },
+ },
+})
+
+minetest.register_craft({
+ output = "digistuff:gpu",
+ recipe = {
+ {"","default:steel_ingot",""},
+ {"digilines:wire_std_00000000","mesecons_luacontroller:luacontroller0000","digilines:wire_std_00000000"},
+ {"dye:red","dye:green","dye:blue"},
+ }
+})