-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathpx9_comp.lua
159 lines (127 loc) · 2.26 KB
/
px9_comp.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
-- px9 compress
-- by zep
-- x0,y0 where to read from
-- w,h image width,height
-- dest address to store
-- vget read function (x,y)
function
px9_comp(x0,y0,w,h,dest,vget)
local dest0=dest
local bit=1
local byte=0
local function vlist_val(l, val)
-- find positon
for i=1,#l do
if l[i] == val then
-- jump to top
for j=i,2,-1 do
l[j]=l[j-1]
end
l[1] = val
return i
end
end
end
function putbit(bval)
if (bval) byte+=bit
poke(dest, byte) bit<<=1
if (bit==256) then
bit=1 byte=0
dest += 1
end
end
function putval(val, bits)
for i=0,bits-1 do
putbit(val&1<<i > 0)
end
end
function putnum(val)
local bits = 0
repeat
bits += 1
local mx=(1<<bits)-1
local vv=min(val,mx)
putval(vv,bits)
val -= vv
until vv<mx
end
-- first_used
local el={}
local found={}
local highest=0
for y=y0,y0+h-1 do
for x=x0,x0+w-1 do
c=vget(x,y)
if not found[c] then
found[c]=true
add(el,c)
highest=max(highest,c)
end
end
end
-- header
local bits=1
while highest >= 1<<bits do
bits+=1
end
putnum(w-1)
putnum(h-1)
putnum(bits-1)
putnum(#el-1)
for i=1,#el do
putval(el[i],bits)
end
-- data
local pr={} -- predictions
local dat={}
for y=y0,y0+h-1 do
for x=x0,x0+w-1 do
local v=vget(x,y)
local a=0
if (y>y0) a+=vget(x,y-1)
-- create vlist if needed
local l=pr[a]
if not l then
l={}
for i=1,#el do
l[i]=el[i]
end
pr[a]=l
end
-- add to vlist
add(dat,vlist_val(l,v))
-- and to running list
vlist_val(el, v)
end
end
-- write
-- store bit-0 as runtime len
-- start of each run
local nopredict
local pos=1
while pos <= #dat do
-- count length
local pos0=pos
if nopredict then
while dat[pos]!=1 and pos<=#dat do
pos+=1
end
else
while dat[pos]==1 and pos<=#dat do
pos+=1
end
end
local splen = pos-pos0
putnum(splen-1)
if nopredict then
-- values will all be >= 2
while pos0 < pos do
putnum(dat[pos0]-2)
pos0+=1
end
end
nopredict=not nopredict
end
if (bit!=1) dest+=1 -- flush
return dest-dest0
end