A sort of basic renderer which has perspective correct texturing and per vertex gouraoud shading from a single light source.
The following code is the lib only, save as "stonemonkey3d.bas"
'*****************************************************************************
'******************** Stonemonkey 3D lib using Tiny_PTC **********************
'*****************************************************************************
'
'Use as you want but please credit if used in any work.
'
'******************** user functions **********************
'
'buffer as buffer pointer=graphics_3d(width,height,[name$])
'close_graphics(buffer)
'world as world pointer=create_world()
'delete_world(world)
'texture as texture pointer=create_texture(world,width,height[,argb_fill])
'set_texel(texture,x,y,argb)
'argb as integer=get_texel(texture,x,y)
'ambient_light(world,level0-255)
'camera as entity pointer=create_camera(world)
'change_camera(world,camera)
'camera as entity pointer=current_camera(world)
'light as entity pointer=create_light(world)
'mesh as entity pointer=create_mesh(world)
'vertex as vertex pointer=add_vertex(mesh,x,y,z[,u,v])
'triangle as triangle pointer=add_triangle(mesh,vertex0,vertex1,vertex2,texture)
'update_normals(world)
'translate_entity(entity,x,y,z)
'position_entity(entity,x,y,z)
'move_entity(entity,x,y,z)
'rotate_entity(entity,a,b,c)
'turn_entity(entity,a,b,c)
'reset_entity_rotation(entity)
'point_entity(entity,target_entity)
'copy_position(destination_entity,source_entity)
'align_to_vector(entity,vx,vy,vz)
'render_world(world,buffer)
'
'
option explicit
const rad_conv=3.14159265/180.0
#define PTC_WIN
#Include Once "tinyptc.bi"
'==============================================================================
' Binary Font By Shockwave / DBF; (59 Chars)
'==============================================================================
font_data:
'space
data 59
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'!
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
'"
data 0,1,1,0,1,1,0,0,0
data 0,1,1,0,1,1,0,0,0
data 0,1,1,0,1,1,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'#
data 0,0,0,0,0,0,0,0,0
data 0,1,1,0,0,0,1,1,0
data 1,1,1,1,1,1,1,1,1
data 0,1,1,0,0,0,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,1,1,0,0,0,1,1,0
data 1,1,1,1,1,1,1,1,1
data 0,1,1,0,0,0,1,1,0
data 0,0,0,0,0,0,0,0,0
'£
data 0,0,1,1,1,1,0,0,0
data 0,1,1,1,1,1,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,1,1,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,0
'%
data 0,0,0,0,0,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,0,0,0,1,0,0
data 0,0,0,0,0,1,0,0,0
data 0,0,0,0,1,0,0,0,0
data 0,0,0,1,0,0,0,0,0
data 0,0,1,0,0,0,1,1,0
data 0,0,0,0,0,0,1,1,0
data 0,0,0,0,0,0,0,0,0
'&
data 0,0,0,1,1,1,0,0,0
data 0,0,1,1,1,1,1,0,0
data 0,0,1,1,0,1,1,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,1,1,0,1,1,0,0
data 0,1,1,0,0,1,1,1,1
data 0,1,1,1,0,0,1,1,0
data 0,0,1,1,1,1,1,0,0
data 0,0,0,0,1,1,0,0,0
''
data 0,1,1,0,0,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'(
data 0,0,0,0,0,1,1,1,0
data 0,0,0,0,1,1,1,1,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,0,1,1,1,0,0
data 0,0,0,0,1,1,1,0,0
data 0,0,0,0,1,1,1,0,0
data 0,0,0,0,1,1,1,1,0
data 0,0,0,0,0,1,1,1,0
')
data 0,1,1,1,0,0,0,0,0
data 0,1,1,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,1,1,1,1,0,0,0,0
data 0,1,1,1,0,0,0,0,0
'*
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,1,0,0,0,0
data 0,0,1,0,1,0,1,0,0
data 0,0,0,1,1,1,0,0,0
data 0,1,1,1,1,1,1,1,0
data 0,0,0,1,1,1,0,0,0
data 0,0,1,0,1,0,1,0,0
data 0,0,0,0,1,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'+
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,1,0,0,0,0
data 0,0,0,0,1,0,0,0,0
data 0,0,1,1,1,1,1,0,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
''
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,0,1,0,0,0,0
'-
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,1,1,1,1,1,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'.
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
'/
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,1,0
data 0,0,0,0,0,0,1,1,0
data 0,0,0,0,0,1,1,0,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,1,1,1,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'0
data 0,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,1,1,1
data 1,1,0,0,0,1,0,1,1
data 1,1,0,0,1,0,0,1,1
data 1,1,0,1,1,0,0,1,1
data 1,1,1,1,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'1
data 0,0,0,1,1,0,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,1,1,1,1,1,1,0,0
data 0,1,1,1,1,1,1,0,0
'2
data 0,0,1,1,1,1,1,1,0
data 0,0,1,1,1,1,1,1,1
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,0,0,0,1,1
data 0,1,1,1,1,1,1,1,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
'3
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,0
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,1,1,1,1,0
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,0
'4
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,1,1,0,0,0
data 1,1,0,0,1,1,0,0,0
data 1,1,1,1,1,1,1,1,1
data 0,0,0,0,0,1,1,1,0
data 0,0,0,0,0,1,1,1,0
data 0,0,0,0,0,1,1,1,0
data 0,0,0,0,0,1,1,1,0
'5
data 0,1,1,1,1,1,1,0,0
data 0,1,1,1,1,1,1,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,0,0,0,0,0,0
data 0,1,1,1,1,1,1,1,0
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,0
'6
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,0
data 1,1,0,0,0,0,1,1,1
data 1,1,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'7
data 0,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,1
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,1,1,1,1,1
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,1,1,1,0
data 0,0,0,0,0,1,1,1,0
data 0,0,0,0,0,1,1,1,0
'8
data 0,0,1,1,1,1,1,0,0
data 0,1,1,1,1,1,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,0,1,1,1,1,1,0,0
data 1,1,1,0,0,0,1,1,1
data 1,1,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'9
data 0,0,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,1
data 0,1,1,0,0,0,0,1,1
data 0,1,1,0,0,0,0,1,1
data 0,0,1,1,1,1,1,1,1
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
':
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
';
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,0,1,0,0,0,0
'<
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,1,1,0,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,0,1,1,1,0,0
data 0,0,0,0,0,1,1,0,0
data 0,0,0,0,0,0,0,0,0
'=
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,1,1,1,1,1,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,1,1,1,1,1,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'>
data 0,0,0,0,0,0,0,0,0
data 0,0,1,1,0,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,0,1,1,0,0,0
data 0,0,0,0,1,1,1,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,1,1,1,0,0,0,0
data 0,1,1,1,0,0,0,0,0
data 0,0,0,0,0,0,0,0,0
'?
data 0,0,1,1,1,1,1,0,0
data 0,1,1,1,1,1,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,0,0,0,0,0,1,1,0
data 0,0,0,1,1,1,1,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,0,0,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
'@
data 0,0,0,0,0,0,0,0,0
data 0,0,1,1,1,1,1,0,0
data 0,1,0,0,0,0,0,0,0
data 0,1,0,0,1,1,1,0,0
data 0,1,0,1,0,0,0,1,0
data 0,1,0,1,1,1,0,1,0
data 0,1,0,0,0,0,0,1,0
data 0,0,1,1,1,1,1,0,0
data 0,0,0,0,0,0,0,0,0
'a
data 0,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,0
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
'b
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,0
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,0
'c
data 0,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,1
'd
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,0
'e
data 0,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,1,1,1,1,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,1
'f
data 0,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,1,1,1,1,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
'g
data 0,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,1,1,1,1
data 1,1,0,0,0,0,1,1,1
data 1,1,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'h
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
'i
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
'j
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,0
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,0
'k
data 1,1,0,0,0,0,1,1,0
data 1,1,0,0,0,0,1,1,0
data 1,1,0,0,0,0,1,1,0
data 1,1,0,0,0,0,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
'l
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,1
'm
data 0,1,1,1,0,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,1,0,0,1,1
data 1,1,0,0,1,0,0,1,1
data 1,1,0,0,1,0,0,1,1
data 1,1,1,0,1,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
'n
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
'o
data 0,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'p
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
'q
data 0,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,1,0,1,1
data 1,1,1,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'r
data 1,1,1,1,1,1,1,1,0
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,0
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
's
data 0,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,0,0,0,0,0,0,0
data 1,1,0,0,0,0,0,0,0
data 0,1,1,1,1,1,1,1,0
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,0
't
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,0,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
data 0,0,0,1,1,1,0,0,0
'u
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,1,1,1,1,0
'v
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,1,0,0,1,1,1
data 0,1,1,1,1,1,1,1,0
data 0,0,1,1,1,1,1,0,0
'w
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,1,0,1,0,0,1,1
data 1,1,1,0,1,0,0,1,1
data 1,1,1,0,1,0,0,1,1
data 1,1,1,1,1,1,1,1,1
data 0,1,1,1,0,1,1,1,0
'x
data 0,1,1,0,0,0,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,1,1,0,0,0,1,1,0
data 0,1,1,1,1,1,1,1,0
data 1,1,1,1,0,0,1,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
data 1,1,1,0,0,0,0,1,1
'y
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 1,1,0,0,0,0,0,1,1
data 0,1,1,1,1,1,1,1,1
data 0,0,0,0,0,0,1,1,1
data 0,0,0,0,0,0,1,1,1
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,0
'z
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
data 0,0,0,0,0,0,0,1,1
data 0,0,0,0,0,0,1,1,1
data 0,1,1,1,1,1,1,1,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,0,0,0,0,0,0
data 1,1,1,1,1,1,1,1,1
data 1,1,1,1,1,1,1,1,1
type buffer
  wwidth as integer
  height as integer
  argb_buffer as integer pointer
  depth_buffer as single pointer
  font_data as integer pointer
  previous_time as double
