' ------------------------------------------------------------
'   n3xt-D exemples
'
'   Sample  045  :  Little2D game version 3D
'   Historique  :
'     29/03/09  19:16    TMyke
'
' ------------------------------------------------------------

' Includes libraries
#include "N3xtD.bi"

Declare Sub Init()
declare Sub CreateMeteor(rad as single, numcol as Integer)
declare Sub CreateProjectil()
declare Sub UpdatePlayer()
declare Sub UpdateMeteor()
declare Sub UpdateExplode()
declare Sub UpdateProjectil()
Declare Sub DeathPlayer()
declare sub RenderAllSprite2D()
declare Sub DeleteProjectil(num as Integer)
declare Function CollideProjectil(numProj as Integer) as Integer
declare Sub GenerateExplode(col as Integer)
declare Sub DeleteMeteor(num as Integer) 
declare Function CollideMeteor(numMeteor as Integer) as Integer
Declare sub Set2DCamera(wwidth As single, height As Single)
Declare Sub Set3DCamera()
Declare Sub Visible3D( flag As Byte)
Declare Sub Visible2D( flag As Byte)

' dimes
Dim app As any Ptr
Dim Quit As Integer

'----------------------------------------------------------
' open n3xt-D screen
app = _CreateGraphics3D(800,600)
If app=NULL Then
  End
End If
  
'----------------------------------------------------------
'     Structures definition
'----------------------------------------------------------
'{ Player definition
Type PLAYER
  dim sp as SpriteSceneNode
  Dim posx as Single
  Dim posy as Single
  Dim radius as Single
End Type
'--}

'{ Meteor definition
Type METEOR
  Dim mesh as EntityNode
  Dim posx as Single
  Dim posy as Single
  Dim transx as Single
  Dim transy as Single
  Dim vcreated as Integer
  Dim radius as Single
End Type
'--}

'{ Projectil definition
Type BALL
  Dim sprite as SpriteSceneNode
  Dim posx as Single
  Dim posy as Single
  Dim transx as Single
  Dim transy as Single
  Dim created as Integer
  Dim radius as Single
End Type
'--}

'{ Explode definition
Type EXPLO
  Dim sp as SpriteSceneNode
  Dim anim as NNodeAnimator
  Dim posx as Single
  dim posy as Single
End Type
'--}
#Define MAXEXPLODE  8

Dim Shared play as PLAYER
Dim Shared EndPlayer as Integer=0
Dim Shared speed as Single=10.0
Dim Shared proj(17) as BALL
Dim Shared num_proj as Single=0
Dim Shared meteorB(64) as METEOR
Dim Shared exp0(MAXEXPLODE) as EXPLO
Dim Shared proj_matrix(17) as Single
Dim Shared score as Integer=0
Dim Shared integererval_score as Integer=0
Dim i as Integer

'----------------------------------------------------------
'----------------------------------------------------------
' init all values And structures
Init()





'-----------------------------------------
'-----------------------------------------
' Create ball sprite
dim shared ballmesh as Mesh 
 ballmesh = _CreateSpriteMesh( 12.0)


'-----------------------------------------
' Create sphere meteor mesh
dim shared spheremesh as Mesh 
spheremesh = _CreateSphereMesh(1.0, 6)

'-----------------------------------------
'-----------------------------------------
' Create PLAYER 
dim shared playmesh as Mesh 
playmesh = _CreateSpriteMesh( 50.0)
play.sp = _CreateSprite3D(playmesh, "media/space1.png")
_MaterialTypeNode(play.sp, EMT_TRANSPARENT_ALPHA_CHANNEL)
_PositionNode(play.sp, 0,0,1)
play.radius = 40.0


'-----------------------------------------
'-----------------------------------------
' Create EXPLODE PLAYER 
Dim shared playerexplodemesh As Mesh 
 playerexplodemesh = _CreateSpriteMesh(160, &h00ffffff)
Dim shared player_explode As SpriteSceneNode 
 player_explode = _CreateSprite3D(playerexplodemesh, "media/Particle.png")
