forked from pyrex/chameleonic
Compare commits
No commits in common. "f7170428c96a944e349db1be91d131fa5eabbe97" and "429706dae9f0292141af7481fcb95be34bfca747" have entirely different histories.
f7170428c9
...
429706dae9
187
chameleonic.p8
187
chameleonic.p8
@ -214,17 +214,6 @@ function level:anchor_points()
|
|||||||
return pairs(self._anch)
|
return pairs(self._anch)
|
||||||
end
|
end
|
||||||
|
|
||||||
function level:anchors_in(px0,py0,px1,py1)
|
|
||||||
ancs={}
|
|
||||||
for ax=px0\4,(px1+3)\4 do
|
|
||||||
for ay=py0\4,(py1+3)\4 do
|
|
||||||
local anc=self._anch[_amix(ax,ay)]
|
|
||||||
if (anc!=nil) add(ancs, anc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ancs
|
|
||||||
end
|
|
||||||
|
|
||||||
function level:point_anchor(px,py)
|
function level:point_anchor(px,py)
|
||||||
local ax,ay=self:p2a(px,py)
|
local ax,ay=self:p2a(px,py)
|
||||||
local anc=self._anch[_amix(ax,ay)]
|
local anc=self._anch[_amix(ax,ay)]
|
||||||
@ -586,6 +575,7 @@ function rope:_make_consistent()
|
|||||||
)
|
)
|
||||||
|
|
||||||
if #self.latch.rec.todo==0 then
|
if #self.latch.rec.todo==0 then
|
||||||
|
self:_tidy_up_gen()
|
||||||
for i=0,#self.ancs do
|
for i=0,#self.ancs do
|
||||||
local a0=self:_anc(i)
|
local a0=self:_anc(i)
|
||||||
local a1=self:_anc(i+1)
|
local a1=self:_anc(i+1)
|
||||||
@ -675,83 +665,49 @@ function rope:drag(
|
|||||||
i,x,y
|
i,x,y
|
||||||
)
|
)
|
||||||
local anc=self:_anc(i())
|
local anc=self:_anc(i())
|
||||||
local busy=self:busy()
|
|
||||||
|
|
||||||
for x,y in self:_rast(
|
for x,y in self:_rast(
|
||||||
anc.x,anc.y,x,y
|
anc.x,anc.y,x,y
|
||||||
) do
|
) do
|
||||||
local a=self:_anc(i())
|
self:_drag1(i(),x,y)
|
||||||
if not (_point_eq(a,{x=x,y=y})) then
|
self:_tidy_up_gen()
|
||||||
a.x=x
|
|
||||||
a.y=y
|
|
||||||
a.dirty=true
|
|
||||||
self.dirty=true
|
|
||||||
if (not busy) self:_tidy_up_gen()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_tidy_up_gen()
|
function rope:_tidy_up_gen()
|
||||||
if (self.under_destruction) return
|
if (self:busy()) return
|
||||||
if (not self.dirty) return
|
|
||||||
|
for i=0,#self.ancs+1 do
|
||||||
|
local a=self:_anc(i)
|
||||||
|
a.dirty=true
|
||||||
|
end
|
||||||
|
|
||||||
local settled=true
|
|
||||||
local touched={}
|
|
||||||
local loop=function(f)
|
|
||||||
local a=0
|
local a=0
|
||||||
while a<=#self.ancs+1 do
|
while a<=#self.ancs+1 do
|
||||||
local anc=self:_anc(a)
|
local anc=self:_anc(a)
|
||||||
if anc.dirty then
|
if anc.dirty and #anc.todo==0 then
|
||||||
anc.seen=true
|
while not self.under_destruction and (
|
||||||
if self[f](self,a) then
|
self:_find_needed_anchors(a) or
|
||||||
settled=false anc.changed=true
|
self:_find_touched_anchors(a) or
|
||||||
end
|
self:_elide_point(a)
|
||||||
end
|
) do end
|
||||||
|
|
||||||
|
anc.dirty=false
|
||||||
|
a=0
|
||||||
|
else
|
||||||
a+=1
|
a+=1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local mark_unseen=function()
|
|
||||||
touched={}
|
|
||||||
for a=0,#self.ancs+1,1 do
|
|
||||||
local anc=self:_anc(a)
|
|
||||||
anc.seen=false
|
|
||||||
anc.changed=false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local propagate_dirty=function(f)
|
function rope:_drag1(
|
||||||
for a=0,#self.ancs+1,1 do
|
i,x,y
|
||||||
local a1=self:_anc(a)
|
)
|
||||||
if a1.dirty then
|
local a_old=self:_anc(i)
|
||||||
local a0=self:_anc(a-1)
|
local a_new={x=x,y=y}
|
||||||
if (a0!=nil) a0.dirty=true
|
if (_point_eq(a_old, a_new)) return
|
||||||
|
|
||||||
local a2=self:_anc(a+1)
|
a_old.x=x
|
||||||
if (a2!=nil) a2.dirty=true
|
a_old.y=y
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
while true do
|
|
||||||
settled=true
|
|
||||||
|
|
||||||
mark_unseen()
|
|
||||||
propagate_dirty()
|
|
||||||
|
|
||||||
loop("_find_needed_anchors")
|
|
||||||
loop("_find_touched_anchors")
|
|
||||||
loop("_elide_point")
|
|
||||||
|
|
||||||
for a=0,#self.ancs+1,1 do
|
|
||||||
local anc=self:_anc(a)
|
|
||||||
if (anc.seen) anc.dirty=anc.changed
|
|
||||||
end
|
|
||||||
|
|
||||||
if (settled) break
|
|
||||||
end
|
|
||||||
|
|
||||||
self.dirty=false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_find_needed_anchors(i)
|
function rope:_find_needed_anchors(i)
|
||||||
@ -768,9 +724,15 @@ function rope:_find_needed_anchors(i)
|
|||||||
local anchors_bydist={}
|
local anchors_bydist={}
|
||||||
local x0,x2=_mnmx(a0.x,a2.x)
|
local x0,x2=_mnmx(a0.x,a2.x)
|
||||||
local y0,y2=_mnmx(a0.y,a2.y)
|
local y0,y2=_mnmx(a0.y,a2.y)
|
||||||
for a1 in all(level:anchors_in(x0-1,y0-1,x2+1,y2+1)) do
|
for _,a1 in level:anchor_points() do
|
||||||
|
-- the new anchor point must be in the bounding box
|
||||||
|
-- of the old line
|
||||||
|
-- note: this fudge never turned out necessary
|
||||||
|
-- i just would be ok with it
|
||||||
|
if x0-1<=a1.x and a1.x<=x2+1 and y0-1<=a1.y and a1.y<=y2+1 then
|
||||||
add(anchors_bydist,{el=a1,key=_linedist(a0,a1,a2)})
|
add(anchors_bydist,{el=a1,key=_linedist(a0,a1,a2)})
|
||||||
end
|
end
|
||||||
|
end
|
||||||
shellsort(anchors_bydist)
|
shellsort(anchors_bydist)
|
||||||
|
|
||||||
for a1 in all(anchors_bydist) do
|
for a1 in all(anchors_bydist) do
|
||||||
@ -779,9 +741,11 @@ function rope:_find_needed_anchors(i)
|
|||||||
self:_can_stretch(a1,a2)
|
self:_can_stretch(a1,a2)
|
||||||
then
|
then
|
||||||
local id=self.id
|
local id=self.id
|
||||||
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
|
add(self.ancs,{id=id,x=a1.x,y=a1.y,todo={}},i)
|
||||||
self.id+=1
|
self.id+=1
|
||||||
|
|
||||||
|
self:_anc(i-1).dirty=true
|
||||||
|
self:_anc(i+1).dirty=true
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -794,20 +758,19 @@ function rope:_find_touched_anchors(i)
|
|||||||
local a0=self:_anc(i-1)
|
local a0=self:_anc(i-1)
|
||||||
local a2=self:_anc(i)
|
local a2=self:_anc(i)
|
||||||
|
|
||||||
if (level:pcoll(a0.x,a0.y)) return false
|
|
||||||
if (level:pcoll(a2.x,a2.y)) return false
|
|
||||||
|
|
||||||
for bx,by in self:_rast(a0.x,a0.y,a2.x,a2.y) do
|
for bx,by in self:_rast(a0.x,a0.y,a2.x,a2.y) do
|
||||||
local a1=level:point_anchor(bx,by)
|
local a1=level:point_anchor(bx,by)
|
||||||
if
|
if a1!=nil and not _point_eq(a0,a1) and not _point_eq(a1,a2)
|
||||||
a1!=nil and not _point_eq(a0,a1) and not _point_eq(a1,a2)
|
and _linedist(a0,a1,a2) < 0.01
|
||||||
and _linedist(a0,a1,a2) == 0.0
|
|
||||||
-- and self:_can_stretch(p,a2)
|
-- and self:_can_stretch(p,a2)
|
||||||
then
|
then
|
||||||
local id=self.id
|
local id=self.id
|
||||||
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
|
add(self.ancs,{id=id,x=a1.x,y=a1.y,todo={}},i)
|
||||||
self.id+=1
|
self.id+=1
|
||||||
|
|
||||||
|
self:_anc(i-1).dirty=true
|
||||||
|
self:_anc(i+1).dirty=true
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -845,15 +808,12 @@ function rope:_elide_point(i)
|
|||||||
end
|
end
|
||||||
|
|
||||||
deli(self.ancs,i)
|
deli(self.ancs,i)
|
||||||
|
self:_anc(i-1).dirty=true
|
||||||
|
self:_anc(i).dirty=true
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
|
function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
|
||||||
if (level:pcoll(a0.x,a0.y)) return false
|
|
||||||
if (level:pcoll(a2.x,a2.y)) return false
|
|
||||||
if (level:pcoll(a1_0.x,a1_0.y)) return false
|
|
||||||
if (level:pcoll(a1_1.x,a1_1.y)) return false
|
|
||||||
|
|
||||||
if not self:_can_stretch(a1_0, a1_1) then
|
if not self:_can_stretch(a1_0, a1_1) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -863,7 +823,7 @@ function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
|
|||||||
if not self:_can_stretch(a1_1,a2) then
|
if not self:_can_stretch(a1_1,a2) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
for x,y in self:_rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do
|
for x,y in self:_rastm(a1_0.x,a1_0.y,a1_1.x,a1_1.y) do
|
||||||
local tm={x=x,y=y}
|
local tm={x=x,y=y}
|
||||||
if not self:_can_stretch(a0,tm) then
|
if not self:_can_stretch(a0,tm) then
|
||||||
return false
|
return false
|
||||||
@ -919,26 +879,11 @@ end
|
|||||||
function rope:_can_stretch(
|
function rope:_can_stretch(
|
||||||
p1,p2
|
p1,p2
|
||||||
)
|
)
|
||||||
-- faster implementation for straight lines
|
|
||||||
if p1.y\8==p2.y\8 then
|
|
||||||
local my=p2.y\8
|
|
||||||
for mx=p1.x\8,p2.x\8 do
|
|
||||||
if (level:mcoll(mx,my)) return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if p1.x\8==p2.x\8 then
|
|
||||||
local mx=p2.x\8
|
|
||||||
for my=p1.y\8,p2.y\8 do
|
|
||||||
if (level:mcoll(mx,my)) return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (level:pcoll(p1.x,p1.y)) return false
|
if (level:pcoll(p1.x,p1.y)) return false
|
||||||
if (level:pcoll(p2.x,p2.y)) return false
|
if (level:pcoll(p2.x,p2.y)) return false
|
||||||
|
|
||||||
local res=true
|
local res=true
|
||||||
for x,y in self:_rastn(p1.x,p1.y,p2.x,p2.y,8,8) do
|
for x,y in self:_rastm(p1.x,p1.y,p2.x,p2.y) do
|
||||||
if level:pcoll(x,y) then
|
if level:pcoll(x,y) then
|
||||||
res=false
|
res=false
|
||||||
break
|
break
|
||||||
@ -948,8 +893,8 @@ function rope:_can_stretch(
|
|||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_rastn(
|
function rope:_rastm(
|
||||||
x0,y0,x1,y1,dx,dy
|
x0,y0,x1,y1
|
||||||
)
|
)
|
||||||
-- todo: more optimized implementation?
|
-- todo: more optimized implementation?
|
||||||
local iter=self:_rast(x0,y0,x1,y1)
|
local iter=self:_rast(x0,y0,x1,y1)
|
||||||
@ -962,8 +907,8 @@ function rope:_rastn(
|
|||||||
|
|
||||||
if (x==nil) done=true return x1, y1
|
if (x==nil) done=true return x1, y1
|
||||||
|
|
||||||
local x8 = x\dx
|
local x8 = x\8
|
||||||
local y8 = y\dy
|
local y8 = y\8
|
||||||
if not (x8==prevx and y8==prevy) then
|
if not (x8==prevx and y8==prevy) then
|
||||||
prevx,prevy=x8,y8
|
prevx,prevy=x8,y8
|
||||||
return x,y
|
return x,y
|
||||||
@ -986,27 +931,34 @@ function rope:_rast(
|
|||||||
if (y0<y1) sy=1
|
if (y0<y1) sy=1
|
||||||
|
|
||||||
local done=false,err
|
local done=false,err
|
||||||
|
local queue={}
|
||||||
if dx>dy then
|
if dx>dy then
|
||||||
err=dx/2.0
|
err=dx/2.0
|
||||||
return function()
|
return function()
|
||||||
if (done) return
|
if (queue==nil) return
|
||||||
if (x==x1) done=true return x1,y1
|
if (x==x1) queue=nil return x1,y1
|
||||||
local oldx,oldy=x,y
|
if #queue==0 then
|
||||||
|
add(queue,{x,y})
|
||||||
err-=dy
|
err-=dy
|
||||||
if (err<0) y+=sy err+=dx
|
if (err<0) y+=sy add(queue,{x,y}) err+=dx
|
||||||
x+=sx
|
x+=sx
|
||||||
return oldx,oldy
|
end
|
||||||
|
return unpack(deli(queue,1))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
err=dy/2.0
|
err=dy/2.0
|
||||||
return function()
|
return function()
|
||||||
if (done) return
|
if (queue==nil) return
|
||||||
if (y==y1) done=true return x1,y1
|
if (y==y1) queue=nil return x1,y1
|
||||||
|
if #queue==0 then
|
||||||
|
add(queue,{x,y})
|
||||||
|
|
||||||
local oldx,oldy=x,y
|
local oldx,oldy=x,y
|
||||||
err-=dx
|
err-=dx
|
||||||
if (err<0) x+=sx err+=dy
|
if (err<0) x+=sx add(queue,{x,y}) err+=dy
|
||||||
y+=sy
|
y+=sy
|
||||||
return oldx,oldy
|
end
|
||||||
|
return unpack(deli(queue,1))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1082,7 +1034,7 @@ function rope:_tug()
|
|||||||
if force or not level:pcoll(x,y) then
|
if force or not level:pcoll(x,y) then
|
||||||
s.x=x
|
s.x=x
|
||||||
s.y=y
|
s.y=y
|
||||||
self.dirty=true
|
s.dirty=true
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end}
|
end}
|
||||||
@ -1096,6 +1048,7 @@ function rope:_tug()
|
|||||||
end
|
end
|
||||||
for node=ancs[i-1].ix-1,ancs[i].ix+1 do
|
for node=ancs[i-1].ix-1,ancs[i].ix+1 do
|
||||||
local anc=self:_anc(node)
|
local anc=self:_anc(node)
|
||||||
|
if (anc!=nil) anc.dirty=true
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -1135,8 +1088,6 @@ function rope:_tug()
|
|||||||
mx0,my0,
|
mx0,my0,
|
||||||
dmx,dmy
|
dmx,dmy
|
||||||
)
|
)
|
||||||
-- be busy for 4 ticks while the crate moves
|
|
||||||
self:_anc(0).todo={{},{},{},{}}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user