end type
type texture
  wwidth as integer
  height as integer
  u_and as integer
  v_and as integer
  u_mult as single
  v_mult as single
  buffer as integer pointer
  mipmap as texture pointer
  next_texture as texture pointer
end type
type vertex
  x as single
  y as single
  z as single
  rx as single
  ry as single
  rz as single
  nx as single
  ny as single
  nz as single
  rnx as single
  rny as single
  rnz as single
  u as single
  v as single
  shade as single
  next_vertex as vertex pointer
end type
type triangle
  v0 as vertex pointer
  v1 as vertex pointer
  v2 as vertex pointer
  nx as single
  ny as single
  nz as single
  texture as texture pointer
  area as single
  next_triangle as triangle pointer
end type
type entity
  x as single
  y as single
  z as single
  ux0 as single
  uy0 as single
  uz0 as single
  ux1 as single
  uy1 as single
  uz1 as single
  ux2 as single
  uy2 as single
  uz2 as single
  first_vertex as vertex pointer
  first_triangle as triangle pointer
  next_entity as entity pointer
end type
type world
  first_mesh as entity pointer
  first_texture as texture pointer
  first_light as entity pointer
  first_camera as entity pointer
  current_camera as entity pointer
  ambient_light as integer
end type
function graphics_3d(byval wwidth as integer,byval height as integer,byval windowname as string="Stonemonkey_3d")as buffer pointer
  If( ptc_open( windowname, wwidth, height ) = 0 ) Then
    End -1
  End If
  dim buffer as buffer pointer=callocate(len(buffer))
  buffer->wwidth=wwidth
  buffer->height=height
  buffer->argb_buffer=callocate(len(integer)*wwidth*height)
  buffer->depth_buffer=callocate(len(single)*wwidth*height)
  dim as integer chars,chrbit,chrdat,char,x,y
 Â
  restore font_data
  read chars
  buffer->font_data=callocate(len(integer)*chars*9)
  dim as integer pointer font_pointer=buffer->font_data
  for char=0 to chars-1
    for y=0 to 8
      chrdat=0
      for x=0 to 8
        read chrbit
        chrdat=chrdat or((2^x)*chrbit)
      next
      *font_pointer=chrdat
      font_pointer+=1
    next
  next
  function=buffer