' adapt material blend value
Dim material As NMaterial = _NodeMaterial(player_explode, 0)
_TypeMaterial(material,  EMT_ONETEXTURE_BLEND )
_TypeBlendMaterial(material, EBF_ONE, EBF_ONE_MINUS_SRC_COLOR,	EMFN_MODULATE_1X,  EAS_TEXTURE Or EAS_VERTEX_COLOR) 
' Create explose sequance texture
Dim texturelist As NArray = _CreateListTexture("media/explo2.bmp",64,64)
Dim anim As NNodeAnimator = _CreateTextureAnimator( texturelist,  130)
_AddAnimatorTexture(player_explode, anim)
_VisibleNode(player_explode, False) ' no render



'-----------------------------------------
'-----------------------------------------
' Create thie first meteors
For i = 0 To 7 
	 CreateMeteor(50.0, -1)
Next



'-----------------------------------------
'-----------------------------------------
' Create first  camera
dim Shared cam As CameraNode 
cam = _CreateCamera()
_PositionNode(cam,0,0,-50)



'-----------------------------------------
'-----------------------------------
' Load background textures
Dim texture As NTexture = _LoadTexture("media/metal13.jpg")


'-----------------------------------------
' Load fonts
_LoadFont("media/courriernew.png")
dim font As IGUIFont = _GetFont()
_LoadFont("media/font0.xml")
Dim font2 As IGUIFont = _GetFont()


'----------------------------------------
' Create EARTH
'----------------------------------------
Dim obj1 As Mesh = _LoadMesh("media/earth.x")
Dim obj0 As Mesh = _CreateMeshWithTangents(obj1)
_FreeLoadedMesh(obj1) 
' set the alpha value of all vertices To 200
_VertexColorAlphaMesh(obj0,  190)
' scale And position mesh
_ScaleMesh(obj0, 16,16,16)

Dim Shared sphere As EntityNode 
 sphere= _CreateEntityNode(obj0)
' Create New sphere with tangent composants
_PositionNode(sphere, -70,130,45)
' Load heightmap, Create normal map from it And set it
Dim earthNormalMap As NTexture = _LoadTexture( "media/earthbump.bmp") 
' Creates a normal map from a height map texture. 
_NormalMapTexture(earthNormalMap, 9.0) 
_MaterialTextureNode(sphere, earthNormalMap , 1)
' adjust material settings
_MaterialTypeNode(sphere,  EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA )
_PositionNode(sphere, 0,0,5)
'-----------------------------------------


'----------------------------------------
' Create light And set position
Dim Shared light As LightNode 
 light = _CreateLight(&hffffffff, 150)
  _PositionNode(light, 10, 20,-2)
'----------------------------------------


' save 3D data 
Set2DCamera(800,600)
'-----------------------------------------
' ---------------------------------------
'           Main loop
' ---------------------------------------
'-----------------------------------------
While Quit=0
 

' If Escape Key, Exit	
  If _GetKeyDown(KEY_ESCAPE) then
    Quit=1
  EndIf
   
  _TurnNode(sphere,0,0.2,0)

  If _GetKeyDown(KEY_ARROW_LEFT) Then
      _TurnNode(play.sp, 0,0,3)
  EndIf
  If _GetKeyDown(KEY_ARROW_RIGHT) Then
      _TurnNode(play.sp, 0,0,-3)
  EndIf
  If _GetKeyDown(KEY_ARROW_UP) Then
      _MoveNode(play.sp,0,-3,0)
  EndIf
  If _GetKeyDown(KEY_ARROW_DOWN) Then
      _MoveNode(play.sp,0,3,0)
  EndIf
  
  If _GetKeyUp(KEY_SPACE) Then
     CreateProjectil() 
  EndIf
  

  If EndPlayer=0 Then
    UpdatePlayer()
    UpdateProjectil()
    UpdateMeteor()
    UpdateExplode()
  Else
    DeathPlayer()
  EndIf
  
  ' ---------------
  '      Render
  ' ---------------
  _BeginScene(20,20,20)
  
  _VisibleNode(player_explode, False)
 
     Visible3D( True) 
     Visible2D( False)
     Set3DCamera()
        If EndPlayer<>0 Then _VisibleNode(player_explode, False)
        _DrawRectImage2D(texture ,0,  0, 0,0,800,600, &hff555555 )
        _DrawScene()
        
        
     Visible2D( True)  
     Visible3D( False)
     Set2DCamera(800,600)
        If  EndPlayer<>0 Then _VisibleNode(player_explode)          
        _DrawScene()
        _DrawText(font, "score: "+ Str(score),  10,10,0,0, &hffffffff)
        _DrawText(font, "Use 'dir' and 'space' key",  450,8,0,0, &hff00ffff)
        If EndPlayer<>0 Then
          _DrawText(font2, "END",  360,250,0,0, &hffffff00)
          _DrawText(font2, "score: "+ Str(score),  350,310,0,0, &hffff00ff)
        EndIf 


  _EndScene()
  ' ---------------
  '  End Render
  ' ---------------
