Yep - server was down for quite a while. Anyway, I added a fade out effect for the shadows as shown.
Final update for this challenge:
`Modeller by Ric.
`Thanks to CPU for the 3d mouse function :)
set display mode 800,600,32
backdrop on
color backdrop 0
autocam off
sync on
position camera 64,30,-64
hide light 0
make light 1
numberoflights=1
position light 1,0,30,0
make object cube 1,1
hide object 1
Make Object plain 2,128,128
Position Object 2,64,0,64
xrotate object 2,-90
grid=free_image()
ink rgb(255,255,255),0
box 0,0,500,500
ink rgb(200,200,200),0
for x=0 to 500 step 20
for y=0 to 500 step 20
box x,y,x+10,y+10
next y
next x
get image grid,0,0,500,500
texture object 2,grid
whitesquare=free_sprite()
ink rgb(255,255,255),0
box 0,0,42,42
get image whitesquare,0,0,42,42
sprite whitesquare,324,44,whitesquare
gosub make_texture_sprites
type objecttype
scalex as float
scaley as float
scalez as float
texture as integer
typeofobject as string
endtype
type TYPE_XYZfloat
x as float
y as float
z as float
endtype
global GU_XYZReturn as TYPE_XYZfloat
global mx#
global my#
global create
make camera 1
color backdrop 1,rgb(0,0,0)
position camera 1,64,90,64
point camera 1,64,0,64
set camera view 1,80,40,screen width()/2-80,190
make camera 2
color backdrop 2,rgb(100,100,100)
position camera 2,64,0.1,-10
point camera 2,64,0,64
set camera view 2,screen width()/2+80,40,screen width()-80,190
set current camera 0
textureobject=free_sprite()
make_button(textureobject,"apply texture",131,20,324,160)
empty=free_sprite()
make_button(empty,"",630,28,86,6)
set sprite diffuse empty,200,200,250
cube=free_sprite()
make_button(cube,"cube",50,20,50+40,10)
box_=free_sprite()
make_button(box_,"box",50,20,102+40,10)
sphere=free_sprite()
make_button(sphere,"sphere",50,20,154+40,10)
cone=free_sprite()
make_button(cone,"cone",50,20,206+40,10)
cylinder=free_sprite()
make_button(cylinder,"cylinder",50,20,258+40,10)
lights=free_sprite()
make_button(lights,"lights",50,20,310+40,10)
shadows=free_sprite()
make_button(shadows,"shadows",50,20,362+40,10)
position=free_sprite()
make_button(position,"position",50,20,414+40,10)
scale=free_sprite()
make_button(scale,"scale",50,20,466+40,10)
rotate=free_sprite()
make_button(rotate,"rotate",50,20,518+40,10)
load=free_sprite()
make_button(load,"load",50,20,570+40,10)
save=free_sprite()
make_button(save,"save",50,20,622+40,10)
set sprite diffuse position,200,200,200
operation=position
positionon=1
ink rgb(0,255,0),0
do
mx#=mousemovex()
my#=mousemovey()
3dmouse()
3dcamera()
line 0,200,screen width(),200
gosub process_events
text 0,0,str$(excludero)
sync
loop
function make_button(spritenumber,btext$,bwidth#,bheight#,bx,by)
create bitmap 1,screen width(),screen height()
for n#=0.0 to bheight#
grey#=(140*n#/bheight#)+100
ink rgb(grey#,grey#,grey#),0
line 0,n#,bwidth#,n#
next n#
for n#=2.0 to bheight#-2
grey#=(140-140*n#/bheight#)+100
ink rgb(grey#,grey#,grey#),0
line 2,n#,bwidth#-2,n#
next n#
ink rgb(255,255,255),0
set text font "arial"
set text size 12
text bwidth#/2.0-text width(btext$)/2,bheight#/2.0-text height(btext$)/2.0,btext$
get image spritenumber,0,0,bwidth#,bheight#,1
delete bitmap 1
sprite spritenumber,bx,by,spritenumber
endfunction
function free_sprite
repeat
inc n
until sprite exist(n)=0 and image exist(n)=0
endfunction n
function pick_sprite(lower,upper)
for spritenumber=lower to upper
if mousex()>=sprite x(spritenumber) and mousex()<=sprite x(spritenumber)+sprite width(spritenumber) and mousey()>=sprite y(spritenumber) and mousey()<=sprite y(spritenumber)+sprite height(spritenumber)
pick=spritenumber
endif
next spritenumber
endfunction pick
function pick_sized_sprite(lower,upper,width,height)
for spritenumber=lower to upper
if mousex()>=sprite x(spritenumber) and mousex()<=sprite x(spritenumber)+width and mousey()>=sprite y(spritenumber) and mousey()<=sprite y(spritenumber)+height
pick=spritenumber
endif
next spritenumber
endfunction pick
process_events:
`button click events
pick=pick_sprite(cube,shadows)
if pick>0 and pick<=lights and mouseclick()=1
selection=pick
gosub reset_buttons
set sprite diffuse selection,200,200,200
create=1
endif
if mouseclick()=1 and pick_sprite(save,save)=save then gosub savescene
if mouseclick()=1 and pick_sprite(load,load)=load then gosub loadscene
if create=1 then gosub create_object
if pick=shadows and mouseclick()=1
gosub reset_buttons
if light1>0 then gosub calculate_shadows
endif
if mouseclick()>0
operation=pick_sprite(position,rotate)
if operation>0
gosub reset_operations
set sprite diffuse operation,200,200,200
if operation=position then positionon=1
if operation=scale then scaleon=1
if operation=rotate then rotateon=1
endif
endif
if mouseclick()=0
excludero=0
excludeso=0
excluderoto=0
if object>0
if object exist(object) and object<>light1 and object<>light2 then set object light object,1
endif
endif
`texture selection
if mouseclick()=1
if pick_sized_sprite(grass,red,40,40)>0 then texture=pick_sized_sprite(grass,red,40,40)
if texture>0 then sprite whitesquare,sprite x(texture)-1,sprite y(texture)-1,whitesquare
if pick_sprite(textureobject,textureobject)>0 and texture>0 then gosub reset_operations:applytexture=1:set sprite diffuse textureobject,200,200,200
endif
`object click events
pickobject=pick object(mousex(),mousey(),3,numberofobjects+2)
if mouseclick()>0 and mouseclick()<3 and exclude=0 and pickobject>2 then picked=pickobject:exclude=1:set object light picked,0
if mouseclick()=0 and picked>2 then exclude=0:set object light picked,1:picked=0
if picked>2 and mouseclick()<3
if positionon=1 then gosub reposition_object
if rotateon=1 then gosub rotate_object
if scaleon=1 then gosub scale_object
if applytexture=1
gosub apply_texture
endif
endif
return
apply_texture:
texture object picked,texture
object(picked).texture=texture
return
reset_operations:
scaleon=0
rotateon=0
positionon=0
applytexture=0
for n=position to rotate
set sprite diffuse n,255,255,255
next n
set sprite diffuse textureobject,255,255,255
return
reset_buttons:
for spritenumber=cube to shadows
set sprite diffuse spritenumber,255,255,255
next spritenumber
return
rotate_object:
object=picked
if create=0
`set cursor to object position first time only
if excluderoto=0
excluderoto=1
position object 1,object position x(object),object position y(object),object position z(object)
endif
if object<>light1 and object<>light2
if mouseclick()=1
turn object right object,mx#
pitch object up object,-my#
endif
if mouseclick()=2
roll object right object,-my#
endif
endif
if mouseclick()=0
excluderoto=0
if object<>light1 and object<>light2 then set object light object,1
endif
endif
return
function free_object
repeat
inc n
until object exist(n)=0
endfunction n
Function 3dmouse()
`left mouse moves in the XZ direction
if create=1 or mouseclick()=1
SYS_screenToXZ(mousex(), mousey(), 0, object position y(1))
position object 1, GU_XYZReturn.x, GU_XYZReturn.y, GU_XYZReturn.z
else
`right mouse moves in the Y direction
if mouseclick() = 2
tmp# = SYS_screenToY(mousex(), mousey(), 0, object position x(1), object position z(1))
position object 1, object position x(1), tmp#, object position z(1)
endif
endif
EndFunction
function 3dcamera
if upkey()=1 then move camera 0.2
if downkey()=1 then move camera -0.2
if leftkey()=1 then turn camera left 90:move camera 0.2:turn camera right 90
if rightkey()=1 then turn camera right 90:move camera 0.2:turn camera left 90
if mouseclick()=3 then turn camera right mx#/2.0
endfunction
create_object:
position object 1,object position x(1),0,object position z(1)
if mousey()>200 and mouseclick()=1
inc numberofobjects
dim object(numberofobjects+2) as objecttype
object=free_object()
if selection=cube then make object cube object,5:object(object).typeofobject="cube"
if selection=box_ then make object box object,5,20,5:object(object).typeofobject="box"
if selection=sphere then make object sphere object,5,10,10:object(object).typeofobject="sphere"
if selection=cone then make object cone object,5:object(object).typeofobject="cone"
if selection=cylinder then make object cylinder object,5:object(object).typeofobject="cylinder"
if selection=lights and light2>0 then gosub reset_buttons:goto getoutofhere
if selection=lights
make object sphere object,2,10,10:object(object).typeofobject="light"
color object object,rgb(255,255,0)
set object light object,0
if light1>0 then light2=object:make light 2:numberoflights=2
if light1=0 then light1=object
endif
if texture>0 and object<>light1 and object<>light2
texture object object,texture
object(object).texture=texture
else
if object<>light1 and object<>light2 then color object object,rgb(rnd(255),rnd(255),rnd(255))
endif
position object object,object position x(1),object position y(1),object position z(1)
if object=light1 then position light 1,object position x(1),0.1,object position z(1)
if object=light2 then position light 2,object position x(1),0.1,object position z(1)
set object cull object,0
gosub reset_buttons
create=0
endif
getoutofhere:
return
reposition_object:
object=picked
if create=0
`set cursor to object position first time only
if excludero=0
excludero=1
position object 1,object position x(object),object position y(object),object position z(object)
endif
position object object,object position x(1),object position y(1),object position z(1)
if mouseclick()=0
excludero=0
if object<>light1 and object<>light2 then set object light object,1
endif
if object=light1 then position light 1,object position x(light1),object position y(light1),object position z(light1)
if object=light2 then position light 2,object position x(light2),object position y(light2),object position z(light2)
endif
return
scale_object:
object=picked
if create=0
`set cursor to object position first time only
if excludeso=0
excludeso=1
position object 1,object position x(object),object position y(object),object position z(object)
endif
if mouseclick()=1
inc object(object).scalex,mx#
inc object(object).scalez,-my#
endif
if mouseclick()=2
inc object(object).scaley,-my#
endif
if object<>light1 and object<>light2 then scale object object,100+object(object).scalex,100+object(object).scaley,100+object(object).scalez
if mouseclick()=0
excludeso=0
if object<>light1 and object<>light2 then set object light object,1
endif
endif
return
calculate_shadows:
undim pixelshaded1(128,128)
undim pixelshaded2(128,128)
dim pixelshaded1(128,128)
dim pixelshaded2(128,128)
if light1>0
create bitmap 1,128,128
set current bitmap 1
ink rgb(255,255,255),0
box 0,0,128,128
ink rgb(10,10,10),0
for y=0 to 128
for x=0 to 128
for object=3 to numberofobjects+2
if object<>light1 and object<>light2
ray1#=intersect object(object,x,0,y,object position x(light1),object position y(light1),object position z(light1))
if light2>0 then ray2#=intersect object(object,x,0,y,object position x(light2),object position y(light2),object position z(light2)) else ray2=0
if ray1#=0 then ray1#=1000
if ray1#<0 then ray1#=1
if ray2#=0 then ray2#=1000
if ray2#<0 then ray2#=1
if ray1#<=100 and ray2#>100
tone=100+ray1#*2
if pixelshaded2(x,y)=1 or pixelshaded1(x,y)=1 then tone=tone/1.5
if tone>255 then tone=255
ink rgb(tone,tone,tone),0
dot x,128-y
pixelshaded1(x,y)=1
endif
if ray2#<=100 and ray1#>100
tone=100+ray2#*2
if pixelshaded1(x,y)=1 or pixelshaded2(x,y)=1 then tone=tone/1.5
if tone>255 then tone=255
ink rgb(tone,tone,tone),0
dot x,128-y
pixelshaded2(x,y)=1
endif
if ray1#<=100 and ray2#<=100
tone=50+(ray1#+ray2#)
if tone>255 then tone=255
ink rgb(tone,tone,tone),0
dot x,128-y
endif
endif
next object
next x
next y
blur bitmap 1,3
shadowmap=free_image()
get image shadowmap,0,0,128,128
delete bitmap 1
set light mapping on 2,shadowmap
endif `(light1 exist)
return
function free_image
repeat
inc image
until image exist(image)=0
endfunction image
function SYS_screenToXZ(screenx as integer, screeny as integer, camera as integer, Yplain as float)
local pick as TYPE_XYZfloat
local height as float
local scalar as float
if camera <> 0
set current camera camera
endif
height = camera position y()
pick screen screenx, screeny, 1.0
pick.x = get pick vector x()
pick.y = get pick vector y()
pick.z = get pick vector z()
`scalar = Yplain - (height/pick.y)
scalar = -1*((height - Yplain)/pick.y)
`since it is impossible
GU_XYZReturn.x = (camera position x() + scalar*pick.x)
GU_XYZReturn.y = Yplain
GU_XYZReturn.z = (camera position z() + scalar*pick.z)
if camera <> 0
set current camera 0
endif
endfunction
function SYS_screenToY(screenx as integer, screeny as integer, camera as integer, Xpos as float, Zpos as float)
local vec0A as integer = 1
local vec1A as integer = 2
local vecB as integer = 3
local vecC as integer = 4
local tmp as float
local rtrn as float
tmp = make vector3(vec0A)
tmp = make vector3(vec1A)
tmp = make vector3(vecB)
tmp = make vector3(vecC)
rem after we make the vectors perform math...
pick screen screenx, screeny, 1.0
set vector3 vec0A, Xpos, 0, Zpos
set vector3 vec1A, 0, 1, 0
set vector3 vecB, get pick vector x(), get pick vector y(), get pick vector z()
cross product vector3 vecC, vec1A, vecB
cross product vector3 vecC, vecC, vecB
normalize vector3 vecC, vecC
tmp = X Vector3(vecC)*camera position x() + Y Vector3(vecC)*camera position y() + Z Vector3(vecC)*camera position z()
rtrn = (tmp - dot product vector3(vec0A, vecC)) / dot product vector3(vec1A, vecC)
tmp = delete vector3(vec0A)
tmp = delete vector3(vec1A)
tmp = delete vector3(vecB)
tmp = delete vector3(vecC)
endfunction rtrn
make_texture_sprites:
create bitmap 1,64,64
`grass
ink rgb(0,255,0),0
box 0,0,64,64
for n=1 to 200
x=rnd(64)
y=rnd(64)
ink rgb(rnd(100),255,rnd(100)),0
dot x,y
next n
grass=free_sprite()
get image grass,0,0,64,64
sprite grass,325,45,grass
size sprite grass,40,40
`concrete
ink rgb(200,200,200),0
box 0,0,64,64
for n=1 to 200
x=rnd(64)
y=rnd(64)
ink rgb(150+rnd(100),150+rnd(100),150+rnd(100)),0
dot x,y
next n
concrete=free_sprite()
get image concrete,0,0,64,64
sprite concrete,370,45,concrete
size sprite concrete,40,40
`brick
ink rgb(250,150,100),0
box 0,0,64,64
for y=1 to 61 step 10
ink rgb(180,180,140),0
line 0,y,64,y
for x=0 to 64 step rnd(10)
line x,y,x,y+10
next x
next y
brick=free_sprite()
get image brick,0,0,64,64
sprite brick,415,45,brick
size sprite brick,40,40
`colours
box 0,0,64,64,rgb(250,0,0),rgb(0,255,0),rgb(0,0,255),rgb(255,255,0)
colours=free_sprite()
get image colours,0,0,64,64
sprite colours,325,90,colours
size sprite colours,40,40
`white
ink rgb(255,255,255),0
box 0,0,64,64
white=free_sprite()
get image white,0,0,64,64
sprite white,370,90,white
size sprite white,40,40
`red
ink rgb(255,0,0),0
box 0,0,64,64
red=free_sprite()
get image red,0,0,64,64
sprite red,415,90,red
size sprite red,40,40
delete bitmap 1
return
savescene:
repeat
text 0,220,"enter a filename (without extension): "
sync
until scancode()>0
set cursor 0,240
input "",filename$
if shadowmap>0
if image exist(shadowmap)
if file exist(filename$+"_shadowmap"+".bmp") then delete file filename$+"_shadowmap"+".bmp"
save image filename$+"_shadowmap"+".bmp",shadowmap
endif
endif
if file exist(filename$+".scn") then delete file filename$+".scn"
open to write 1,filename$+".scn"
write file 1,numberoflights
write float 1,light position x(1)
write float 1,light position y(1)
write float 1,light position z(1)
if numberoflights=2
write float 1,light position x(2)
write float 1,light position y(2)
write float 1,light position z(2)
endif
write file 1,numberofobjects
for object=3 to numberofobjects+2
if object exist(object)
write string 1,object(object).typeofobject
write float 1,object position x(object)
write float 1,object position y(object)
write float 1,object position z(object)
write float 1,object angle x(object)
write float 1,object angle y(object)
write float 1,object angle z(object)
write float 1,object(object).scalex
write float 1,object(object).scaley
write float 1,object(object).scalez
write file 1,object(object).texture
endif
text 0,0,"Saving"
sync
next object
close file 1
return
loadscene:
repeat
text 0,220,"enter a filename (without extension): "
sync
until scancode()>0
set cursor 0,240
input "",filename$
if file exist(filename$+"_shadowmap"+".bmp")
shadowmap=free_image()
load image filename$+"_shadowmap"+".bmp",shadowmap
set light mapping on 2,shadowmap
endif
if file exist(filename$+".scn")
`delete existing scene
light1=0
light2=0
for object=3 to numberofobjects+2
if object exist(object)
delete object object
endif
next object
open to read 1,filename$+".scn"
read file 1,numberoflights
read float 1,lightx#
read float 1,lighty#
read float 1,lightz#
position light 1,lightx#,lighty#,lightz#
if numberoflights=2
read float 1,lightx#
read float 1,lighty#
read float 1,lightz#
if light exist(2)=0 then make light 2
position light 2,lightx#,lighty#,lightz#
endif
read file 1,numberofobjects
undim object(numberofobjects+2)
dim object(numberofobjects+2) as objecttype
for object=3 to numberofobjects+2
if file end(1)=0
read string 1,typeofobject$
object(object).typeofobject=typeofobject$
if typeofobject$="cube" then make object cube object,5
if typeofobject$="box" then make object box object,5,20,5
if typeofobject$="sphere" then make object sphere object,5,10,10
if typeofobject$="cone" then make object cone object,5
if typeofobject$="cylinder" then make object cylinder object,5
if typeofobject$="light"
make object sphere object,2,10,10
color object object,rgb(255,255,0)
set object light object,0
if light1=0 then light1=object else light2=object
endif
read float 1,x#
read float 1,y#
read float 1,z#
position object object,x#,y#,z#
read float 1,anglex#
read float 1,angley#
read float 1,anglez#
rotate object object,anglex#,angley#,anglez#
read float 1,scalex#
read float 1,scaley#
read float 1,scalez#
scale object object,100+scalex#,100+scaley#,100+scalez#
object(object).scalex=scalex#
object(object).scaley=scaley#
object(object).scalez=scalez#
read file 1,texture
object(object).texture=texture
texture object object,texture
endif
text 0,0,"Loading"
sync
next object
else
text 0,0,"File not found"
sync
wait 1000
endif `(file exist)
close file 1
return