end function
sub text(byval buffer as buffer pointer,txt as string,byval x as integer,y as integer)
  dim as integer char,position,chrdat,xx,yy
  dim as integer pointer char_pointer,screen_pointer
  for position=1 to len(txt)
    char=(asc(mid$(txt,position,1))-32)*9
    char_pointer=buffer->font_data+char
    for yy=y to y+8
      screen_pointer=buffer->argb_buffer+(yy*buffer->wwidth+x+(position*10))
      chrdat=*char_pointer
      for xx=x to x+8
        if (chrdat and 1)=1 then *screen_pointer=&hffffff
        chrdat shr=1
        screen_pointer+=1
      next
      char_pointer+=1
    next
  next
end sub
sub close_graphics(byval buffer as buffer pointer)
  deallocate buffer->argb_buffer
  deallocate buffer->depth_buffer
deallocate buffer->font_data
  deallocate buffer
  ptc_close
end sub
function create_texture(byval world as world pointer,_
            byval texture_width as integer,_
            byval texture_height as integer,_
            byval argb as integer=0)as texture pointer
  dim texture as texture pointer=callocate(len(texture))
  texture->wwidth=texture_width
  texture->height=texture_height
  texture->u_mult=texture_width
  texture->v_mult=texture_width*texture_height
  texture->u_and=texture_width-1
  texture->v_and=(texture_height-1)*texture_width
  texture->buffer=callocate(texture_width*texture_height*len(integer))
  dim x as integer,y as integer,p as integer pointer
  p=texture->buffer
  for y=0 to texture_height-1
    for x=0 to texture_width-1
      *p=argb
      p+=1
    next
  next
  texture->next_texture=world->first_texture
  world->first_texture=texture
  function=texture
end function
sub set_texel(byval texture as texture pointer,byval u as integer,byval v as integer,byval argb as integer)
  *(texture->buffer+(u+v*texture->wwidth))=argb
end sub
function get_texel(byval texture as texture pointer,byval u as integer,byval v as integer)as integer
  function=*(texture->buffer+(u+v*texture->wwidth))
end function
sub mipmap(byval world as world pointer,byval texture as texture pointer)
  if (texture->wwidth<2)or(texture->height<2) then return
  if texture->mipmap=0 then texture->mipmap=create_texture(world,texture->wwidth shr 1,texture->height shr 1)
  dim uu as integer,vv as integer,argb as uinteger,alpha as uinteger,red as integer,gre as integer,blu as integer
  for vv=0 to texture->height-2 step 2
    for uu=0 to texture->wwidth-2 step 2
      argb=get_texel(texture,uu,vv)
      alpha=(argb and &hff000000)shr 24
      red=argb and &hff0000
      gre=argb and &hff00
      blu=argb and &hff
      argb=get_texel(texture,uu+1,vv)
      alpha=alpha+((argb and &hff000000)shr 24)
      red=red+(argb and &hff0000)
      gre=gre+(argb and &hff00)
      blu=blu+(argb and &hff)
      argb=get_texel(texture,uu,vv+1)
      alpha=alpha+((argb and &hff000000)shr 24)
      red=red+(argb and &hff0000)
      gre=gre+(argb and &hff00)
      blu=blu+(argb and &hff)
      argb=get_texel(texture,uu+1,vv+1)
      alpha=alpha+((argb and &hff000000)shr 24)
      red=red+(argb and &hff0000)
      gre=gre+(argb and &hff00)
      blu=blu+(argb and &hff)
      alpha=(alpha shl 22)and &hff000000
      red=(red shr 2)and &hff0000
      gre=(gre shr 2)and &hff00
      blu=(blu shr 2)and &hff
      set_texel(texture->mipmap,uu shr 1,vv shr 1,alpha or red or gre or blu)
    next
  next
  mipmap world,texture->mipmap