Wend 
' end
_FreeEngine()


'-----------------------------------------
'-----------------------------------------
'-----------------------------------------
' { initialise structures
Sub Init()
	Dim i as Integer
    ' init projectil tab
    For i = 0 To 16
      proj(i).sprite = Null
      proj(i).created = 0
    Next
    For i = 0 To MAXEXPLODE-1
      exp0(i).sp = Null
      exp0(i).anim = Null
    Next
End Sub

' }

'-----------------------------------------

' { set camera in 2D mode
sub Set2DCamera(wwidth As single, height As single)
  dim mat(17) As Single  
  _CameraProjectionMatrix(cam, Varptr (proj_matrix(0)))
  _ProjectionMatrixOrthoLH( wwidth, height, Varptr (mat(0)) )
  _ProjectionMatrixCamera(cam,  Varptr (mat(0)),  FALSE)
End Sub 
' }
' { set camera in 2D mode
Sub Set3DCamera()
  _ProjectionMatrixCamera(cam,  Varptr (proj_matrix(0)))
End Sub
' }

'-----------------------------------------

' { update player
Sub UpdatePlayer()
  Dim  pos_space(3) as Single

  _NodePosition(play.sp, Varptr (pos_space(0)) )
  play.posx =  pos_space(0)
  play.posy =  pos_space(1)
  
  If ( play.posx>450 ) Then  play.posx = -450 : _PositionNode(play.sp, play.posx, play.posy, 1)
 	If ( play.posx<-450 )Then 	play.posx = 450  : _PositionNode(play.sp, play.posx, play.posy, 1)
 	If ( play.posy>350 ) Then  play.posy = -350 : _PositionNode(play.sp, play.posx, play.posy, 1) 
 	If ( play.posy<-350 ) Then 	play.posy = 350 : _PositionNode(play.sp, play.posx, play.posy, 1)

End Sub
' }

'-----------------------------------------

' { update all projectils
Sub UpdateProjectil()
    Dim col as integer, rd as Single, i as Integer
    
    For i = 0 To 16
      If proj(i).created <> 0  Then
        proj(i).posx = proj(i).posx + proj(i).transx
        proj(i).posy = proj(i).posy + proj(i).transy
        _PositionNode( proj(i).sprite, proj(i).posx, proj(i).posy, 1)
	  If ( proj(i).posx>400 Or  proj(i).posx<-400 ) Then 	DeleteProjectil(i)
	  If ( proj(i).posy>300 Or  proj(i).posy<-300 ) Then 	DeleteProjectil(i)
	  col = CollideProjectil(i)
	  If col<>-1  Then
	    rd = meteorB(col).radius
	    DeleteProjectil(i)
	    If rd>13  Then
	      rd = rd / 2.0
	      CreateMeteor(rd, col)
	      CreateMeteor(rd, col)
	    Else
	      ' explosion
	      GenerateExplode(col)
	    EndIf  
	    DeleteMeteor(col)			  
	  EndIf
      EndIf
    Next
End Sub
' }

