# OpenComputers Graphics Lib

Sep 22nd, 2020 (edited)
266
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. local Graphics = {version=6}
2. local gpu = require'component'.gpu
3. local unicode = require'unicode'
4.
5. local function expect(v,...)
6.   local exp = {...}
7.   local got = type(v)
8.   local tx  = ''
9.   local ok  = false
10.   for i,v in ipairs(exp) do
11.     tx=tx..v
12.     if not(i>=#exp) then
13.       tx=tx..' or '
14.     end
15.     if got==v then
16.       ok=true
17.     end
18.   end
19.   return ok , ('Expected '..tx..', but got '..got)
20. end
21. local function getIndex(x,y,w)
22.   return w*(y-1)+x
23. end
24. local function getXY(i,w)
25.   local x=(i-1)%w+1
26.   return x,(i-x)/w+1
27. end
28. --local y=math.floor(i/(w+1))
29. --return ((i-1)%w)+1,y+1  --OLD CODE
30.
31. local function cn(v)
32.   if type(v)=='number' then
33.     return v
34.   elseif v then
35.     return 1
36.   else
37.     return 0
38.   end
39. end
40. local function toBits(num,bits)
41.   local t={}
42.   for b = bits, 1, -1 do
43.     t[b] = math.fmod(num, 2)
44.     num = math.floor((num - t[b]) / 2)
45.   end
46.   return t
47. end
48.
49.
50. local cstack={}
51. local function pushColor()
52.   table.insert(cstack,{gpu.getBackground(),gpu.getForeground()})
53. end
54. local function popColor()
55.   local bg,fg=table.unpack(table.remove(cstack))
56.   gpu.setBackground(bg)
57.   gpu.setForeground(fg)
58. end
59.
60. function Graphics:getWidth()
61.   assert(expect(self,'table'))
62.   return self.w*2
63. end
64.
65. function Graphics:getHeight()
66.   assert(expect(self,'table'))
67.   return self.h*4
68. end
69.
70. function Graphics:getDimensions()
71.   assert(expect(self,'table'))
72.   return self:getWidth(),self:getHeight()
73. end
74.
75. function Graphics:_px(x,y,v)
76.   assert(expect(self,'table'))
77.   assert(expect(x,'number'))
78.   assert(expect(y,'number'))
79.   --assert(expect(v,'number','boolean','nil'))
80.
81.   local w,h=self:getDimensions()
82.   if not(x>w or x<1 or y>h or y<1)then
83.     local ew,eh=2,4
84.     local fx,fy=math.ceil(x/ew),math.ceil(y/eh)
85.     local lx,ly=x-(fx-1)*ew,y-(fy-1)*eh
86.     local iA,iB=getIndex(fx,fy,self.w),getIndex(ly,lx,eh)
87.     if v~=nil then
88.       local oldv=self.s[iA][iB]
89.       local newv=cn(v)
90.       if not(oldv==newv) then
91.         self.s[iA][iB]=newv
92.         self.u[iA]=true
93.       end
94.     else
95.       return self.s[iA][iB]
96.     end
97.   end
98. end
99.
100. function Graphics:setPixel(x,y,v)
101.   if v==nil then v=false end
102.   self:_px(x,y,v)
103. end
104.
105. function Graphics:getPixel(x,y)
106.   return self:_px(x,y,nil)
107. end
108.
109. function Graphics:fastLine(x,y,vx,vy,l,rem)
110.   assert(expect(self,'table'))
111.   assert(expect(x ,'number')) assert(expect(y ,'number'))
112.   assert(expect(vx,'number')) assert(expect(vy,'number'))
113.   assert(expect(l ,'number'))
114.   for i=0,l do
115.     self:setPixel(
116.       math.ceil(x+i*vx),
117.       math.ceil(y+i*vy),
118.       not(rem)
119.     )
120.   end
121. end
122.
123. function Graphics:oldLine(x1,y1,x2,y2,rem)
124.   assert(expect(self,'table'))
125.   assert(expect(x1,'number')) assert(expect(x2,'number'))
126.   assert(expect(y1,'number')) assert(expect(y2,'number'))
127.   local a=math.atan2(x1-x2,y1-y2)
128.   local vx,vy=-math.sin(a),-math.cos(a)
129.   local l=math.sqrt((x2-x1)^2+(y2-y1)^2)
130.   self:fastLine(x1,y1,vx,vy,l,rem)
131. end
132.
133. function Graphics:drawLine(x1,y1,x2,y2,rem)
134.   assert(expect(self,'table'))
135.   assert(expect(x1,'number')) assert(expect(x2,'number'))
136.   assert(expect(y1,'number')) assert(expect(y2,'number'))
137.   y1,y2=y1+1,y2+1
138.   local dx = math.abs(x2-x1)
139.     local dy = -math.abs(y2-y1)
140.   local sx,sy
141.     if x1<x2 then
142.         sx=1
143.     else
144.         sx=-1
145.     end
146.     if y1<y2 then
147.         sy=1
148.     else
149.         sy=-1
150.     end
151.   local err = dx+dy
152.   while true do
153.     self:setPixel(x1,y1,not(rem))
154.     if x1==x2 and y1==y2 then
155.             break
156.         end
157.     local e2 = 2*err
158.     if e2 >= dy then
159.       err = err+dy
160.       x1 = x1+sx
161.     end
162.     if e2 <= dx then
163.       err = err+dx
164.       y1 = y1+sy
165.     end
166.   end
167. end
168.
169. local function fixRect(x,y,w,h)
170.   if w<0 then
171.     x,w=x+w,math.abs(w)
172.   end
173.   if h<0 then
174.     y,h=y+h,math.abs(h)
175.   end
176.   return x,y,w,h
177. end
178.
179. function Graphics:drawRect(x,y,w,h,fill,rem)
180.   assert(expect(self,'table'))
181.   assert(expect(x,'number')) assert(expect(y,'number'))
182.   assert(expect(w,'number')) assert(expect(h,'number'))
183.   x,y,w,h=fixRect(x,y,w,h)
184.   if fill then
185.     for i=0,w-1 do
186.       for j=0,h-1 do
187.         self:setPixel(x+i,y+j,not(rem))
188.       end
189.     end
190.   else
191.     self:fastLine(x,y,1,0,w-1,rem)--top
192.     self:fastLine(x,y+h-1,1,0,w-1,rem)--bottom
193.     self:fastLine(x,y,0,1,h-1,rem)--left
194.     self:fastLine(x+w-1,y,0,1,h-1,rem)--right
195.   end
196. end
197.
198. local Sprite={}
199.
200. function Sprite:getWidth()
201.   assert(expect(self,'table'))
202.   return self.w
203. end
204.
205. function Sprite:getHeight()
206.   assert(expect(self,'table'))
207.   return self.h
208. end
209.
210. function Sprite:getDimensions()
211.   assert(expect(self,'table'))
212.   return Sprite:getWidth(),Sprite:getHeight()
213. end
214.
215. --TODO SPRITE SET PIX/GET PIX
216.
217. function Graphics:newSprite(spriteData)
218.   assert(expect(spriteData,'string'))
219.   local t={
220.     w=spriteData:byte(1),
221.     h=spriteData:byte(2),
222.     data={}
223.   }
224.   local d={spriteData:byte(3,#spriteData)}
225.   for i=1,#d do
226.     local b=toBits(d[i],8)
227.     for j=1,#b do
228.       if #t.data<=t.w*t.h then
229.         t.data[#t.data+1]=(b[j]==1)
230.       else
231.         break
232.       end
233.     end
234.   end
235.   setmetatable(t,{__index=Sprite})
236.   return t
237. end
238.
239. function Graphics:drawSprite(sprite,x,y)
240.   assert(expect(self,'table'))
241.   assert(expect(x,'number'))
242.   assert(expect(y,'number'))
243.   local px,py=0,0
244.   local d=sprite.data
245.   for i=1,#d do
246.     self:setPixel(x+px,y+py,d[i])
247.     px=px+1
248.     if px>=sprite.w then
249.       px=0
250.       py=py+1
251.     end
252.   end
253. end
254.
255. function Graphics:_draw(i,x,y,shd)
256.   x=x or 0
257.   y=y or 0
258.
259.   pushColor()
260.   local v=self.s[i]
261.   local xp,yp=getXY(i,self.w)
262.   local sxp,syp=xp+x,yp+y
263.   local gw,gh=gpu.getResolution()
264.
265.   local r=false
266.
267.   if sxp>=1 and syp>=1 and sxp<=gw and syp<=gh then
268.     local schr,sfg,sbg=gpu.get(sxp,syp)
269.     local chr=self:char(v)
270.     local fg,bg=table.unpack(v.color)
271.     if chr~=schr or sfg~=fg or sbg~=bg then --:gsub(' ','')
272.       gpu.setForeground(fg)
273.       gpu.setBackground(bg)
274.       gpu.set(sxp,syp,chr)
275.       r=true
276.     end
277.   end
278.   popColor()
279.   return r
280. end
281.
282. function Graphics:redraw(x,y,shd)
283.   assert(expect(self,'table'))
284.   assert(expect(x,'number','nil'))
285.   assert(expect(y,'number','nil'))
286.   assert(expect(shd,'function','nil'))
287.   for i=1,self.w*self.h do --old
288.     self:_draw(i,x,y,shd)
289.   end
290. end
291.
292. function Graphics:draw(x,y)
293.   assert(expect(self,'table'))
294.   assert(expect(x,'number','nil'))
295.   assert(expect(y,'number','nil'))
296.   for i,v in next,self.u do
297.     self:_draw(i,x,y)
298.   end
299.   self.u={}
300. end
301.
302. function Graphics:_reset(UPUSH)
303.   self.u={}
304.   for i=1,self.w*self.h do
305.     if UPUSH and self:char(self.s[i])~=' ' then
306.       self.u[i]=true
307.     end
308.     self.s[i]={
309.       0,0,0,0,0,0,0,0,
310.       color={0xFFFFFF,0x000000}
311.     }
312.   end
313. end
314.
315. function Graphics:reset()
316.   assert(expect(self,'table'))
317.   self:_reset(true)
318. end
319.
320. function Graphics:char(s)
321.   assert(expect(s,'table'))
322.   local n=s[1]+s[2]*2+s[3]*4+s[4]*64+s[5]*8+s[6]*16+s[7]*32+s[8]*128
323.   --local n=tonumber(table.concat(s):reverse(),2)
324.   if n>0 then
325.     return unicode.char(10240+n)
326.   else
327.     return ' '
328.   end
329. end
330.
331. function Graphics:new(w,h)
332.   assert(expect(self,'table'))
333.   assert(expect(w,'number','nil'))
334.   assert(expect(h,'number','nil'))
335.
336.   local gpuw,gpuh=gpu.getResolution()
337.   w,h = w or gpuw, h or gpuh
338.
339.   local g={
340.     w=w,
341.     h=h,
342.     u={},
343.     s={}
344.   }
345.   setmetatable(g,{__index=Graphics})
346.   g:_reset()
347.   return g
348. end
349.
350. return setmetatable(
351.   Graphics,
352.   {
353.     __call=Graphics.new,
354.     __newindex=function()end
355.   }
356. )