end sub
function create_world() as world pointer
  dim world_pointer as world pointer=callocate(len(world))
  function=world_pointer
end function
sub ambient_light(byval world as world pointer,byval level as integer)
  world->ambient_light=level and &hff
end sub
function create_camera(byval world as world pointer) as entity pointer
  dim camera as entity pointer=callocate(len(entity))
  camera->ux0=1.0
  camera->uy1=1.0
  camera->uz2=1.0
  camera->next_entity=world->first_camera
  world->first_camera=camera
  world->current_camera=camera
  function=camera
end function
sub change_camera(byval world as world pointer,byval camera as entity pointer)
  world->current_camera=camera
end sub
function current_camera(byval world as world pointer)as entity pointer
  function=world->current_camera
end function
function create_light(byval world as world pointer) as entity pointer
  dim light as entity pointer=callocate(len(entity))
  light->ux0=1.0
  light->uy1=1.0
  light->uz2=1.0
  light->next_entity=world->first_light
  world->first_light=light
  function=light
end function
function create_mesh(byval world as world pointer) as entity pointer
  dim mesh as entity pointer=callocate(len(entity))
  mesh->ux0=1.0
  mesh->uy1=1.0
  mesh->uz2=1.0
  mesh->next_entity=world->first_mesh
  world->first_mesh=mesh
  function=mesh
end function
function add_vertex(byval mesh as entity pointer,byval x as single,_
                         byval y as single,_
                         byval z as single,_
                         byval u as single=0.0,_
                         byval v as single=0.0) as vertex pointer
  dim vertex as vertex pointer=callocate(len(vertex))
  vertex->x=x
  vertex->y=y
  vertex->z=z
  vertex->u=u
  vertex->v=v
  vertex->next_vertex=mesh->first_vertex
  mesh->first_vertex=vertex
  function=vertex
end function
sub add_triangle(byval mesh as entity pointer,byval vertex0 as vertex pointer,_
                       byval vertex1 as vertex pointer,_
                       byval vertex2 as vertex pointer,_
                       byval texture as texture pointer)
  dim triangle as triangle pointer=callocate(len(triangle))
  triangle->v0=vertex0
  triangle->v1=vertex1
  triangle->v2=vertex2
  triangle->texture=texture
  triangle->next_triangle=mesh->first_triangle
  mesh->first_triangle=triangle
end sub
private sub update_triangle_normals(byval mesh as entity pointer)
  dim triangle as triangle pointer=mesh->first_triangle
  dim v0 as vertex pointer
  dim v1 as vertex pointer
  dim v2 as vertex pointer
  dim vx0 as single,vy0 as single,vz0 as single
  dim vx1 as single,vy1 as single,vz1 as single
  dim vx as single,vy as single,vz as single,d as single
  while triangle<>0
    v0=triangle->v0
    v1=triangle->v1
    v2=triangle->v2
    vx0=v1->x-v0->x
    vy0=v1->y-v0->y
    vz0=v1->z-v0->z
    vx1=v2->x-v0->x
    vy1=v2->y-v0->y
    vz1=v2->z-v0->z
    vx=vy0*vz1-vz0*vy1
    vy=vz0*vx1-vx0*vz1
    vz=vx0*vy1-vy0*vx1
    d=1.0/Sqr(vx*vx+vy*vy+vz*vz)
    triangle->area=abs((v1->u-v0->u)*(v2->v-v0->v)-(v2->u-v0->u)*(v1->v-v0->v))
    triangle->area*=(triangle->texture->wwidth*triangle->texture->height)
    triangle->nx=vx*d
    triangle->ny=vy*d
    triangle->nz=vz*d
    triangle=triangle->next_triangle
  wend
end sub
private sub update_vertex_normals(byval mesh as entity pointer)
  dim vertex as vertex pointer=mesh->first_vertex
  dim d as single
  dim triangle as triangle pointer=mesh->first_triangle
  while triangle<>0
    triangle->v0->nx+=triangle->nx
    triangle->v0->ny+=triangle->ny
    triangle->v0->nz+=triangle->nz
    triangle->v1->nx+=triangle->nx
    triangle->v1->ny+=triangle->ny
    triangle->v1->nz+=triangle->nz
    triangle->v2->nx+=triangle->nx
    triangle->v2->ny+=triangle->ny
    triangle->v2->nz+=triangle->nz
    triangle=triangle->next_triangle
  wend
  while vertex<>0
    d=1.0/sqr(vertex->nx*vertex->nx+vertex->ny*vertex->ny+vertex->nz*vertex->nz)
    vertex->nx*=d
    vertex->ny*=d
    vertex->nz*=d
    vertex=vertex->next_vertex
  wend
end sub
sub update_normals(byval world as world pointer)
  dim mesh as entity pointer=world->first_mesh
  while mesh<>0
    update_triangle_normals(mesh)
    update_vertex_normals(mesh)
    mesh=mesh->next_entity
  wend