' { Create projectils (16 maxi)
Sub CreateProjectil()
    Dim pos_space(3) as Single
    Dim rot_space(3) as Single
    Dim i as Integer

    num_proj = -1
    FOR i = 0 To 15
      If proj(i).created = 0 Then
        num_proj = i
        exit for
      EndIf
    NEXT
    If num_proj<0 Then Return
          
     proj(num_proj).sprite = _CreateSprite3D(ballmesh,"media/Particle.png")
    _MaterialTypeNode(proj(num_proj).sprite, EMT_TRANSPARENT_ALPHA_CHANNEL)

    _NodePosition(play.sp, Varptr (pos_space(0)) )
    _NodeRotation(play.sp, Varptr (rot_space(0)) )

    pos_space(0) = pos_space(0) + Sin( -rot_space(2)*0.01745329 ) * 55.0
    pos_space(1) = pos_space(1) + Cos( -rot_space(2)*0.01745329 ) * 55.0
     
    _PositionNode(proj(num_proj).sprite, pos_space(0), pos_space(1), pos_space(2))
    proj(num_proj).posx = pos_space(0)
    proj(num_proj).posy = pos_space(1)
    proj(num_proj).transx = Sin( -rot_space(2)*0.01745329) * speed
    proj(num_proj).transy = Cos( -rot_space(2)*0.01745329) * speed
    proj(num_proj).created = 1
    proj(num_proj).radius = 10.0
End Sub
' }

' { destruct projectil
Sub DeleteProjectil(num as Integer)
  If (proj(num).sprite) Then
    _FreeNode(proj(num).sprite)
    proj(num).sprite = Null
    proj(num).created = 0
  EndIf
End Sub
' }

'-----------------------------------------

' { Create Meteor 
sub CreateMeteor(rad as single, numcol as Integer)
    Dim pos_space(3) As Single
    Dim rot_space(3) as Single
    Dim i as Integer
    Dim num_meteor as Integer, posx as single=0, posy as Single=0

    num_meteor = -1
    For i = 0 To 63
      If meteorB(i).vcreated = 0 then
        num_meteor = i
        Exit for
      EndIf
    Next
    If num_meteor<0 Then Return

         meteorB(num_meteor).mesh = _CreateEntityNode(spheremesh)
        _ScaleNode(meteorB(num_meteor).mesh, rad,rad,rad)
        _LoadTextureNode( meteorB(num_meteor).mesh, "media/wall.jpg") 
        _MaterialFlagNode(meteorB(num_meteor).mesh,  EMF_LIGHTING, False )

      
        If numcol<0  Then
          do
            posx = Rnd()*800.0
          loop Until (posx<250.0 Or posx>550.0)
          posx = posx -400.0
          Do
            posy = Rnd()*600.0
          loop Until (posy<200.0 Or posy>400.0)
          posy = posy -300.0
        Else
          posx = meteorB(numcol).posx
          posy = meteorB(numcol).posy
        EndIf
        _PositionNode(meteorB(num_meteor).mesh, posx, posy, 1 )
        meteorB(num_meteor).posx = posx
        meteorB(num_meteor).posy = posy

        meteorB(num_meteor).transx = -1.5+Rnd()*3.0
        meteorB(num_meteor).transy = -1.5+Rnd()*3.0
        meteorB(num_meteor).vcreated = 1
        meteorB(num_meteor).radius = rad
   
End Sub
' }

' { update all meteor
Sub UpdateMeteor()
  Dim i as Integer
    For i = 0 To 63
      If meteorB(i).vcreated<> 0  Then
        meteorB(i).posx = meteorB(i).posx + meteorB(i).transx
        meteorB(i).posy = meteorB(i).posy + meteorB(i).transy
        _PositionNode( meteorB(i).mesh, meteorB(i).posx, meteorB(i).posy, 1)
              
 			  If ( meteorB(i).posx>450 ) Then meteorB(i).posx = -450
 			  If ( meteorB(i).posx<-450 )Then meteorB(i).posx = 450
 			  If ( meteorB(i).posy>350 ) Then meteorB(i).posy = -350
 			  If ( meteorB(i).posy<-350 )Then meteorB(i).posy = 350
    
        _TurnNode(meteorB(i).mesh, 0,0,0.5)
 			  
 			  If CollideMeteor(i)<>0  Then
 			    EndPlayer = 11
 			  EndIf
      EndIf
    Next
End Sub
' }

' { destruct meteor
Sub DeleteMeteor(num as Integer) 
  _FreeNode(meteorB(num).mesh)
  meteorB(num).mesh = Null
  meteorB(num).vcreated = 0
End Sub
' }

'-----------------------------------------

