Code archives/3D Graphics - Effects/3D Elite Style Scanner

This code has been declared by its author to be Public Domain code.

Download source code

3D Elite Style Scanner by Krischan2010
This demo shows the use of a 3D space scanner like in the game "Elite". It shows a type field within a given distance with "blips" and "poles" attached to the blips - they represent the relative height to the centered spaceship. The demo creates two procedural textures blended together to get a nice glowing radar screen. Arrows/Mouse to move, LMB=increase speed, RMB=halves scanner range. Have fun!

Edit: shortened code and added color schemes / more constants to declare.

AppTitle "3D Elite Style Scanner"

Graphics3D 800,600,32,2

Const TurnSpeed#    = 4.00      ; cam turn speed
Const RollSpeed#    = 0.50      ; cam roll speed
Const CameraSpeed#  = 1.00      ; cam move speed
Const Objects%      = 2000      ; number of space objects
Const RadarSize%    = 256       ; radar size in pixels

Const PoleWidth#    = 1.0       ; width of poles
Const BlipSize#     = 3.0       ; size of radar blip
Const VertScale#    = 1.0       ; height multiplicator of pole/blip
Const RadarBorder#  = 0.9       ; range within 1.0 to display

; color scheme: blue
Const R1%=  0,G1%=128,B1%=192   ; grid lines color
Const R2%=  0,G2%= 16,B2%= 32   ; scanner background color
Const R3%=  0,G3%=128,B3%=255   ; scanner border glow color

; color scheme: green
;Const R1%=  0,G1%=192,B1%=  0   ; grid lines color
;Const R2%=  0,G2%= 32,B2%=  0   ; scanner background color
;Const R3%=  0,G3%=255,B3%=  0   ; scanner border glow color

Type blip
    
    Field entity%
    Field blip%
    Field pole%
    Field x#,y#,z#
    Field vx#,vy#,vz#
    Field r%,g%,b%
    Field size#
    
End Type

Global WIDTH%=GraphicsWidth()
Global HEIGHT%=GraphicsHeight()
Local TIMER%=CreateTimer(60)

; camera
Local CAM%=CreateCamera()
CameraRange CAM,1,WIDTH+RadarSize

; setup radar
Local RADAR=InitRadar(RadarSize,512,10,CAM)

; setup objects
InitObjects(RADAR,Objects,1000)

MoveMouse WIDTH/2,HEIGHT/2

While Not KeyHit(1)
    
    Local range%=256,visible%
    
    ; move player
    Movement(CAM)
    
    ; RMB = short range radar
    If MouseDown(2) Then range=128
    
    ; update radar
    visible%=UpdateRadar(CAM,RADAR,RadarSize,range,90)
    
    RenderWorld
    
    WaitTimer TIMER
    
    Text 0, 0,"Scanner range....: "+range
    Text 0,15,"Objects / visible: "+Objects+" / "+visible
    
    Flip
    
Wend

End