end sub
sub translate_entity(byval entity as entity pointer,byval x as single,byval y as single,byval z as single)
  entity->x+=x
  entity->y+=y
  entity->z+=z
end sub
sub position_entity(byval entity as entity pointer,byval x as single,byval y as single,byval z as single)
  entity->x=x
  entity->y=y
  entity->z=z
end sub
sub move_entity(byval entity as entity pointer,byval x as single,byval y as single,byval z as single)
  entity->x+=x*entity->ux0+y*entity->uy0+z*entity->uz0
  entity->y+=x*entity->ux1+y*entity->uy1+z*entity->uz1
  entity->z+=x*entity->ux2+y*entity->uy2+z*entity->uz2
end sub
sub turn_entity(byval entity as entity pointer,byval b as single,byval a as single,byval c as single)
  dim csa as single=cos(-a*rad_conv)
  dim sna as single=sin(-a*rad_conv)
  dim csb as single=cos(-b*rad_conv)
  dim snb as single=sin(-b*rad_conv)
  dim csc as single=cos(c*rad_conv)
  dim snc as single=sin(c*rad_conv)
  dim x as single
  dim y as single
  dim z as single
  x=entity->ux0*csa+entity->uz0*sna
  z=entity->uz0*csa-entity->ux0*sna
  entity->uz0=z*csb+entity->uy0*snb
  y=entity->uy0*csb-z*snb
  entity->ux0=x*csc+y*snc
  entity->uy0=y*csc-x*snc
  x=entity->ux1*csa+entity->uz1*sna
  z=entity->uz1*csa-entity->ux1*sna
  entity->uz1=z*csb+entity->uy1*snb
  y=entity->uy1*csb-z*snb
  entity->ux1=x*csc+y*snc
  entity->uy1=y*csc-x*snc
  x=entity->ux2*csa+entity->uz2*sna
  z=entity->uz2*csa-entity->ux2*sna
  entity->uz2=z*csb+entity->uy2*snb
  y=entity->uy2*csb-z*snb
  entity->ux2=x*csc+y*snc
  entity->uy2=y*csc-x*snc
end sub
sub rotate_entity(byval entity as entity pointer,byval b as single,byval a as single,byval c as single)
  dim csa as single=cos(a*rad_conv)
  dim sna as single=sin(a*rad_conv)
  dim csb as single=cos(b*rad_conv)
  dim snb as single=sin(b*rad_conv)
  dim csc as single=cos(-c*rad_conv)
  dim snc as single=sin(-c*rad_conv)
  dim x as single
  dim y as single
  dim z as single
  x=entity->ux0*csa+entity->ux2*sna
  z=entity->ux2*csa-entity->ux0*sna
  entity->ux2=z*csb+entity->ux1*snb
  y=entity->ux1*csb-z*snb
  entity->ux0=x*csc+y*snc
  entity->ux1=y*csc-x*snc
  x=entity->uy0*csa+entity->uy2*sna
  z=entity->uy2*csa-entity->uy0*sna
  entity->uy2=z*csb+entity->uy1*snb
  y=entity->uy1*csb-z*snb
  entity->uy0=x*csc+y*snc
  entity->uy1=y*csc-x*snc
  x=entity->uz0*csa+entity->uz2*sna
  z=entity->uz2*csa-entity->uz0*sna
  entity->uz2=z*csb+entity->uz1*snb
  y=entity->uz1*csb-z*snb
  entity->uz0=x*csc+y*snc
  entity->uz1=y*csc-x*snc
end sub
sub reset_entity_rotation(byval entity as entity pointer)
  entity->ux0=1.0
  entity->uy0=0.0
  entity->uz0=0.0
  entity->ux1=0.0
  entity->uy1=1.0
  entity->uz1=0.0
  entity->ux2=0.0
  entity->uy2=0.0
  entity->uz2=1.0
end sub
Function point_entity(byval entity as entity pointer,byval target as entity pointer,byval roll as single=0.0)
  dim tx as single=target->x-entity->x
  dim ty as single=target->y-entity->y
  dim tz as single=target->z-entity->z
  reset_entity_rotation(entity)
turn_entity entity,-ATan2(ty,Sqr(tx*tx+tz*tz))/rad_conv,ATan2(tx,tz)/rad_conv,roll
End Function
sub copy_position(byval dest as entity pointer,byval source as entity pointer)
  dest->x=source->x
  dest->y=source->y
  dest->z=source->z
end sub
sub copy_rotation(byval dest as entity pointer,byval source as entity pointer)
  dest->ux0=source->ux0
  dest->uy0=source->uy0
  dest->uz0=source->uz0
  dest->ux1=source->ux1
  dest->uy1=source->uy1
  dest->uz1=source->uz1
  dest->ux2=source->ux2
  dest->uy2=source->uy2
  dest->uz2=source->uz2