' { test collide between palyer spaceship And one meteor
Function CollideMeteor(numMeteor As integer) As Integer
  dim dist As single, bt As single, col As single
  
  dist = play.radius + meteorB(numMeteor).radius
  ' cal distance
  bt =  (play.posx - meteorB(numMeteor).posx)*(play.posx - meteorB(numMeteor).posx) + (play.posy - meteorB(numMeteor).posy)*(play.posy - meteorB(numMeteor).posy) 
  bt = Sqr(bt)
  col = 0
  If bt<dist Then  col = 1 
 Return col
End Function

' }

' { test collide between palyer spaceship And one meteor
Function CollideProjectil(numProj as Integer) as integer
  Dim dist as single, bt as Single, col as Integer
  Dim i as Integer

  col = -1
  For i = 0 To 63
   If meteorB(i).vcreated <> 0  Then
    dist = proj(numProj).radius + meteorB(i).radius
    ' cal distance
    bt = (proj(numProj).posx - meteorB(i).posx)*(proj(numProj).posx - meteorB(i).posx) + (proj(numProj).posy - meteorB(i).posy)*(proj(numProj).posy - meteorB(i).posy) 
    bt = Sqr(bt)
    If bt<dist Then col = i : Return col 
   EndIf
  Next
  Return -1
End Function
' }

'-----------------------------------------

' { Generate Explode
Sub GenerateExplode(col as Integer) 
  Dim posx as single, posy as Single
  Dim num_exp as integer=-1, i as Integer
 
  score = score + 1
  integererval_score = integererval_score + 1
  If (integererval_score=4) Then
    integererval_score=0 
    CreateMeteor(50.0, -1)
  EndIf
  
  posx = meteorB(col).posx
  posy = meteorB(col).posy
  
  num_exp = -1
  For i = 0 To MAXEXPLODE-1
      If exp0(i).sp = Null  Then
        num_exp = i
        Exit For
      EndIf
  Next
  If num_exp<0 Then Return

  Dim spmesh As Mesh = _CreateSpriteMesh( 50.0)
  Exp0(num_exp).sp = _CreateSprite3D(spmesh, "media/Particle.png")
  _MaterialTypeNode(Exp0(num_exp).sp, EMT_TRANSPARENT_ALPHA_CHANNEL)
  
  ' Create explose sequance texture
  Dim texturelist as NArray = _CreateListTexture("media/explode.png", 64, 64)
  exp0(num_exp).anim = _CreateTextureAnimator( texturelist,  130, False)
  _AddAnimatorTexture(exp0(num_exp).sp, exp0(num_exp).anim)
  
  _PositionNode( exp0(num_exp).sp, posx, posy, 1)
  _VisibleNode( exp0(num_exp).sp )

End Sub
' }

' { Update Explode
Sub UpdateExplode() 
  Dim i as integer
  For i = 0 To MAXEXPLODE-1
    If(exp0(i).sp)  Then
       If ( _AnimatorTextureIndex(exp0(i).anim) = _AnimatorTextureSize(exp0(i).anim)-1 )  then
          _FreeNode( exp0(i).sp )
          exp0(i).sp = Null
          exp0(i).anim = Null
      EndIf
    EndIf
  Next

End Sub
' }

'-----------------------------------------
' { Death Player
Sub DeathPlayer()
   dim  pos_space(3) As Single

  _NodePosition(play.sp, Varptr (pos_space(0)) )
  _PositionNode(player_explode, pos_space(0), pos_space(1), 0.1)

End Sub
' }

'-----------------------------------------
' { turn OFF  Or ON 3D elements
Sub Visible3D( flag As Byte)
  _VisibleNode(light,  flag) 
  _VisibleNode(sphere, flag)   
End Sub 
' }

' { turn OFF  Or ON 2D elements
sub Visible2D( flag As Byte)
  dim i As Integer
  _VisibleNode(play.sp,  flag) 
  For i = 0 To 16
    If ( proj(i).sprite ) Then  _VisibleNode(proj(i).sprite, flag)
  Next
  For i = 0 To 63
    If ( meteorB(i).mesh ) Then _VisibleNode(meteorB(i).mesh, flag)
  Next
  For i = 0 To MAXEXPLODE-1
    If ( Exp0(i).sp ) Then _VisibleNode(Exp0(i).sp, flag)
  Next
End sub
' }