; populate scene with dummy objects
Function InitObjects(radar%,number%=100,range#=500.0)
    
    Local i%,b.blip
    
    For i=1 To number
        
        b.blip = New blip
        b\entity=CreateCone(16)
        b\blip=CreateSphere(6,radar)
        b\pole=CreateCube(radar)
        b\x=Rnd(-range,range)
        b\y=Rnd(-range,range)
        b\z=Rnd(-range,range)
        b\vx=Rnd(-0.1,0.1)
        b\vy=Rnd(-0.1,0.1)
        b\vz=Rnd(-0.1,0.1)
        b\r=Rand(255)
        b\g=Rand(255)
        b\b=Rand(255)
        b\size=2
        
        ; align "ship" to its flight vector
        AlignToVector b\entity,b\vx,b\vy,b\vz,2,1
        
        ; create the entity itself
        PositionEntity b\entity,b\x,b\y,b\z
        EntityFX b\entity,1
        EntityColor b\entity,b\r,b\g,b\b
        ScaleEntity b\entity,b\size,b\size*2,b\size
        EntityAutoFade b\entity,1,range
        
        ; creates a radar blip
        EntityFX b\blip,1
        EntityOrder b\blip,-100
        EntityColor b\blip,b\r,b\g,b\b
        
        ; creates a blip pole
        EntityFX b\pole,1
        EntityOrder b\pole,-100
        EntityColor b\pole,b\r,b\g,b\b
        
    Next
    
End Function

; simple spaceship movement
Function Movement(cam%,sensitivity#=1.0)
    
    Local roll#,cz#,tx#,ty#,multi%=1
    
    ; arrows = move / SHIFT or LMB = Turbo
    cz=(KeyDown(200)-KeyDown(208))*CameraSpeed
    roll=(KeyDown(203)-KeyDown(205))*RollSpeed
    If KeyDown(42) Or KeyDown(54) Or MouseDown(1) Then multi=10
    
    tx=Normalize(MouseX(),0,WIDTH , 1,-1)
    ty=Normalize(MouseY(),0,HEIGHT,-1, 1)
    
    If ty<0 Then ty=(Abs(ty)^sensitivity)*-1 Else ty=ty^sensitivity
    If tx<0 Then tx=(Abs(tx)^sensitivity)*-1 Else tx=tx^sensitivity
    
    TurnEntity cam,ty*TurnSpeed,tx*TurnSpeed,roll*TurnSpeed
    MoveEntity cam,0,0,cz*multi
	
End Function

; creates a nice elite stype radar sprite at screen bottom
Function InitRadar(scale#,size%=512,quads%=8,parent%=False,sharp#=1.0,blur#=50.0)
    
    Local RADAR%=CreateQuad()
    EntityParent RADAR,parent
    Local tex1%=CreateGridTexture(size,quads)
    Local tex2%=CreateGlowTexture(size,sharp,blur)
    
    ; apply textures to radar quad
    EntityFX RADAR,1
    ScaleEntity RADAR,scale,scale,scale
    PositionEntity RADAR,0,-HEIGHT+(RadarSize*0.75),WIDTH
    TextureBlend tex1,2
    TextureBlend tex2,3
    EntityTexture RADAR,tex1,0,1
    EntityTexture RADAR,tex2,0,2
    EntityBlend RADAR,1
    
    ; create centered ship marker (you!)
    Local CENTER%=CreateCone(3,1,RADAR)
    RotateMesh CENTER,30,0,0
    PositionEntity CENTER,0,0,0
    ScaleEntity CENTER,1.0/32,1.0/32,1.0/32
    EntityFX CENTER,1
    EntityColor CENTER,255,255,0
    
    EntityOrder CENTER,-20
    EntityOrder RADAR,-10
    
    Return RADAR
    
End Function

; updates the radar scene
Function UpdateRadar(cam%,radar%,scale#=128.0,range#=256.0,angle#=60.0)
    
    Local b.blip
    Local d#
    Local rx#,ry#,rz#
    
    Local halfscale#=scale/2.0
    Local doublescale#=scale*2.0
    Local ps#=PoleWidth/scale
    Local bs#=BlipSize/halfscale
    Local div#=((scale/2.0)/range)*RadarBorder
    
    Local visible%=0
    
    For b.blip = Each blip
        
        ; dumb object movement
        b\x=b\x+b\vx
        b\y=b\y+b\vy
        b\z=b\z+b\vz
        PositionEntity b\entity,b\x,b\y,b\z
        
        ; get distance to object
        d=EntityDistance(b\entity,cam)
        
        ; within scanner range?
        If d<range Then
            
            visible=visible+1
            
            ; show blip and its pole
            ShowEntity b\pole
            ShowEntity b\blip
            
            ; transform position
            TFormPoint (b\x,b\y,b\z,0,cam)
            rx=-TFormedX()/halfscale*div
            rz=TFormedZ()/halfscale*div
            ry=TFormedY()*div
            
            ; reposition/scale blip
            PositionEntity b\blip,0,0,0
            TranslateEntity b\blip,rx,rz,ry/scale*VertScale
            ScaleEntity b\blip,bs,bs,bs
            
            ; reposition/scale pole
            PositionEntity b\pole,0,0,0
            ScaleEntity b\pole,ps,ps,ry/doublescale*VertScale
            TranslateEntity b\pole,rx,rz,ry/doublescale*VertScale
            
        Else
            
            ; hide blip and its pole
            HideEntity b\pole
            HideEntity b\blip
            
        EndIf
        
    Next
    
    ; radar always points to cam
    RotateEntity radar,-angle,180,0
    
    Return visible
    
End Function

; simple quad creation
Function CreateQuad(r%=255,g%=255,b%=255,a#=1.0)
    
    Local mesh%,surf%,v1%,v2%,v3%,v4%
    
    mesh=CreateMesh()
    surf=CreateSurface(mesh)
    
    v1=AddVertex(surf,-1,1,0,1,0)
    v2=AddVertex(surf,1,1,0,0,0)
    v3=AddVertex(surf,-1,-1,0,1,1)
    v4=AddVertex(surf,1,-1,0,0,1)
    
    VertexColor surf,v1,r,g,b,a
    VertexColor surf,v3,r,g,b,a
    VertexColor surf,v2,r,g,b,a
    VertexColor surf,v4,r,g,b,a
    
    AddTriangle(surf,0,1,2)
    AddTriangle(surf,3,2,1)
    
    FlipMesh mesh
    
    Return mesh
    
End Function

; create procedural glowing border texture
Function CreateGlowTexture(size%=512,sharpness#=1.0,blur#=50.0)
    
    Local strength#=512*1.0/size*sharpness
    Local tex%=CreateTexture(size,size,3)
    Local tb%=TextureBuffer(tex)
    
    Local x%,y%,i#,j%,col%,rgb%,rc%,gc%,bc%
    
    LockBuffer tb
    
    For x=0 To size-1
        
        For y=0 To size-1
            
            ; clear colors
            rgb=0*$1000000+0*$10000+0*$100+0
            WritePixelFast x,y,rgb,tb
            
        Next
        
    Next
    
    For j=1 To (size/2)-2
        
        ; exponential falloff
        col=j*strength/Exp((((size/2)-2)-j)*(strength/blur))
        
        If col>224 Then col=Normalize(col,224,255,224,0)
        If col<0 Then col=0
        
        ; multiply RGB with brightness
        rc=R3*col Shr 8
        gc=G3*col Shr 8
        bc=B3*col Shr 8
        
        rgb=255*$1000000+rc*$10000+gc*$100+bc
        
        For i=0 To 360 Step 0.05
            
            WritePixelFast ((size-2)/2.0)+(Sin(i)*j),((size-2)/2.0)+(Cos(i)*j),rgb,tb
            
        Next
        
    Next
    
    UnlockBuffer tb
    
    Return tex
    
End Function

; normalize a value
Function Normalize#(value#=128.0,vmin#=0.0,vmax#=255.0,nmin#=0.0,nmax#=1.0)
    
    Return ((value#-vmin#)/(vmax#-vmin#))*(nmax#-nmin#)+nmin#
    
End Function

; create radar grid texture
Function CreateGridTexture(size%=512,quads%=16)
    
    Local x%,y%,j%,i#,rgb%,col%,r%,g%,b%
    Local steps%=size/quads
    
    Local tex%=CreateTexture(size,size,3+8)
    Local buffer%=TextureBuffer(tex)
    
    SetBuffer buffer
    
    ; background color
    Color R2,G2,B2
    Rect 0,0,size,size,1
    
    ; create grid
    Color R1,G1,B1
    For x=0 To quads-1
        For y=0 To quads-1
            Rect x*steps,y*steps,steps+1,steps+1,0
        Next
    Next
    
    Color 255,255,255
    
    LockBuffer buffer
    
    ; create glowing border and delete pixels outside the circle
    For j=(size/2)-6 To size
        
        For i=0 To 360 Step 0.05
            
            x=((size-2)/2.0)+(Sin(i)*j)
            y=((size-2)/2.0)+(Cos(i)*j)
            
            col=0
            If j<=(size/2) Then col=Normalize(j,(size/2)-6,(size/2),255,0)
            
            ; multiply RGB with brightness
            r=R3*col Shr 8
            g=G3*col Shr 8
            b=B3*col Shr 8
            
            rgb=0*$1000000+r*$10000+g*$100+b
            
            If x>=0 And x<size And y>=0 And y<size Then
				
                WritePixelFast x,y,rgb,buffer
                
            EndIf
            
        Next
        
    Next
	
    UnlockBuffer buffer
    
    SetBuffer BackBuffer()
    
    Return tex
    
End Function

Comments

puki2010
Cool.


BlitzSupport2010
Yeah, very nicely done. The demo itself has a really good feel to it too.


_PJ_2010
Nice! I love the effect and how it's been done as a textured mesh rather than direct 2D drawing :)
Really useful!


Krischan2010
For a clean 3D only variant take a look at this. Here I'm using quads as blips and poles to create the radar echoes instead of cubes and spheres. They are textured, too! Looks even more cool now.






puki2010
Here are the two images together, it makes it easier to cross-reference:




Blitzplotter2010
Indeed, very cool & inspiring - lovely piece of coding. In fact it inpsired me to look at the relative distance of the planets & their paths through our solar system:-

http://www.solarviews.com/eng/solarsys.htm


Code Archives Forum