end sub
Function align_to_vector(byval entity as entity pointer,byval vx as single,_
                            byval vy as single,_
                            byval vz as single,_
                            byval axis as integer,_
                            byval speed as single=1.0)
  dim x as single,y as single,z as single
  dim a as single,b as single,c as single
  select case axis
  case 1
    turn_entity entity,-90,0,0
  case 2
    turn_entity entity,0,-90,0
  end select
  x=vx*entity->ux0+vy*entity->ux1+vz*entity->ux2
  y=vx*entity->uy0+vy*entity->uy1+vz*entity->uy2
  z=vx*entity->uz0+vy*entity->uz1+vz*entity->uz2
  a=atan2(-y,z)/rad_conv
  b=atan2(x,z)/rad_conv
  c=0
  turn_entity entity,a*speed,b*speed,c*speed
  select case axis
  case 1
    turn_entity entity,90,0,0
  case 2
    turn_entity entity,0,90,0
  end select
End Function
type render_vertex
  z as single
  x as single
  y as single
  u as single
  v as single
  s as single
end type
type render_edge
  x as single
  dx as single
  z as single
  dz as single
  u as single
  du as single
  v as single
  dv as single
  s as single
  ds as single
end type
private sub render_triangle(byval y_start as integer,_
              byval y_end as integer,_
              byref ledge as render_edge,_
              byref redge as render_edge,_
              byval buffer as buffer pointer,_
              byval ambient as integer,_
              byval texture as texture pointer)
  dim as integer x_start,x_end,uu,vv,sh,argb,rbl,gre
  dim as single zz,z,dz,u,du,v,dv,s,ds,d
  dim depth_pointer as single pointer
  while y_start<=y_end
    d=1.0/(redge.x-ledge.x)
    dz=(redge.z-ledge.z)*d
    du=(redge.u-ledge.u)*d
    dv=(redge.v-ledge.v)*d
    ds=(redge.s-ledge.s)*d
    z=ledge.z
    u=ledge.u
    v=ledge.v
    s=ledge.s
    x_start=ledge.x+0.5
    x_end=redge.x-0.5
   Â
    if x_start<0 then x_start=0
    if x_end>=buffer->wwidth then x_end=buffer->wwidth-1
   Â
    d=x_start-ledge.x
    z+=dz*d
    u+=du*d
    v+=dv*d
    s+=ds*d
    depth_pointer=buffer->depth_buffer+(x_start+y_start*buffer->wwidth)
    while x_start<=x_end
      if z>*depth_pointer then
        *depth_pointer=z
        zz=1.0/z
        uu=(u*zz)and texture->u_and
        vv=(v*zz)and texture->v_and
        sh=s*zz
        if sh<ambient then sh=ambient
        argb=*(texture->buffer+(uu or vv))
        rbl=((argb and &hff00ff)*sh)and &hff00ff00
        gre=((argb and &hff00)*sh)and &hff0000
        *(buffer->argb_buffer+(x_start+y_start*buffer->wwidth))=(rbl or gre)shr 8
      end if
      z+=dz
      u+=du
      v+=dv
      s+=ds
      depth_pointer+=1
      x_start+=1
    wend
    ledge.x+=ledge.dx
    ledge.z+=ledge.dz
    ledge.u+=ledge.du
    ledge.v+=ledge.dv
    ledge.s+=ledge.ds
    redge.x+=redge.dx
    redge.z+=redge.dz
    redge.u+=redge.du
    redge.v+=redge.dv
    redge.s+=redge.ds
    y_start+=1
  wend
