Just bored. Check it out:
arrowkeys to move around, leftclick to zoom in, rightclick to zoom out.
I guess it's an alright demo of recursive functionality. It also has some useful functions for checking if something's on screen.
`set display mode 1280,800,32
`one w stands for one world unit
global retx as float
global rety as float
global PPW as float `base pixels per world unit
global camera_zoom as float `higher zoom is... well, more zoom. Everything looks BIGGGERRRRR!!!!
global zoomVal as float`camera zoom is exponential, this value is linear (easier to control). camera_zoom=2^zoomVal
`Actual PPW = PPW*2^camera_zoom
`basically, when camera_zoom is one, there are screen width()/PPW world units on screen.
`when camera zoom is two, there is half a world unit on the screen
`when camera zoom is 1/2, there are two world units on screen.
`0 camera zoom would have every world unit on the screen, and infinite camera zoom would have zero world units on screen.
global camera_x as float `position of the CENTER of the camera, in w
global camera_y as float `W
camera_x=0.0
camera_y=0.0
zoomVal=0
camera_zoom=1
PPW=100
sync rate 60
do
cls
d3d_batch_set_line2d 100000
if mouseclick()=1 then inc zoomVal, .05
if mouseclick()=2 then dec zoomVal, .05
camera_zoom=2^zoomVal
inc camera_x,(rightkey()-leftkey())/camera_zoom*.1
inc camera_y,(downkey()-upkey())/camera_zoom*.1
drawTri(0,0,10,0,5,-8.660254)
SierpinskiTriangle(0,0,10,0,5,-8.660254)
d3d_batch_draw_line2d 1
sync
loop
end
function SierpinskiTriangle(x1 as float, y1 as float,x2 as float, y2 as float, x3 as float, y3 as float)
n as boolean
n=lineIsOnScreen(x1,y1,x2,y2)
if n=0 then n=lineIsOnScreen(x2,y2,x3,y3)
if n=0 then n=lineIsOnScreen(x3,y3,x1,y1)
if n=0 then n=isInsideTriangle(x1,y1,x2,y2,x3,y3,camera_x,camera_y)
if n `make sure whatever is drawn will be at least partly visible
if (getSiez(x1,x2,x3)+getSiez(y1,y2,y3))*PPW*camera_zoom<4.0
drawTri(x1,y1,x2,y2,x3,y3)
else
x4 as float `----------1----------- 4 is the midpoint of 1 and 2
y4 as float `---------=-=---------- 5 is the midpoint of 2 and 3
x5 as float `--------=---=--------- 6 is the midpoint of 1 and 3
y5 as float `-------=-----=--------
x6 as float `------4=======6-------
y6 as float `-----=-=-----=-=------
`----=---=---=---=----- `so draw triangles (1,4,6),(2,4,5),(5,6,3)
`---=-----=-=-----=----
`--2=======5=======3---
x4=(x1+x2)/2
y4=(y1+y2)/2
x5=(x2+x3)/2
y5=(y2+y3)/2
x6=(x1+x3)/2
y6=(y1+y3)/2
sierpinskiTriangle(x1,y1,x6,y6,x4,y4)
sierpinskiTriangle(x2,y2,x4,y4,x5,y5)
sierpinskiTriangle(x3,y3,x5,y5,x6,y6)
`unless the triangle is the largest triangle, only the inside boundary (triangle 4,5,6) needs to be drawn.
`before calling this function, draw the largest triangle.
drawTri(x4,y4,x5,y5,x6,y6)
endif
endif
endfunction
function isInsideTriangle(x1 as float, y1 as float,x2 as float, y2 as float, x3 as float, y3 as float, x4 as float,y4 as float)
`points 1-3 are the triangle, point 4 is the one to be checked.
`http://mathworld.wolfram.com/TriangleInterior.html <- comprehensive guide to what is being done here
`basically, let p1 be one vertex of the triangle, and p2,p3 be the vectors from p1 to p2/p3 respectively.
`then, you can express p4 as p1+a*p2+b*p3. Treating the vectors as column matrices:
`a= (|p4 p3| - |p1 p3|)/(|p2 p3|)
`b=-(|p4 p2| - |p1 p2|)/(|p2 p3|)
c#=x2*y3-x3*y2
a#= (y3*(x4-x1)-x3*(y4-y1))
b#=-(y2*(x4-x1)-x2*(y4-y1))
if c#=0
if a#=0 and b#=0 then exitfunction 1
exitfunction 0
else
a#=a#/c#
b#=b#/c#
if a#>0 and b#>0 and a#+b#<1 then exitfunction 1
endif
endfunction 0
function drawTri(x1 as float, y1 as float,x2 as float, y2 as float, x3 as float, y3 as float)
transformPointToScreen(x1,y1)
x1=retx
y1=rety
transformPointToScreen(x2,y2)
x2=retx
y2=rety
transformPointToScreen(x3,y3)
x3=retx
y3=rety
d3d_batch_add_line2d x1,y1,x2,y2
d3d_batch_add_line2d x2,y2,x3,y3
d3d_batch_add_line2d x3,y3,x1,y1
endfunction
function lineIsOnScreen(x1 as float, y1 as float,x2 as float, y2 as float)
transformPointToScreen(x1,y1)
x1=retx
y1=rety
transformPointToScreen(x2,y2)
x2=retx
y2=rety
`store the leftmost point in x1,y1 and the rightmost in x2,y2
if x2<x1
x3#=x2
y3#=y2
x2=x1
y2=y1
x1=x3#
y1=y3#
endif
ax as integer
ay as integer
bx as integer
by as integer
ax=int(x1)
ay=int(y1)
bx=int(x2)
by=int(y2)
if bx<0 then exitfunction 0
if ax>screen width() then exitfunction 0
if ay>screen height() and by>screen height() then exitfunction 0
if ay<0 and by<0 then exitfunction 0
`^^no way those can intersect.
if ax>0 and ay>0 and ax<screen width() and ay<screen height() then exitfunction 1
if bx>0 and by>0 and bx<screen width() and by<screen height() then exitfunction 1
`^^one of the points is on screen, so part of the line has to be
if bx-ax<>0
m#=(by-ay)*1.0/(bx-ax)
b#=ay-m#*ax
if b#>0 and b#<screen height()
exitfunction 1 `the left screen intercept is onscreen
else
b#=m#*screen width()+b#
if b#>0 and b#<screen height() then exitfunction 1 `right screen intercept is onscreen
endif
endif
`no right intercept, no left intercept, neither points are on screen, but it's still possible part of the line is.
if by-ay<>0
m#=(bx-ax)*1.0/(by-ay)
b#=ax-m#*ay
if b#>0 and b#<screen height()
exitfunction 1 `bottom intercept is onscreen
else
b#=m#*screen height()+b#
if b#>0 and b#<screen height() then exitfunction 1 `top intercept is onscreen
endif
endif
endfunction 0
function transformPointToScreen(x as float, y as float)
width=screen width()
height=screen height()
retx=((x-camera_x)*(PPW*camera_zoom))+0.5*width
rety=((y-camera_y)*(PPW*camera_zoom))+0.5*height
`translate the point so that the camera is the origin, scale correctly
`add half the screen width/height because camera_x/y represents the center of the camera, not the top left or whatever.
endfunction
`getSize is reserved :\
function getSiez(x1 as float,x2 as float, x3 as float)
s#=minimum(x1,minimum(x2,x3))
l#=maximum(x1,maximum(x2,x3))
w#=l#-s#
endfunction w#
function maximum(a as float, b as float)
if a>b then exitfunction a
endfunction b
function minimum(a as float, b as float)
if a<b then exitfunction a
endfunction b
it uses d3dfunc lines You can remove these commands:
d3d_batch_set_line2d 100000
d3d_batch_draw_line2d 1
and replace any line that calls "d3d_batch_add_line2d" with "line", but it's very slow (dbpro built-in lines are very slow).
If you want to speed things up more, you can increase the value in this line:
if (getSiez(x1,x2,x3)+getSiez(y1,y2,y3))*PPW*camera_zoom<4.0
basically, it determines if the horizontal plus the vertical size of the triangle is less than four pixels. If it is, then it doesn't call the same function recursively.
As you zoom in a lot, the lines get jagged, and things start disappearing, and eventually the program crashes. Things get jagged because of floating point inaccuracies. Things start disappearing, probably because of rounding errors and if statements, and the program crashes probably because of a divide by zero, or passing in #inf into a function (int()?), but I haven't actually looked into either of those.
[edit]
shows floating point inaccuracies:
(You're at the edge of the map. Here be monsters)
Also, in case you're wondering why everything seems to hit a wall (speedwise) when you zoom in so close, it has to do with the way floats are processed. When a float is *almost* zero, it's very inaccurate... to account for the inaccuracies the floats are processed differently, and that's slower to process (I'm not sure why... either because the calculations are harder, or it's just not as well supported by most processors)