Compare commits

..

No commits in common. "f7170428c96a944e349db1be91d131fa5eabbe97" and "429706dae9f0292141af7481fcb95be34bfca747" have entirely different histories.

View File

@ -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
local settled=true for i=0,#self.ancs+1 do
local touched={} local a=self:_anc(i)
local loop=function(f) a.dirty=true
local a=0 end
while a<=#self.ancs+1 do
local anc=self:_anc(a) local a=0
if anc.dirty then while a<=#self.ancs+1 do
anc.seen=true local anc=self:_anc(a)
if self[f](self,a) then if anc.dirty and #anc.todo==0 then
settled=false anc.changed=true while not self.under_destruction and (
end self:_find_needed_anchors(a) or
end self:_find_touched_anchors(a) or
self:_elide_point(a)
) do end
anc.dirty=false
a=0
else
a+=1 a+=1
end end
end end
end
local mark_unseen=function() function rope:_drag1(
touched={} i,x,y
for a=0,#self.ancs+1,1 do )
local anc=self:_anc(a) local a_old=self:_anc(i)
anc.seen=false local a_new={x=x,y=y}
anc.changed=false if (_point_eq(a_old, a_new)) return
end
end a_old.x=x
a_old.y=y
local propagate_dirty=function(f)
for a=0,#self.ancs+1,1 do
local a1=self:_anc(a)
if a1.dirty then
local a0=self:_anc(a-1)
if (a0!=nil) a0.dirty=true
local a2=self:_anc(a+1)
if (a2!=nil) a2.dirty=true
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,8 +724,14 @@ 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
add(anchors_bydist,{el=a1,key=_linedist(a0,a1,a2)}) -- 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)})
end
end end
shellsort(anchors_bydist) shellsort(anchors_bydist)
@ -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
err-=dy add(queue,{x,y})
if (err<0) y+=sy err+=dx err-=dy
x+=sx if (err<0) y+=sy add(queue,{x,y}) err+=dx
return oldx,oldy x+=sx
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
local oldx,oldy=x,y if #queue==0 then
err-=dx add(queue,{x,y})
if (err<0) x+=sx err+=dy
y+=sy local oldx,oldy=x,y
return oldx,oldy err-=dx
if (err<0) x+=sx add(queue,{x,y}) err+=dy
y+=sy
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