end sub
private sub setup_textured_triangle(byval triangle as triangle pointer,_
                  byval buffer as buffer pointer,_
                  byval ambient as integer)
  dim as vertex pointer v0=triangle->v0,v1=triangle->v1,v2=triangle->v2
  dim v(0 to 2) as render_vertex
  v(0).z=1.0/v0->rz
  v(0).x=(buffer->wwidth shr 1)+(v0->rx*v(0).z*buffer->wwidth)
  v(0).y=(buffer->height shr 1)-(v0->ry*v(0).z*buffer->wwidth)
  v(1).z=1.0/v1->rz
  v(1).x=(buffer->wwidth shr 1)+(v1->rx*v(1).z*buffer->wwidth)
  v(1).y=(buffer->height shr 1)-(v1->ry*v(1).z*buffer->wwidth)
  v(2).z=1.0/v2->rz
  v(2).x=(buffer->wwidth shr 1)+(v2->rx*v(2).z*buffer->wwidth)
  v(2).y=(buffer->height shr 1)-(v2->ry*v(2).z*buffer->wwidth)
 Â
 Â
  if (v(1).x-v(0).x)*(v(2).y-v(0).y)>(v(2).x-v(0).x)*(v(1).y-v(0).y) then
    dim area as single=((v(1).x-v(0).x)*(v(2).y-v(0).y)-(v(2).x-v(0).x)*(v(1).y-v(0).y))*2.0
    dim texture as texture pointer=triangle->texture
    while (area<triangle->area)and(texture->mipmap<>0)
      texture=texture->mipmap
      area*=4.0
    wend
    v(0).u=(v0->u*texture->u_mult-.5)*v(0).z
    v(0).v=(v0->v*texture->v_mult-.5)*v(0).z
    v(0).s=v0->shade*v(0).z
    v(1).u=(v1->u*texture->u_mult-.5)*v(1).z
    v(1).v=(v1->v*texture->v_mult-.5)*v(1).z
    v(1).s=v1->shade*v(1).z
    v(2).u=(v2->u*texture->u_mult-.5)*v(2).z
    v(2).v=(v2->v*texture->v_mult-.5)*v(2).z
    v(2).s=v2->shade*v(2).z
   Â
    dim as integer p0,p1,p2
 Â
    p0=0
    if v(1).y<v(0).y then p0=1
    if v(2).y<v(p0).y then p0=2
    p2=2
    if v(1).y>v(2).y then p2=1
    if v(0).y>v(p2).y then p2=0
    p1=3-p0-p2
 Â
    dim edge0 as render_edge,edge1 as render_edge
    dim d as single,y_start as integer,y_end as integer
    if (v(p0).y<buffer->height)and(v(p1).y>=0.0) then
      d=1.0/(v(p1).y-v(p0).y)
      edge0.dx=(v(p1).x-v(p0).x)*d
      edge0.dz=(v(p1).z-v(p0).z)*d
      edge0.du=(v(p1).u-v(p0).u)*d
      edge0.dv=(v(p1).v-v(p0).v)*d
      edge0.ds=(v(p1).s-v(p0).s)*d
      d=1.0/(v(p2).y-v(p0).y)
      edge1.dx=(v(p2).x-v(p0).x)*d
      edge1.dz=(v(p2).z-v(p0).z)*d
      edge1.du=(v(p2).u-v(p0).u)*d
      edge1.dv=(v(p2).v-v(p0).v)*d
      edge1.ds=(v(p2).s-v(p0).s)*d
      y_start=v(p0).y+.5
      if y_start<0 then y_start=0
      y_end=v(p1).y-.5
      if y_end>=buffer->height then y_end=buffer->height-1
      d=y_start-v(p0).y
      edge0.x=v(p0).x+edge0.dx*d
      edge0.z=v(p0).z+edge0.dz*d
      edge0.u=v(p0).u+edge0.du*d
      edge0.v=v(p0).v+edge0.dv*d
      edge0.s=v(p0).s+edge0.ds*d
      edge1.x=v(p0).x+edge1.dx*d
      edge1.z=v(p0).z+edge1.dz*d
      edge1.u=v(p0).u+edge1.du*d
      edge1.v=v(p0).v+edge1.dv*d
      edge1.s=v(p0).s+edge1.ds*d
      if edge1.dx>edge0.dx then
        render_triangle y_start,y_end,edge0,edge1,buffer,ambient,texture
      else
        render_triangle y_start,y_end,edge1,edge0,buffer,ambient,texture
      end if
    end if
    if (v(p1).y<buffer->height)and(v(p2).y>=0.0) then
      d=1.0/(v(p2).y-v(p0).y)
      edge0.dx=(v(p2).x-v(p0).x)*d
      edge0.dz=(v(p2).z-v(p0).z)*d
      edge0.du=(v(p2).u-v(p0).u)*d
      edge0.dv=(v(p2).v-v(p0).v)*d
      edge0.ds=(v(p2).s-v(p0).s)*d
      d=1.0/(v(p2).y-v(p1).y)
      edge1.dx=(v(p2).x-v(p1).x)*d
      edge1.dz=(v(p2).z-v(p1).z)*d
      edge1.du=(v(p2).u-v(p1).u)*d
      edge1.dv=(v(p2).v-v(p1).v)*d
      edge1.ds=(v(p2).s-v(p1).s)*d
      y_start=v(p1).y+.5
      if y_start<0 then y_start=0
      y_end=v(p2).y-.5
      if y_end>=buffer->height then y_end=buffer->height-1
      d=y_start-v(p2).y
      edge0.x=v(p2).x+edge0.dx*d
      edge0.z=v(p2).z+edge0.dz*d
      edge0.u=v(p2).u+edge0.du*d
      edge0.v=v(p2).v+edge0.dv*d
      edge0.s=v(p2).s+edge0.ds*d
      edge1.x=v(p2).x+edge1.dx*d
      edge1.z=v(p2).z+edge1.dz*d
      edge1.u=v(p2).u+edge1.du*d
      edge1.v=v(p2).v+edge1.dv*d
      edge1.s=v(p2).s+edge1.ds*d
      if edge1.dx>edge0.dx then
        render_triangle y_start,y_end,edge1,edge0,buffer,ambient,texture
      else
        render_triangle y_start,y_end,edge0,edge1,buffer,ambient,texture
      end if
    end if
  end if
end sub
private sub mesh_render(byval world as world pointer,byval buffer as buffer pointer)
  dim mesh as entity pointer=world->first_mesh
  dim triangle as triangle pointer
  while mesh<>0
    triangle=mesh->first_triangle
    while triangle<>0
      if (triangle->v0->rz>0.0)and _
        (triangle->v1->rz>0.0)and _
        (triangle->v2->rz>0.0) then setup_textured_triangle triangle,buffer,world->ambient_light
      triangle=triangle->next_triangle
    wend
    mesh=mesh->next_entity
  wend
end sub
private sub update_geometry(byval world as world pointer)
  dim mesh as entity pointer=world->first_mesh
  dim camera as entity pointer=world->current_camera
  dim as single cam_xt,cam_yt,cam_zt,ox,oy,oz
  dim as single light_xt,light_yt,light_zt,lx,ly,lz,d
  dim as single ux0,uy0,uz0,ux1,uy1,uz1,ux2,uy2,uz2
  light_xt=world->first_light->x-camera->x
  light_yt=world->first_light->y-camera->y
  light_zt=world->first_light->z-camera->z
  lx=camera->ux0*light_xt+camera->ux1*light_yt+camera->ux2*light_zt
  ly=camera->uy0*light_xt+camera->uy1*light_yt+camera->uy2*light_zt
  lz=camera->uz0*light_xt+camera->uz1*light_yt+camera->uz2*light_zt
  dim vertex as vertex pointer
  while mesh<>0
    cam_xt=mesh->x-camera->x
    cam_yt=mesh->y-camera->y
    cam_zt=mesh->z-camera->z
    ox=camera->ux0*cam_xt+camera->ux1*cam_yt+camera->ux2*cam_zt
    oy=camera->uy0*cam_xt+camera->uy1*cam_yt+camera->uy2*cam_zt
    oz=camera->uz0*cam_xt+camera->uz1*cam_yt+camera->uz2*cam_zt
    ux0=camera->ux0*mesh->ux0+camera->ux1*mesh->ux1+camera->ux2*mesh->ux2
    ux1=camera->ux0*mesh->uy0+camera->ux1*mesh->uy1+camera->ux2*mesh->uy2
    ux2=camera->ux0*mesh->uz0+camera->ux1*mesh->uz1+camera->ux2*mesh->uz2
    uy0=camera->uy0*mesh->ux0+camera->uy1*mesh->ux1+camera->uy2*mesh->ux2
    uy1=camera->uy0*mesh->uy0+camera->uy1*mesh->uy1+camera->uy2*mesh->uy2
    uy2=camera->uy0*mesh->uz0+camera->uy1*mesh->uz1+camera->uy2*mesh->uz2
    uz0=camera->uz0*mesh->ux0+camera->uz1*mesh->ux1+camera->uz2*mesh->ux2
    uz1=camera->uz0*mesh->uy0+camera->uz1*mesh->uy1+camera->uz2*mesh->uy2
    uz2=camera->uz0*mesh->uz0+camera->uz1*mesh->uz1+camera->uz2*mesh->uz2
    vertex=mesh->first_vertex
    while vertex<>0
      vertex->rx=vertex->x*ux0+vertex->y*ux1+vertex->z*ux2+ox
      vertex->ry=vertex->x*uy0+vertex->y*uy1+vertex->z*uy2+oy
      vertex->rz=vertex->x*uz0+vertex->y*uz1+vertex->z*uz2+oz
      vertex->rnx=vertex->nx*ux0+vertex->ny*ux1+vertex->nz*ux2
      vertex->rny=vertex->nx*uy0+vertex->ny*uy1+vertex->nz*uy2
      vertex->rnz=vertex->nx*uz0+vertex->ny*uz1+vertex->nz*uz2
      light_xt=lx-vertex->rx
      light_yt=ly-vertex->ry
      light_zt=lz-vertex->rz
      d=1.0/sqr(light_xt^2+light_yt^2+light_zt^2)
      light_xt*=d
      light_yt*=d
      light_zt*=d
      vertex->shade=255.0*(light_xt*vertex->rnx+light_yt*vertex->rny+light_zt*vertex->rnz)
      vertex=vertex->next_vertex
    wend
    mesh=mesh->next_entity
  wend
end sub
private sub clear_buffers(byval buffer as buffer pointer)
  dim as integer x,y
  dim as integer pointer argb_pointer=buffer->argb_buffer
  dim as single pointer depth_pointer=buffer->depth_buffer
  for y=0 to buffer->height-1
    for x=0 to buffer->wwidth-1
      *argb_pointer=0
      *depth_pointer=0.0
      argb_pointer+=1
      depth_pointer+=1
    next
  next
end sub
sub render_world(byval world as world pointer,byval buffer as buffer pointer)
  clear_buffers buffer
  update_geometry world
  mesh_render world,buffer
  dim time_diff as double=timer-buffer->previous_time
  buffer->previous_time=timer
  text buffer,"FPS: "+left$(str$(1.0/time_diff),4),10,20
  ptc_update buffer->argb_buffer
end sub
sub delete_world(byval world as world pointer)
  dim to_delete as any pointer
  dim texture as texture pointer=world->first_texture
  while texture<>0
    to_delete=texture
    texture=texture->next_texture
    deallocate to_delete
  wend
  dim vertex as vertex pointer,triangle as triangle pointer
  dim entity as entity pointer=world->first_light
  while entity<>0
    to_delete=entity
    entity=entity->next_entity
    deallocate to_delete
  wend
  entity=world->first_camera
  while entity<>0
    to_delete=entity
    entity=entity->next_entity
    deallocate to_delete
  wend
  entity=world->first_mesh
  while entity<>0
    vertex=entity->first_vertex
    while vertex<>0
      to_delete=vertex
      vertex=vertex->next_vertex
      deallocate to_delete
    wend
    triangle=entity->first_triangle
    while triangle<>0
      to_delete=triangle
      triangle=triangle->next_triangle
      deallocate to_delete
    wend
    to_delete=entity
    entity=entity->next_entity
    deallocate to_delete
  wend
  deallocate world
end sub