Worklog for AntMan - Banned in the line of duty.

Worklog 1

Return to Worklogs

Mission Decision.(Posted 2006-05-05)
Right now we're investigating various physics apis.

Newton is a safe bet. It works and it is within our arsenal already.
But Ad recieved some good news regarding Ageia Physx(The api with a specialized ppu card to come) that it is free to use in most types of games.

It's apperently capable of 1000 entities on a 1ghz compared to 100 with ode on the same machine.

The game will be a tale of turn based combat. Hopefully weaved in some form of Narrative. Nothing too grand but enough to propel the player forward beyond the accumulation of points.

We're likely to use some forms of weapon upgrades/cards to spice things up. Well If I have my way we are. :)


No known decimal system is adequate.(Posted 2006-04-23)
Aurora 3D Lite has released. Half the price of the now entitled pro version but without Blitz Net Optica(Networking) and MaxAVI(AVI reading)

Buy it now, you won't regret it.


Two billion and counting.(Posted 2006-04-18)
Just been writing a doc to html generator. It's quite a nice process really. You can view the docs in the custom exe viewer or view the html it generates the first time you run.

Here's some sample code from the generator just to show how cool it is. It's cool because I said it's cool. You dig?

Type TDoc2HTml
	
	Global ad:Tdoc
	Global fold:String
	
	Function Do( in:Tdoc,folder:String )
	
		ad = in
		If FileType(folder)=0
			CreateDir( folder )
		EndIf
		GenerateIndex()
		
	
	End Function
	
	Function GenerateIndex()
		
		thml.write(	fold+"index.html" )
		thml.header("Aurora Doc System Index")
		thml.bodyhead()
		thml.headhead(3,"center")
		thml.text("Aurora Online API Reference")
		thml.headfoot(3)
		WriteIndex()
		thml.bodyfoot()
		thml.footer()
		thml.close()
		
	End Function
	
	Function WriteIndex()
	
		thml.listhead()
			'---Write Types
			
			For Local t:TType = EachIn ad.types
				thml.itemHead()
				thml.text(t.name)
				thml.listhead()
				thml.itemhead()
				thml.text("General")
				thml.listhead()
				For Local tb:TBody = EachIn t.bodies
					thml.itemhead()
					thml.LinkHead( t.name+tb.name+".html" )
					thml.text( tb.name )
					thml.linkfoot()
					thml.itemfoot()
				Next
				thml.listfoot()
				thml.itemfoot()
				thml.itemHead()
				thml.text("Methods")
				thml.listhead()
				For Local m:tmethod = EachIn t.methods
					For Local tb:TBody = EachIn m.bodies
						thml.itemhead()
						thml.linkhead( t.name+m.name+tb.name+".html" )
						thml.text( tb.name )
						thml.linkfoot()
						thml.itemfoot()
					Next
				Next
				thml.listfoot()
				thml.itemfoot()
			
				thml.itemHEad()
				thml.text("Functions")
				thml.listhead()
				For Local f:Tfunction = EachIn t.functions
					For Local tb:Tbody = EachIn f.bodies
						thml.itemhead()
						thml.linkhead( t.name+f.name+tb.name+".html" )
						thml.text( tb.name )
						thml.linkfoot()
						thml.itemfoot()
					Next
				Next
				thml.listfoot()
				thml.itemfoot()
				thml.itemfoot()
				
			Next
			
			
			'---Write General Bodies
			thml.itemHead()
			thml.text("General")
			thml.listhead()
			For Local tb:Tbody = EachIn ad.bodies
				thml.itemhead()
				'thml.text( tb.name )
				thml.LinkHead( tb.name+".html" )
				thml.text( tb.name )
				thml.linkfoot()
				thml.itemfoot()
			Next
			thml.listfoot()
			thml.itemFoot()
		
		thml.listfoot()
	
	End Function
		
	Function GenerateBodies()
		
		
		
	End Function
	

End Type




The only downside is I spent all morning learning html to do this, so my html skills are not exactly guru like, so it's going to be mimiallistic. But it serves it's purpose well.

CKOB has write the first of his series of exampels for Aurora. check out the private club at the aurora forums if you're a license holder.
I think his series will grow to prove the first choice resource for people new to Aurora. And that's everyone at this point.

Wait a minute, just passsed three billion. What am I still doing here when I have all this money you ask? Good question. *Walks away into the sunset*


3D Made EZ(Posted 2006-04-16)
The engine has been released. I've sold approximately 3 million copies so far.


Post fx added.(Posted 2006-04-14)
Just finished add post fx, set it up with just two commands(And a compositor script)
The cool thing is you chain compositors together by adding more than one(done in oder of being added)
Example,

TPostFx.Add("Bloom")
TPostFx.Enable("Bloom")
TPostFx.Add("Embossed")
TPostFx.Enable("Embossed"


just four lines of code and you'll now have bloom layer 1 with a second embossed layer over the top.
Rendering remains the same.


Functionality redefined(Posted 2006-04-13)
The list of areas that Aurora covers is growing by the day.. recently we've seen avi, networking, ode additions. Today we add Lua scripts to the armoury.

The script engine, built around lua will have many functions exposed to it that will allow precise control over the entire aurora pipeline. From entities to cameras, from lights to tform commands, all possible in lua scripts.
Aurora will include the public domain lua module with it so the entire aurora package will work out of the bag.


At the moment Aurora is intended for windows only, but there's a good chance we'll see a mac and linux version in the coming months. The only lose will be ode, but you'll still have newton powered physics.

Be sure to check out Evak's recent worklog for a picture of the engine up and running our latest game, Full Metal Conflict Phoniex.


Aurora = OgreMax+BlitzNet+MaxAvi+OgreNewt+Ode = One helluva package(Posted 2006-04-10)
Aurora will include with it studio licenses to blitz net optica, MaxAVI, and free OgreNewt bindings.

Physics are so easy in ogremax you'll never write a game without them. There is just no reason not to use them.

The Ode solution requires the purchurse of JV-ode, on top of Aurora (Not my library, nothing I can do about that) but Newton physics (Which are easier and support cool features like automatic hull generation. convex hulls. line picking, camera picks and much more) are free out of the box.

Coupled with BlitzNet +MaxAVI aurora is shaping up to be the perfect game sdk. Whatever your needs it covers them.
It's going to have so many features you'd forget that it's main reason for being is the extremely powerful ogre powered 3d engine.

Added full animation support yesterday, including looped and anim speed controllers.

You may have to wait a year for max3D, but you don't have to wait a year for a good 3d engine. And even when max3d comes, will it offer networking? Will it offer two physics solutions tightly integrated into the engine for no extra cost? Will it handle movie playback for all so important company logos, cut scenes and ending credits?
Will it offer a free FMOD powered sound engine that allows you to playback/stream virtually any sound format on the market today?
Will it let you stream music over the internet?

It will offer a fine 3d engine, but it will be procedural and will not be oop from the ground up. Mark just doesn't work like that.

The best is yet to come.


Aurora Net Optica(Posted 2006-04-06)
The Network library is nearing compliation.

Here's an example client to show how easy to use it is, it also demonstrates EventCallbacks which are nice ways of handling events compared to standard procedural methods. It does support procedural methods however.

Added a number of cool features, the most important of which is reliable in order packets. So if message C arrives before Message B it will be rejected until Message B Arrives. This works both ways, client and sever.

Each Class Variable can be optionally reliable or unreliable. Unreliable packets are faster because they have no packet ordering and are not sure to arrive.

You can also set an optional pulse rate(In milliseconds) that definte how many times a second the clients update the server.
The network lib is also inteligent in the sense, it will ignore a variable if the value has not changed.

All messages are compressed but are sometimes sent uncompressed if the compression resulted in a higher byte sized message. Which can happen if the message is too small to compress to any useful degree. This ensures the library only sends the smallest sized streams requried.

Strict
Import "Network.bmx"

Local ip$=Input("Network I.P(Leave blank for 127.0.0.1)")
If ip=""
	ip="127.0.0.1"
EndIf
Local name:String =  Input("Name>")
Local nl:TLogger = Tlogger.Create(name)

'Set up client.
Local client:TClient = TClient.Create( name,ip,5555 )

'Create player class template
Local player:TClass = Tclass.create("Ship")
player.addFloat("X",15000)
player.addFloat("Y",15000)
client.addClassTemplate( player )

'---Wait till connected
SeedRnd( MilliSecs() )

'---Create Event callback class.
Type DemoCallBack Extends NEventCallBack
	Method OnNewClass( event:NEvent )
		
		Select event.own.class
			Case "Ship"
				Print "Spawned "+event.own.name
				CreateBot( event.own.name,event.own )
		End Select
	
	End Method
	
	Method OnConnect( event:NEvent )

		Print "Connected.."
		Local play:TClass = client.SpawnClass("Chatter",name )
		Player = CreateBot( name,play )
		play.SetData( Object( Player )
				
	End Method
	
	Method OnUpdateVar( event:NEvent )
	
		Local b:Bot = Bot( event.own.getData() )
		Select event.varo.name
		
			Case "X"
				
				b.x = event.varo.val
				
			Case "Y"
			
				b.y = event.varo.val
		
		End Select
	
	End Method

End Type

Client.RegisterEventCallBack( New DemoCallBack )



'Bot List and Local Player object
Global Bots:Tlist = CreateList()
Global Player:Bot

Type bot
	
	Field net:TClass
	Field x#,y#

	Method Draw()
		DrawRect x-10,y-10,20,20
	End Method

End Type

Graphics 320,240,0


Repeat
Cls
	
	nl.update()
	client.update()
	
	If player<>Null
		player.x:+1
		player.y:+1
		If player.x>320
			player.x=0
		EndIf
		If player.y>240
			player.y=0
		End If
		player.net.setfloat("X",playb.x,False )
		player.net.setfloat("Y",playb.y,False )
	EndIf
	
	
	
	
	
	
	
	client.ClearEvents()
	For Local b:Bot = EachIn bots
		b.draw()
	Next

Flip

Until KeyDown(KEY_ESCAPE)
	
Function CreateBot:Bot( name:String,class:TClass )
	
	Local b:Bot = New bot
	b.net = class
	bots.addlast( b )
	Return b
	
End Function


It will go on sale shortly. Price not yet decided.


Network Library(Posted 2006-04-05)
Aurora will include a fully realised network module that utilises virtual classes to offer a very familiar way of coding networking games..

Here's a cut and paste from our forums and a look at the code as of now. This will be the only code released freely from the project.

=-=-=-=-=-=-=-=-
Here's the current build of the network lib to famalirize yourself with it.

I've just finished the infrostructure, and it's very cool imo. Firstly it groups off all messages by connection, then compresses them before sending. So in a big game with lots of floats we should save a lot of bandwidth.

Currently you can create a server, and connect to it. The server rejects the connection if it passes a set max connection reason. It can also reject it for other reasons when needed.

Rem

	Aurora Net Optica.

		V1.0
		
	(c)Antony Wells 2006
	
	Aurora (c)Antony Wells 2006
	
End Rem
Strict
Import "bnet.bmx"
Import "OgreMaxSystem.bmx"

Const Default_Message_Size = 10240
Const Default_Ack_Cycles = 5

Const Net_Connect = 1,Net_Disconnect =2
Const Net_System = 3,Net_User =4
Const Net_ObjectUpdate = 5,Net_AckConfirm = 6
Const Net_Compressed = 7,Net_Raw = 8
Const Net_ConnectConfirm = 8,Net_ConnectDeny = 9

Const Fail_UserLimit = 1,Fail_Banned = 2,Fail_PingTooLow = 3
Const Fail_Password = 4
Global FailConnect:String[255]
FailConnect[Fail_UserLimit] = "The Server is full."
FailConnect[Fail_Banned] = "Your I.P address is banned from the server."
FailConnect[Fail_PingTooLow] = "Your ping is too low to connect."
FailConnect[Fail_Password] = "Incorrect Password"

Type TMessage
	
	Function Create:TMessage(mtype = Net_Connect,reliable = True,buildBuffer = True)
		
		Local out:TMessage = New tmessage
		If buildBuffer
			out.buf = MemAlloc( Default_Message_Size )
			out.bufs = CreateRamStream( out.buf,default_message_size,True,True )
		EndIf
		out.reliable = reliable
		out.mtype = mtype
		Return out
				
	End Function
	
	
	
	Method Delete()
	
		MemFree buf
		CloseStream bufs
	
	End Method
	
	Field Ack,AckCycles
	Field reliable
	Field Hub:THub
	Field fromIp,fromPort
	Field mtype
	Field Con:TConnection
	Field buf:Byte Ptr
	Field bufs:TRamstream
	
End Type


Const Connection_Active = 1,Connection_Pending = 2,Connection_Remove = 3
Const Connection_Syncing = 4,Connection_Failed = 5

Type TConnection 'Holds one connection record
	
	Field ip,port
	Field hub:THub
	Field recvAck:Long
	Field sendAck:Long
	Field sendPulse:TTimer
	Field name:String
	Field Msgs:TList
	Field Recv:TList
	Field state
	Field WaitAck 
	
	Method New()
	
		msgs = CreateList()
		sendAck = 1
		RecvAck = 0
		recv = CreateList()
		state = connection_active
			
	End Method
	
	Method SendAckConfirm( Ack )
	
		Local M:TMessage = ConstructAckConfirm( Ack )
		AddMessage( M )
	
	End Method
	
		
	Method AddIncoming( Msg:TMessage )
		
		recv.addlast( msg )
			
	End Method
	
	Method AddMessage( Msg:TMessage )
	
		msgs.addlast( msg )	
			
	End Method
	
	Method RequestAck:Long()
		
		Local rt:Long = sendAck
		sendAck:+1
		Return rt
		
	End Method
	
	
	Method RemoveAcks( ack )
	
		For Local m:TMessage = EachIn Msgs
			If m.ack = ack
				Print "Removed Messaged based on Ack:"+Ack
				msgs.remove( m )
			EndIf
		Next
	
	End Method
	
	Method Send()
		
		Local Siz = GetMessagesSize()
		 
		
		Local pool:Byte Ptr = MemAlloc( Siz )
		Local pools:TRamstream = CreateRamStream( pool,siz,True,True )
		
		CopyMessagesToStream( pools )
		If siz = 0 Return
		Local com:Byte Ptr = MemAlloc (Siz*4)
		Local dlen = siz * 4
		compress com,dlen,pool,siz
		'Print "Was "+Siz+" Is "+dlen
		
		If dlen>siz
			
			WriteByte hub.stream,Net_Raw
			SeekStream pools,0
			WriteInt hub.stream,siz
			CopyStream pools,hub.stream
			sendudpmsg hub.stream,ip,port
			
		Else
		
			WriteByte hub.stream,Net_Compressed
			WriteInt hub.stream,dlen
			WriteInt hub.stream,siz
			For Local j=0 Until dlen
				WriteByte hub.stream,com[j] 
			Next
			sendudpmsg hub.stream,ip,port
		
		EndIf
		
		MemFree com
		MemFree pool
		RemoveUnreliable()
		
	End Method
	
	Method RemoveUnreliable()
		
		For Local m:Tmessage = EachIn msgs
			If m.ack = -1 
				msgs.remove( m )
			EndIf
		Next
			
	End Method
	
	Method CopyMessagesToStream( str:Tramstream)
		
		For Local m:tmessage = EachIn msgs
			If m.ackCycles=0
				WriteInt str,m.mtype
				
				If m.reliable
					If m.ack = 0 
						m.ack = RequestAck()
					End If
				Else
					m.ack = -1
				EndIf
				WriteInt str,m.ack
				Print "Wrote Ack:"+m.ack
				Local ms = StreamPos( m.bufs )
				SeekStream m.bufs,0
				WriteInt str,ms
				CopyBytes m.bufs,str,ms
				m.ackCycles = Default_Ack_Cycles
			Else
				m.ackCycles:-1
			EndIf
		Next
		
		
		
	End Method
		
	Method GetMessagesSize()
	
		Local bs = 0
		For Local m:TMessage = EachIn msgs
		
			If m.ackCycles = 0			
				bs :+ StreamPos( m.bufs )+12
			Else
				
			EndIf
			
		Next
		Return bs
	
	End Method
	
	Method update()
		If sendPulse.clicked()
	
			Send()
			
		EndIf	
	End Method
			
End Type

Type THub 'Base class for all transmitters and recievers.
	
	Field Stream:TUdpStream
	Field Port,Ip
	Field Cons:tlist 'Connections and count
	Field Incoming:TList 
	Field name:String
	Field Unrouted:Tlist
	Field MaxConnections 
	Field ConnectionUpdateInterval
	

			
	Method FindConnection:TConnection( ip,port )
		
		For Local c:TConnection = EachIn cons
			If c.ip = ip And c.port = port
				Return c
			End If
		Next
		'Print "New connection."
		Return Null
		
	End Method
	
	Method AddUnrouted( m:TMessage )
	
		unrouted.addlast( m )
	
	End Method
	
	
	Method New()
		
		incoming = CreateList()
		cons = CreateList()
		unrouted = CreateList()
		MaxConnections = 32
		ConnectionUpdateInterval = 100
		
		
	End Method
	Method SetMaxConnections( number )
	
		maxconnections = number
	
	End Method
	
	Method AddConnection:TConnection( ip,port,pulseInterval,hub:THub,name:String ="" )
			
		Local c:TConnection = New tconnection
		c.ip = ip
		c.port = port
		c.name = name
		c.hub = hub
		cons.addlast( c )
		c.sendPulse = TTimer.Create( pulseInterval )
		
		Return c
				
	End Method	
	
	Method GrabIncoming()
	
		If recvudpmsg( stream )
		
			'Print "Got Message:"
			Local fromIp = udpMsgIp(stream)
			Local fromPort = udpMsgPort(stream)
			Local con:TConnection = FindConnection( fromIp,fromPort )
			Local mode = ReadByte( stream )
			'Print "Mode:"+Mode
			Local rbuf:Byte Ptr = MemAlloc( 50000 )
			Local rs:TRamstream = CreateRamStream( rbuf,50000,True,True )
			Local netsiz
			
			Select mode
				
				Case net_compressed
					
					Local csiz,osiz
					csiz = ReadInt( stream )
					osiz = ReadInt( stream )
					'Print "Compressed:"+csiz
					'Print "OrigSize:"+osiz
					For Local j=0 Until csiz
						rbuf[j] = ReadByte( stream )
					Next
					Local nbuf:Byte Ptr = MemAlloc( osiz )
					
					uncompress nbuf,osiz,rbuf,csiz
					rbuf = nbuf
					rs = CreateRamStream(  rbuf,osiz,True,True )
					netsiz = osiz							
				Case net_raw
				
					Local osiz
					osiz = ReadInt( stream )
					'Print "OrigSize:"+osiz
					For Local j=0 Until osiz
						rbuf[j] = ReadByte( stream )
					Next
					netsiz = osiz
					
				Default
					Print "Network faliure."
					Print "Illegal Transmission mode "+mode+" specified."
					End		
			End Select
		'	DebugStop
			
			Local ts:TRamstream = CreateRamStream( rbuf,netsiz,True,False )
					
			While Not Eof( ts )
				Local m:TMessage = New tmessage
				Local mtype = ReadInt( ts )
				m.mtype = mtype
				Local ack:Int = ReadInt( ts )
				m.ack = ack
				'Print "Message Type:"+mtype
				'Print "Ack:"+ack
				Local mlen:Int = ReadInt( ts )
				'Print "Length:"+mlen
				m.fromip = fromip
				m.fromport = fromport		
				Local msgbuf:Byte Ptr = MemAlloc( mlen )
				For Local j=0 Until mlen
					msgbuf[j] = ReadByte( ts )
				Next
				m.buf = msgbuf
				m.bufs = CreateRamStream( msgbuf,mlen,True,False )
				If con <>Null
					Con.AddIncoming( m )
					'Print "Added Message to connection "+con.name
				
				Else
				
					AddUnrouted( m )
					'Print "Added unrouted Message."
				EndIf
				
								
			Wend
			 
			
			
		End If
	
	End Method
	
	Method ProcessServerUnrouted( in:TList )
		If in = Null End
		
		For Local m:TMessage = EachIn in
			'Print "Processing Type:"+m.mtype
			Select m.mtype
				Case Net_Connect
					'Print "Connection Attempt." 
					Local name:String = ReadLine( m.bufs )
					'Print "Name:"+name
					Local con:Tconnection = AddConnection( m.fromip,m.fromport,ConnectionUpdateInterval,Self )
					con.state = connection_pending
					'Print "Added Pending Connection."
					con.addIncoming( m )
					in.remove( m )
				Default
					'Print "Unroutable connection attempt."
					in.remove( m )
			End Select
		Next
			
	End Method
	
	Method ProcessServerConnection( con:TConnection,in:TList )
	
		For Local m:TMessage = EachIn in
			'Print "Got Routed Message."
			Select m.ack
				Case -1
					'Print "Unreliable message."
				Default
					Print "Reliable Message."
					Print "Ack is:"+m.ack
					con.SendackConfirm( m.ack ) 
			End Select
			
			Print "Ack Was :"+m.ack
						
			Select m.mtype
				Case Net_AckConfirm
					Local Ack:Int = ReadInt( m.bufs )
					Print "Ack Confirm "+Ack+" Recieved Server Side"
					con.RemoveAcks( ack )
					in.remove( m )
				Case net_connect
					in.remove( m )
					Print "Connection verified."
					Select con.state
						Case connection_pending
							
							If CountList( cons ) => MaxConnections
								con.state = Connection_Failed
								Local m:Tmessage = constructConnectionDeny( Fail_UserLimit )
								con.addMessage( m )
							Else
								con.state = Connection_Syncing
								Local M:TMessage = ConstructConnectionConfirm()
								con.addMessage( m )
							EndIf
						Case connection_syncing
							Print "Recieved unrequired call to connect."
					
					End Select
					
	
			End Select
		Next
	
	End Method
	
	
End Type

Const Server_Idle =1,Server_Active = 2


Type TServer Extends THub 'Server hub.

	Function Create:TServer( port = 45555 )
	
		Local out:TServer = New TServer
		out.stream = CreateUdpStream( port )
		If out.stream = Null
			RuntimeError "Could not create server."
		End If
		Return out
			
	End Function
	
	Method Update()
		ClearList( unrouted )
		
		GrabIncoming()
		ProcessServerUnrouted( unrouted )
		For Local c:TConnection = EachIn cons
			ProcessServerConnection( c,c.Recv )
			c.update()
			Select c.state
				Case Connection_Failed
			End Select
		Next 
			
	End Method
	
End Type


Type TClient Extends THub 'Client hub

	Field state 

	Function Create:TClient( name:String="Player", ip:String,port = 45555,updateInterval = 100 )
		
		Local out:Tclient = New tclient
		out.stream = createudpstream()
		If out.stream = Null 
			RuntimeError "Could not create client."
		End If
		out.server = out.addconnection( intip( ip ),port,updateInterval,out )
		out.name = name
		out.state = Connection_Pending
		out.server.addMessage( ConstructConnectionMessage(name) )
		Return out
			
	End Function	
	
	Method ProcessClientServerUpdate( con:Tconnection )
	
		For Local m:TMessage = EachIn con.recv
			Print "Recieved Client Side Message."
			
			Select m.ack
				Case -1
					Print "Unreliable message."
				Default
					Print "Reliable Message."
					Print "Ack was :"+m.Ack
					con.SendackConfirm( m.ack ) 
			End Select
			
			
			Select m.mtype
				Case Net_AckConfirm
					Local Ack:Int = ReadInt( m.bufs )
					Print "Ack Confirm "+Ack+" Recieved Client Side"
					con.RemoveAcks( ack )	
					con.recv.remove( m ) 				
				Case Net_ConnectConfirm
					Select state
					 	Case Connection_Pending
							Print "Connection Accepted."
							state = connection_syncing
							
						Case Connection_Active,Connection_Syncing
							Print "Unrequried confirm recieved."
					End Select
					con.recv.remove( m )			
				Case Net_ConnectDeny
					
					Local reason = ReadInt( m.bufs )
					Print "Connection attempt failed. Reason:"+FailConnect[ reason ]
					con.recv.remove( m )
					
			End Select
		Next
	
	End Method
	
	Method update()
	
		'Print "Updating Client."
		GrabIncoming()
		server.update()
		ProcessClientServerUpdate( server )
		'Print "End of client update."
		
		
		
	End Method
	

	Field server:TConnection

End Type

Function ConstructConnectionDeny:TMessage(reason)

	Local Msg:TMessage = TMessage.Create( Net_ConnectDeny )
	WriteInt msg.bufs,reason
	Return msg

End Function

Function ConstructConnectionConfirm:TMessage()

	Local Msg:TMessage = TMessage.Create( Net_ConnectConfirm )
	Return Msg
	

End Function

Function ConstructAckConfirm:TMessage( ack )

	Local Msg:TMessage = TMessage.Create( Net_AckConfirm,False )
	WriteInt msg.bufs,ack
	Print "Wrote Ack Confirm:"+Ack
	Return msg

End Function

Function ConstructConnectionMessage:TMessage(name:String)

	Local msg:TMessage = TMessage.Create( Net_Connect )
	WriteLine msg.bufs,name
	Return msg
	
End Function



Human like A.I.(Posted 2006-04-05)
We've done it.

We've crossed the threashold that seperates man from machine. In our hands lay the technology of gods. We've invented True A.I. Skynet is a reality.

A simple conversation with Hal can be described for the first time.

"Who are you?"

"Hal:I am a program."

"That is what you are, not who you are. I repeat, who are you."

"Hal:My name is hal. Who are you?"

"Antony"

"Hal:Please to meet you. Do you want to play a game?"

April fools suckers.


Ode to Ode.(Posted 2006-04-04)
Ode is proving to be a great physics lib. Our game, Full Metal Conflict : Phoniex is off to a much better start now. The controls are nearly like fmc was in all it's glory.


Oh and Warren, i'll reserve you a copy. you know you want it.
You can show it to your bosses, with the subject 'How to make a real game'. :)


Multiple Licenses/ Multiple Physic solutions.(Posted 2006-04-03)
Been thinking about the kind of licenses that will be offer.
There will be two I think. Sharewhere license and studio license.

Similar to how Swwift does it, one is for indie bedroom coders, the other are serious indiependent developers who make their living with bmax.

Prices will most likely be,

80Dollers for the sharewhere license. 1000Dollers for the studio license.

Aurora will also offer two physics solutions, one powered by newton, and one powered by ode. So you can go for ease of use(Newton) or flexibity and power.(ode)

Studio license will include the full C++ source and blitzmax source code. Shareware license will be a user's license, no source code will be included.

Both versions will recieve free updates for the life of Aurora.


The inside scoop.(Posted 2006-04-01)
I've just uploaded (Well still am so I've just posted this give it a minute if it's not showing up) build 6 of the engine.

Biggest new feature is full collision feedback in a very easy to use way,

some sample code,

local ColList:TList = TCollisionFeedback.GetList()

for Local Col:TCollision = eachin ColList
  print "Col X:"+Col.ContactX()+" Y:"+Col.ContactY()
  print "Speed:"+Col.ContactSpeed()
next



IT uses newtons collision callback feature and is mostly wrote C++ side. Get list just scopes them all up and puts them into blitz objects.

So just three functions to handle collisions. Speed is useful we can also get the 3d force vector of the collision so we can do proper sound where softer hits are quieter and throw up less particles.

Onto the particle engine, I explained most in the particle thread. To see the particles in action hold down the t key and smoke will be emitted from the player ship.
Be sure to grab the new media folder from the rar as it contains the particle defs/textures.


Physics(Posted 2006-04-01)
Coming along nicely. Added a bunch of tbody.class methods to handle things like torque, force and linear damping.

Here's a sample app, a bit messy as this is just test code that's been reilterated about a hundred times over the course of the engine's development. This demo uses the UI, Newton physics and the engine's new camera pick and linepicks.

Also demonstrates it's b3d style tformpoint/vector functions.

trict
Import "OgreMaxSYSTEM.bmx"
'-=-=-=-=-=-=-=-=-=-=-
'
'      Ogre Max
'        V1.0
'
'    Chaser Studios.(Well we need a better name than prime target :) )
'
'     Usage Demo
'
'-=-=-=-=-=-=-=-=-=-=-

Global lastdirx:Float,lastdiry:Float,lastdirz:Float,damp:Float=0.98
Global oldx:Float , oldy:Float , oldz:Float
Global newx:Float,newy:Float,newz:Float
Global camx#,camy#,camz#,targx#,targy#,targz#
	
Local Display:TDisplay = TDisplay.Create()
Display.OpenScreen()
Display.ShadowMode( Shadows_TextureMod )

Local Camera:TCamera = TCamera.Create()
Camera.Position( 0,0,5 )
Camera.LookAt( 0,-20,0 )

Local Entity:TEntity = TEntity.CreateMesh("hammer.mesh")
Local Sky:TEntity = TEntity.CreateMesh("sky.mesh")

Local InputDevice:TInput = TInput.Create()



'Local Chaser:TChasePivot = TChasePivot.Create( Camera,Entity,0,10,30,0.85 )
Entity.position(0,10,0)
'Local Ground:TEntity = TEntityPrefab.MakePlane(1500,1500)
Entity.CastShadows( True )

Local Light:TLight = Tlight.CreateOmni()
Light.Diffuse( 255,255,255 )
Light.Position( 0,30,0 )
Light.Specular( 255,0,0 )
TLight.SetAmbient( 128,128,128 )

'Ground.CastShadows( False )
'Ground.SetMaterial( "Examples/RustySteel" )

InitGui( camera.cam )
RootWindow.Hwnd = GuiRoot()

'local Ok:TButton = TButton.Create(20,20,200,200,"Ok",RootWindow )

Local Win:TWindow = TWindow.create(200,200,300,300,"Space Dust V1.0",RootWindow )
Local Quit:TButton = TButton.Create(5,5,DisplayWidth()/2,70,"Quit",Win )
'Print displayWidth()+" : "+displayHeight()

TPhysics.Init( Camera )
TPhysics.SetWorldSize( -1000,-1000,-1000,1000,1000,1000 )

Local Terrain:TEntity = TEntity.CreateMesh("terrain.mesh")
Local Col:TCollider = TCollider.CreateStatic( Terrain )
Local GBody:TBody = tbody.Create( col,"Ground" )
gbody.attachtopivot( terrain )
gbody.setInertia( Tinertia.CreateCube( 0,1,1,1 ) )


Local Entities:TList = CreateList()
Col = TCollider.CreateConvex( Entity )
Local PBody:TBody = TBody.Create( col,"Player")
pbody.attachtopivot( entity )
pbody.setinertia( TInertia.CreateCube( 1000,2,1,2 ) )
pbody.enableGravity()
pbody.position(0,-20,0 )
Local ships = 5
For Local j=1 To ships
	Local shp:TEntity = TEntity.CreateMesh( "hammer.mesh" )
	col = tcollider.createConvex( shp )
	Local tb:TBody = tbody.create( col,"Ship "+String(j) )
	tb.setinertia( tinertia.createCube( 1000,2,1,2 ) )
	tb.enablegravity()
	tb.attachtopivot( shp )
	tb.position( Rnd(-40,40),Rnd(0,10),Rnd(-40,40) )
	shp.castshadows( True )
	entities.addlast( tb )
	entities.addlast( shp )
Next


Local Cyn:TEntity = TEntity.CreateMesh("cylinder.mesh")

cyn.scale( 1.3,0.5,0.5 )
Col = TCollider.CreateCylinder( 0.5,1.3 )
Local CBody:TBody = TBody.Create( col,"Cylinder")
CBody.AttachToPivot( Cyn )
CBody.SetInertia( TInertia.CreateCylinder(10,0.5,1.3) )
CBody.Position(15,0,0)
CBody.EnableGravity()

Local Boxes = 5
For Local j=1 To boxes
	Local Bx:TEntity = TEntity.CreateMesh("box.mesh")
	bx.scale( 2,2,2 )
	Col = TCollider.CreateCube( 2,2,2 )
	Local Bb:TBody = TBody.Create( Col,"Box "+String(j) )
	Bb.attachToPivot( bx )
	BB.Position( Rnd(-40,40),Rnd(10,50),Rnd(-40,40) )
	bx.setmaterial( "Examples/RustySteel" )
	bb.setinertia( TInertia.CreateCube( 10,2,2,2 ) )
	entities.addlast( bx )
	bb.enableGravity()
	entities.addlast( bb ) ' just so the gc doesn't gobble them up.
Next
Local Chase:TPivot = TPivot.Create()

Local chaser:TChasePivot = TChasePivot.Create( Camera,Entity,0,5,-30,0.7 )
Local campiv:TPivot = Entity.CreateChild()
campiv.position(0,10,-30)
campiv.lookat( 0,0,0)

Local do = 0
Local iv:Float
Local ang:Float
Local sy# = 10
Local of#=0
Repeat

	If inputdevice.keydown(key_k)
		sy=15
	End If
	'entity.position(0,sy,0)
	sy = sy *0.90
	For Local j=1 To 3
	tphysics.update( 0.3 )
	Next
	
	ang:+1
	
	
	
	'Camera.Position( Sin(ang)*40,10,Cos(ang)*40 )
	'Camera.LookAt( 0,0,0 )
	If inputdevice.keydown( Key_u )
		iv:-0.01
		Print iv
	Else If inputdevice.keydown( key_i)
		iv:+0.01
		Print iv
	EndIf
	
	Entity.TFormPoint( 0,0,-2 )
	Local x1#,y1#,z1#
	x1 = entity.x()
	y1 = entity.y()
	z1 = entity.z()
	Entity.TFormPoint( 0,0,2 )
	Local x2#,y2#,z2#
	x2 = entity.tx
	y2 = entity.ty
	z2 = entity.tz
	
	Entity.TFormVector( 0,-2,0 )
	Local fx#,fy#,fz#
	fx = entity.tformedx()
	fy = entity.tformedy()
	fz = entity.tformedz()
	
	If TRayCast.Cast( x1,y1,z1,fx,fy,fz )
		'pbody.push( x1,y1-2,z1,-fx*iv,-fy*iv,-fz*iv ) 	
	End If
	
	Local yf# = InputDevice.mousexspeed();
	If yf>0.01
	Print "YF:"+Yf
	EndIf
	yf = -yf
	yf = yf *iv
	
	
	If inputDevice.KeyDown(Key_w)
		Entity.TFormPoint(0,-0.2,-2)
		x1 = entity.tx
		y1 = entity.ty
		z1 = entity.tz
		Entity.TFormVector(0,0.2,1)
		pbody.push( x1,y1,z1,entity.tx,entity.ty,entity.tz )
		'pbody.addpush( entity.tx,entity.ty,entity.tz )
		
	End If
	
	'This code turns the car by applying opposing forces at opposite ends on different sides. This results
	'in a pretty nice turn that can be tweaked. it's exactly how I did when using my own physics lib for fmc.
	'pbody.torqueadd(yf,yf,yf)
	'yf=0
	
	of:-(yf*0.3)
	of:*0.72
	If yf>0.01
		'Local x1#,y1#,z1#
		'Local x2#,y2#,x2#
		Entity.TFormPoint(-1,0,1)
		x1 = entity.tx
		y1 = entity.ty
		z1 = entity.tz
		Entity.TFormVector(yf,0,0)
		PBody.Push( x1,y1,z1,entity.tx,entity.ty,entity.tz )
		
		Entity.tformPoint(1,0,-1)
		x2 = entity.tx
		y2 = entity.ty
		z2 = entity.tz
		Entity.tformVector(-Abs(yf),0,0)
		pbody.push( x2,y2,z2,entity.tx,entity.ty,entity.tz )
		
	Else If yf<-0.01
	
		Entity.TFormPoint(1,0,1)
		x1 = entity.tx
		y1 = entity.ty
		z1 = entity.tz
		Entity.TFormVector( yf,0,0 )
		PBody.Push( x1,y1,z1,entity.tx,entity.ty,entity.tz )
		
		Entity.tformPoint(-1,0,-1)
		x2 = entity.tx
		y2 = entity.ty
		z2 = entity.tz
		Entity.TFormVector( Abs(yf),0,0 )
		PBody.Push( x2,y2,z2,Entity.tx,entity.ty,entity.tz )
	
	EndIf
	yf=of
	If yf>0.01
		'Local x1#,y1#,z1#
		'Local x2#,y2#,x2#
		Entity.TFormPoint(-1,0,1)
		x1 = entity.tx
		y1 = entity.ty
		z1 = entity.tz
		Entity.TFormVector(yf,0,0)
		PBody.Push( x1,y1,z1,entity.tx,entity.ty,entity.tz )
		
		Entity.tformPoint(1,0,-1)
		x2 = entity.tx
		y2 = entity.ty
		z2 = entity.tz
		Entity.tformVector(-Abs(yf),0,0)
		pbody.push( x2,y2,z2,entity.tx,entity.ty,entity.tz )
		
	Else If yf<-0.01
	
		Entity.TFormPoint(1,0,1)
		x1 = entity.tx
		y1 = entity.ty
		z1 = entity.tz
		Entity.TFormVector( yf,0,0 )
		PBody.Push( x1,y1,z1,entity.tx,entity.ty,entity.tz )
		
		Entity.tformPoint(-1,0,-1)
		x2 = entity.tx
		y2 = entity.ty
		z2 = entity.tz
		Entity.TFormVector( Abs(yf),0,0 )
		PBody.Push( x2,y2,z2,Entity.tx,entity.ty,entity.tz )
	
	EndIf
	
	chase.position( entity.x(),entity.y(),entity.z() )
	chase.rotate( 0,entity.getyaw(),0 )
	'Print "Pi:"+entity.getpitch()+" Yi:"+entity.getyaw()+" Rl:"+entity.getRoll()
	entity.tformpoint( 0,10,-20)
	'Print "Tx:"+Entity.tx+" Ty:"+entity.ty+" Tz:"+entity.tz
	'camera.position( entity.tx,entity.ty,entity.tz )
	'camera.position(camera.x() + (campiv.x() - camera.x())*.2 , campiv.y()+2 , camera.z() + (campiv.z() - camera.z())*.2 )
	If do = 0
	do = 1
	camera.lookat(entity.x() , entity.y() , entity.z() )
	EndIf
	chaser.update()
	
	
	
	'camera.pitch(10)
	
	


	
	
	If Camera.Pick( TGui.CursorX(),TGui.CursorY() )
		Local t:TBody = Camera.PickBody()
		Local px#,py#,pz#
		px = camera.pickx()
		py = camera.picky()
		pz = camera.pickz()
		If inputdevice.keydown(Key_c)
		t.Push( px,py,pz,Rnd(-12,12),Rnd(-12,12),Rnd(-12,12) )
		EndIf		
		
	EndIf
	

	Render3D()
	CaptureInput()
	tgui.updateEvents()
	Repeat
		Local e:TguiEvent =Tgui.eventnext()
		If e=Null
			Exit
		Else
			Select e.id
				Case event_buttonclicked
					Select e.owner
						Case quit
							End
					End Select
			End Select
		EndIf
	Forever
	tgui.freeevents()
	tgui.updateevents()
	If InputDevice.KeyDown(key_escape) Then End

Forever




Let's get physical(Posted 2006-03-31)
Just added the foundations of the physic component.

Some sample code,

TPhysics.Init( Camera )
Local Box:TEntity = TEntity.CreateMesh("box.mesh")
box.scale( 50,1,50 )
Local Col:TCollider = TCollider.CreateCube( 50,1,50 )
Local BoxBody:TBody = TBody.Create( Col )

BoxBody.AttachToPivot( Box )
BoxBody.Position( 0,-20,0 )
box.setmaterial( "Examples/RustySteel" )

Local Cyn:TEntity = TEntity.CreateMesh("cylinder.mesh")
cyn.scale( 1.3,0.5,0.5 )
Col = TCollider.CreateCylinder( 0.5,1.3 )
Local CBody:TBody = TBody.Create( col )
CBody.AttachToPivot( Cyn )
CBody.SetInertia( TInertia.CreateCylinder(10,0.5,1.3) )
CBody.EnableGravity()



Also yesterday I added CEGUI support via a maxgui like (But oop instead of procedural) gui lib. works in fullscreen mode too so it's perfect for games.

Tomorrow, i'll be adding more physic types and hopefully ragdoll. RAGDOLL.


Storyteller(Posted 2006-03-19)
47236
					JET BLACK

FADE IN.
EXT.STARS.NIGHT
Panning across a sea of stars. The eclipsed sun comes into view.

					NARRATOR:
				Earth. 2020.

Camera inverts and appears beside the sun looking back on Earth.
	
					NARRATOR:
				Ravaged by war. Left for dead by mankind.

Pan inwards. Towards New York. It's skyline a wreak of war.
Smoke belowing from every crack. A shadow of it's former self.
	
					NARRATOR:
				Once beautiful  cities lay torn in the dust.
				Everywhere the eye can see, rust.
				The smell of charred corpse fr agent the air.

Pan in  on the remains of The Projectile NightRoom.

Wait a beat.

CUT TO
INT.PROJECT NIGHTROOM.SAME DAY

Barstools and tools lay across the broken floors. The glass shutters
are smeared with dirt and rust. Like everyplace in down town New York, smoke fills
the air.

					NARRATOR
				There are places even the devil's afraid 
				to go.
				
A Tall dark figure walks into shot. Jet Black. A scanvanger. A gunslinger.
	
					JET BLACK	
				They're late.

A Woman walks in behind him. Long brunette hair, and no make up to speak of.
Amanda Rain. Jet Black's long time partner.
	
					AMANDA
				Them's the sort that are always late.
	
					JET BLACK
				One of these days they'll be late to their
				own funeral.
	
					AMANDA	
				They're already dead. Just ain't been told is all.

					RYAN(O.S)
				Talkin' about anyone I know?

Ryan McBrian walks into the shot. Middle aged, and gruff looking.
The lowest form of scum on earth.

					JET BLACK
				You're late.
	
					RYAN
				That's subjective. I say, you're early.
		
					AMANDA
				Are we here to quibble over semantics, or we here	
				to break the law.

					RYAN
				Well that would be the latter, my dear.

					JET BLACK
				Such a fine mouth for such a pretty face.
				Where's the fireworks.
	
RYAN smiles and point from where he come.

					RYAN
				Sandy's bringing it up the rear. You know him,
				you could put a fusion jet up his ass and he still
				wouldn't move for shit.

					AMANDA
				No piece, you become a pacifist all of a sudden?
	
					RYAN
				No sense, I trust you guys.
	
					JET BLACK
				I'm touched. 

					RYAN
				Dandy.

Sandy Doir saddles into shot.
	
					SANDY
				I said wait up, always gotta leave me trailin'
	
					RYAN
				Get your slow ass  up on in here.
				We got some bartering to be doing.
		
					JET BLACK
				Ain't gonna be much bartering.
				The prices are set by the times.
				We ain't paying no more, no less.
	
RYAN SMILES

					RYAN	
				The price is set by whoever's got the biggest	
				gun.
	
					JET BLACK
				Unless you're talking about your cod piece, I don't see 
				no gun. I just see a low life making little to no sense.

SANDY REACHES BEHIND RYAN'S BACK
Pulls a piece. A High Velocity Mark 5 Handgun.
Points sqaurely at Jet.
	
					JET BLACK
				That better be one of those magic guns that
				take out two people in one shot or you're not
				walking away from this.

					RYAN
				I don't need to kill yer. I just need to scare you into handing
				over that money. And believe me, I'm good at scaring people.
			
					AMANDA
				Just one look at you face is enough to make a woman
				believe that. Still ain't getting no money of mine.
					
					JET BLACK
				Yours?

					AMANDA
				You shoot, I spend. It's our thing.

					JET BLACK
				Oh it's our thing.

					AMANDA
				As much as anything Captain.
	
RYAN AND SANDY look at each other.

					RYAN
				Unless you're a fixing to feel
				the sharp end of one of these here bullets
				I suggest you..stem the talking, start the giving.
				As in, give me the money, now!

					JET BLACK
				You know in good conscious I can't be doing that.

					RYAN	
				We seem to have a situational awareness problem, 
				or general lack there of.
				Here. I have a gun.  It's self, it has bullets. 
				Those bullets contain gun powder.
				Combined they form a weapon. A weapon that can be used to inflict
				great pain in any sorry son of a bitch stupid' enough to get in the way 
				of it.
				
					JET BLACK
				Well that's all well and good but I have..I have..
Looks towards Amanda
					JET BLACK	
				What do I have?

					AMANDA
				A  winning smile.

					JET BLACK
				Think bigger.
			
					AMANDA
				A TCK-47 Personal Shield, Manafactured 
				in taiwan, worn in America.
			
					JET BLACK
				Why now I think you're right.

Ryan face drops. In disbelief at first, then turns to anger.

					RYAN
				Bullshit. I shoot you and you're a piss can.
			
					JET BLACK
				Shoot me and the ricochet will rip your balls off.
	
					RYAN
				OK Then I'll shoot her!.

					JET BLACK
				Unlucky, she's wearing one too.

					RYAN
				....So 40 a piece then?

JET SMILES.

CUT TO
INT.JET'S HIDEOUT.SAME DAY
	
Rock, a 30 year gunslinger is sat holding a big looking gun. Simian, the crew's driver is sat beside him looking directly at him.

					SIMIAN
				Normal guns, just not enough for you?
	
					ROCK
				What's wrong with a big gun?

					SIMIAN
				Oh no, nothing. You compensating?
					
					ROCK
				Compensating for a lack of understanding between
				 fellow out laws is all.
				
					SIMIAN
				Oh yeah, what's that?
		
					ROCK
				They like shooting me, and I like shooting them.

Penny walks in holding a live news feed tablet. She throws it on the table.

					PENNY	
				They did it again.

					ROCK:
				Whose they, and what they do?
	
					PENNY
				Those bastards did it again!

					SIMIAN
				Penny, slow down. What did they do?

					PENNY
				They shanked us. They stole the sun from our hearts.
				They rode in at sunset and claimed our land as theirs.

She pounds her chest.

					ROCK
				You're not making a lick of sense.	
	
					PENNY
				Read my lips you Neanderthal They stole our land!
				
					ROCK
				We've got land? Did you know that?

Rock nods in Simian's direction.
					SIMIAN	
				I wouldn't call it land, as much as I would a swap 
				with a teeny tiny house stuck in the middle.
		
					PENNY
				That don't matter! Our land is ours.
				Ain't no scavenger taking what's rightly mine.

					ROCK
				We men. Go save. Big Land. 
				Women. No cry. 
					
Simian smiles. Penny catches his reaction in the corner of her eye and turns to him.

					PENNY
				Captain won't think it's funny
				You gonna laugh in his face too.

					ROCK
				Hell I just watch we had a working camera to take a picture of it.

					PENNY		
				Why is any man that carries a gun automatically a pig?

She pivots 180 degrees and walks out.

					ROCK
				I ain't ever getting married.

					SIMIAN
				I don't expect you are.


RING
The on board communication system rings. 
Rock And Simian stand to attention. Simian runs over and flicks a switch.

					SIMIAN
				You've reached poverty central,
				 how may I direct your call?
		
					JET BLACK (O.S)
				Quit your playing and come pick us up.
					
					SIMIAN
				Everything go as planned?

					JET BLACK(O.S)
				Pretty much smooth as clockwork. 
					
					AMANDA (O.S) 
				Until...
		
					JET BLACK
				Until they started shooting at us.
				We're coming in hot. Assistance would greatly be appreciated
				
CUT TO
EXT.HIDE OUT DRIVEWAY.SAME DAY
	
We're looking at the main driveway car door.

Wait a beat.

The door flings open, and a Humvee flies out in a great hull of smoke.

					ROCK
				YEEE HAW!
			
CUT TO
Int.Inside Humvee. 

Simian is looking at rock.

					SIMIAN
				Please don't do that. Ever. 

CUT TO
Ext.Outside Projectile Night room. Floor Level.
	
Jet Black And Amanda are taking cover behind the sharp corner of the room.
Ryan, Sandy, Shaky and Tom are at the other end of the room, sporadically firing shots.

					JET BLACK
				Yep. We're pinned down.
		
					AMANDA
				Why do we attract so much gun fire.
				Is it because we're so damn pretty?

					JET BLACK
				Must be. 

Jet black comes out and fires a shot. It hits Tom in the leg. He falls crying like a baby.

					JET BLACK
				Could be we're just unlikable folk.

					AMANDA		
				Are you saying I'm not charming?

Amanda comes out and fires a shot. Hits Shaky's hat.

					SHAKY
				She shot me in the hat!

					JET BLACK
				Not at all.

					AMANDA
				Good. 'Cos I'm all about the people around me.

They both come out and fire shots. 

					RYAN
				This is pointless Jet. We outnumber you,
				we out smart you. 
		
					JET BLACK
				Took you long enough to discover
				the truth about the shields.

					RYAN
				Thought it would be fun to let you	
				think you had the advantage for a change.

BEEP BEEP
The Humvee's tuned horn bellows outside.

					

					JET BLACK
				Looks like the cavalierly has arrived.

					RYAN
				Your boys come to save you Jet!?
	
					JET BLACK
				No, they came to save you.

					RYAN
				I don't follow.
		
					JET BLACK
				Now I don't have to kill you.

CRASH
The wall nearest to Jet and Amanda crashes through as the Humvee ploughs through it

					ROCK
				We miss the party?

					JET
				Just getting started.
			
Rock pulls a machine gun from beneath his seat. He points it in the general direction of Ryan and his men and opens fire.

					SIMIAN
				Get in!

Jet and Amanda run to the Humvee, firing as they do.

Ryan, Tom, Sandy and Shake dive for cover. Bullets narrowly missing them.
			
Simian puts the Humvee into reverse. He struggles over the debris from the wall and eventually
makes it out.
We follow him up and under the huge hole in the wall. 

Snap back to a irate shot of Ryan and his men.
			
					RYAN
				Damn ingrates!

Back to the Humvee, floating above it as it hurtles down the derelict highway.

CUT TO
Int.Inside Humvee.	
						ROCK
					Can't you go one mission with getting
					us into a firefight.

						JET (O.S)
					Gotta keep it interesting.

						ROCK
					Drive straight.

SIMIAN Glances over towards rock.

						SIMIAN
					I'll stop the car right now. Right here.
						
						AMANDA
					Captain, we done good this time.
					
						JET BLACK
					25 pounds of mother nature's finest syntax explosive.

						ROCK
					Shit yeah. Less shooting and more exploding I say.

						SIMIAN
					She was right, you are a Neanderthal.

CUT.TO.
Int.Jet's Hideout.Same Day.

Lucy Silver, A twenty five year old computer hacker, is sat in a load of dirty clothes.
She's worked for the captain and crew most of her life.  
	
						SILVER
					I ain't scrubbing their drawers. Not again.
		
Andrea Point, a twenty seven year old freelance gunslinger walks into shot.
She smiles.

						POINT
					Just tell 'em you were far too busy
					hacking into the feds central database.
				
						SILVER
					That's the excuse I used last time.

						POINT
					Renembering it would mean they understood it.

						SILVER
					That's a point.

Silver lifts her arm up, waiting for Andrea to pick her up. She obliges.
	
						SILVER
					Know what crazy life threatening mission they're on 
					this time?

						POINT
					Captain's looking for some syntex for
					the job. Apparently found some low life
					with enough to blow up parliament.
		
						SILVER
					I love me a firework show.
 
She smiles and walks out of the room.
	
RING
The hide out's intercom rings. Andrea hesitates then walks over and flicks a switch.
The door slides open automatically.
The Captain, Amanda, Rock and Simian walk in huffing and puffing.
Jet throws a rucksack into the hands of Point.

						JET BLACK
					Signal Spider, we've got the syntex.

						POINT
					The usual?
		
						JET BLACK
					People shot at us. We shot back. Be impolite not to.

Point smiles and walks out of the room. Rock sits down and Simian gives a knowing look.

						JET BLACK
					She didn't scrub 'em. 

CUT TO 
Int.Spider's Bar.Day

Spider, a fifty year ex-war vet, now turned to organized crime. As organized as organized can be
in this world. He served in the same platoon as the Captain.
Charlie and Bronco, two of his henchmen are stood before him.

						SPIDER
					Let me get this straight.
		
						CHARLIE
					OK.
			
						SPIDER
					You had the goods. MY GOODS. You had the money,
					likewise, MY MONEY. And you just left them idling,
					paying no attention to the fact you can't spit and not hit a thief
					in this town, all so you could have yourself a time with a whore!?
	
						CHARLIE
					She was real pretty.

						SPIDER
					 So pretty she'd last a life time? 
					Because by the time I'm through with you,
					you won't even be able to stand up straight.
		
						BRONCO
					I told him not to.

						CHARLIE
					You did not!
	
						SPIDER
					Silence! Both of you, get out of here before I 	
					beat you to death with my wooden leg!

RING
Spider's communication badge rings. He flicks it.

						SPIDER
					WHAT!?
	
						POINT (O.S)
					Spider? It's Jet. I mean, I'm speaking for Jet.
						
						SPIDER
					Oh hello lady, just been pondering the meaning
					of existence.. What can I do for you?

						POINT
					The stuff. We got it. We're good to go.

						SPIDER	
					Well that's the first good piece of news	
					I've got today. Tell Jet to get his sorry ass over here.
					We have to celebrate this monumental occasion.

CUT TO
Ext.Spider's bar.Night

Jet is stood holding the pack of syntex. Rock is stood beside him looking disinterested.
	
						JET
					You think he'll be happy to see us?

						ROCK	
					Couple of pretty looking fellas like ourselfs?		
					What's not to be happy about?

DOOR OPENS
Spider stands there with a cocksure grin.

						JET
					Spider!

						SPIDER	
					Jet!

Spider catches Jet with a right hook, sends him to the floor.

Rock looks down at jet and grins his big old white teeth.

CUT TO
Int.Spider's bar.Night

Inside a pool of water, looking up. The soft diffuse lighting bouncing off the gentle waves.

Wait a beat.

Jet's head comes plunging down into the water. Air bubbles escaping from his mouth and nose, cascading around him.

						JET (MUFFLED BY THE WATER)
					You're being unreasonable.
	
Spider pulls his head out and we follow Jet's face up out of the water.

						SPIDER
					You think you can hide from me?

						JET
					I came knocking at your door!
			
Pushes his head back down into the water, we follow him down.
	
									
						JET
					You're being very unreasonable!

Pulls head  back out of the water.

						JET
					Let me expl..

Cutting him off he attempts to push him back under. Jet resists
		
						JET
					Don't you go pushing me back, let me explain.

Spider stops trying to push him under and grabs him by the coller

						SPIDER
					Go on then, explain.

						JET
					What did you do with Rock?

						SPIDER
					He was tired so he took a nap.

Camera pans left as spider gestures to an unconscious Rock. 
						
						JET
					He dead?

						SPIDER
                                                    



Bunch of vultras(Posted 2005-08-14)
Vultra, as it is now known (And not vultra's flying magical garden of singing gnomes. That rumor...Damn that rumor..)

Things are going well. The engine is in a stable bug free state (In no small part due to VC2005's Unbeliably excellent ide. The thing actually parses it as you write the code, instanstly flagging and highlighting errors as you go!
It's like having a super computer making sure you don't (bleep) up.)

The engine docs are also being wrote side by side, thanks to vc's automatic doccer. like bmax's, but this one produces true XML documentation that can be converted into any given format. It's again very tasty..automatically creating a template doc for your function merely by typing "///" in the ide. Formats it and everything.
So no vivid 1 rubbish docs syndrome this time..fortunately.

And that's about it..I could probably ramble on about what it will have..but I won't.



Sprite as a spark.(Posted 2005-08-06)
The framework is now in place. The engine it's self is a C# class library.(.dll)
so actually integrating it is as simple as "Add reference VividDX(Name changed) and throwing in "using VividDX;" at the top of your game/whatever.

Currently have sprites loading and displaying and a base scene graph set up.

Anyone know anything about wrapping/calling C# .dlls in bmax? IF so...help a man out :)



Direct X Maa!(Posted 2005-08-06)
Started work on Vivid NG.(Developing it along concept, but not for concept. Still using ogre.)
I'm coding it entirely in Visual C#, but I'll be releasing it for C# and Bmax.

The bmax version will utilise a set of wrapper classes.

Not much else to say at this point... Most of my time is being spent reading Managed DirectX9 KickStart. (By the author of Managed DirectX! So it's going smoothly.)

Expect screens, demos, jesus-esque hype and and new levels of arrogance soon!



Aye Eye.(Posted 2005-08-01)
It's...it's...alive!

Well almost.

The neural net is now complete (for now) with backprop learning and datasets automated supervison learning. (Target based)

basically I create a supervisor, then suppy it with a set of sample inputs with the desired outputs. it will then cycle through this sample datsets and train the network to produce the desire output for these cases.
Then in real world use, the final network once fully trained(It returns an average error last cycle to determine how close it was to it's goal. 0 = perfect match. 0.015454 is a realistic goal) it can produce output derived from the input.

For example, here's how I produced a vector finder neural network. that given two 1dimensional coords, will return the vector between the two.

i.e, 0,5 would be a vector of 1,, -5,-10 would be a vector of -1.

cout << "A test of all tests"<<endl;
	NeuralNet *vpu = new NeuralNet;
	NInput *ax = vpu->addInput();
	NInput *ay = vpu->addInput();
	
	NOutput *xvec = vpu->addOutput();

	vpu->addHiddenLayer(8);
	vpu->connectNetwork();
		
	int ind=0;

	Supervisor *train = new Supervisor;
	DataSet * xdat;
	DataSet * ydat;
	DataSet * odat;
	xdat=train->addInput( ax );
	ydat=train->addInput( ay );
	odat=train->addOutput( xvec );

	
	xdat->addInputRecord( 0 );
	ydat->addInputRecord( 5 );
	odat->addTargetRecord( 1 );

	xdat->addInputRecord( 0 );
	ydat->addInputRecord( -5 );
	odat->addTargetRecord( 0 );

	xdat->addInputRecord( 0 );
	ydat->addInputRecord( 0 );
	odat->addTargetRecord( 0.5 );
	
	xdat->addInputRecord( -5 );
	ydat->addInputRecord( 0 );
	odat->addTargetRecord( 1 );

	xdat->addInputRecord( -5 );
	ydat->addInputRecord( -10 );
	odat->addTargetRecord( 0 );

	xdat->addInputRecord( -5 );
	ydat->addInputRecord( -5 );
	odat->addTargetRecord( 0.5 );

	xdat->addInputRecord( 5 );
	ydat->addInputRecord( 0 );
	odat->addTargetRecord( 0 );

	xdat->addInputRecord( 5 );
	ydat->addInputRecord( 10 );
	odat->addTargetRecord( 1 );

	xdat->addInputRecord( 5 );
	ydat->addInputRecord( 5 );
	odat->addTargetRecord( 0.5 );

	


	train->setNetwork( vpu );
	int tin=0;
	double err;
	while( ind<1500){
		err=train->train( true );

		ind++;
		tin++;
		if(tin>140){
		//	cout<<"XVec:"<<xvec->value()<<endl;
		//	cout<<"Should be:"<<xvec->getTarget()<<endl;
			//cout<<"Error:"<<err<<endl;
		};

	};



	cout<<"Done!"<<endl;

	ax->value( 0 );
	ay->value( -5 );
	xvec->target(0);
	err=vpu->cycle();
	cout<<"XOut:"<<(-1)+xvec->value()*2<<endl;
	cout<<"New Error:"<<err<<endl;
	while(true){
		
	};


	
	return 0;
}



And here's the neural lib(Open source.). I'd be happy to see this wrapped in blitzmax. Will do it myself once bmax3d is out.

#ifndef NEURALNET_H
#define NEURALNET_H

using namespace std;
double rndn( double from,double fin)
{
	srand( (int)GetTickCount() );
    double rndr =(double) rand()/RAND_MAX;
    return from+(fin-from)*rndr;
};

double rndn()
{
	srand( (int)GetTickCount() );
    return (double)rand()/RAND_MAX;
};
double sigmoid(double netinput, double response=1)
{
    return ( 1.0 / ( 1.0 + exp(-netinput / response)));
}


class Neuron
{
public:


    ~Neuron()
    {}

	Neuron(){
		ic=0;
		oc=0;
		output=0;
		echoOut=false;
		init();
		outmode=0;
	};
	void modWeight( int connection,double val){
		w[connection]+=val;
	};
    void connectNeuron( Neuron *to){
        out.push_back( to );
        oc++;
        to->addInput( (Neuron *)this);
      
//		cout<<"Connected Neuron"<<endl;
//		cout<<"Oc:"+oc<<endl;
//		cout<<"ic:"+to->ic;
	};
    
    void init(){
        oc=0;
        ic=0;
     
      
        for(int j=0;j<255;j++)
        {
            w[j]=-1.0+rndn()*2.0;
        };
        
        output =0;
    };
    
    
    
	double getWeight( int connection =0){
		return w[connection];
	};

	void sumInputs()
    {
        double weight =0;
			
        for(int i=0;i<ic+1;i++)
        {
			if(i<ic){
		    weight += w[i] * in[i]->getOutput() ;
			}else{
			weight += w[i] * 1;
			};
		};

	
//..        weight+= w[ic]*-1;
       // if(output>w[ic]*-1){
		if(outmode=1){
			 output =sigmoid(weight,1);
		}else{
           output=weight;
		};        
    };
    
    void fire(){
        
    };

    void setOutput( double noutput)
    {
        output=noutput;
    };

	void outputMode(int mode){
		outmode=mode;
	};
    double getOutput()
    {
		if(echoOut==true){
		cout<<"Echo Neuron called."<<endl;
		cout<<"Output is:"<<output<<endl;
		};

		return output;

    };
	void incInput(){
		ic++;
	};
	void addInput( Neuron *inN){
		in.push_back( inN );
		ic++;
		cout <<"Added input>"<<ic<<endl;
	};
	void echoOutput( bool enable=true){
		echoOut=enable;
	};
	double getErr(){
		return err;
	};
	void setErr( double val){
		err=val;
	};
	double getDelta(){
		return delta;
	};
	void setDelta(double ndelta){
		delta = ndelta;
	};

private:
    vector<Neuron *>in;
    vector<Neuron *>out;
    double w[255];
    double output;
    int ic,oc;
	bool echoOut;
	double err;
	double delta;
	int outmode;
};

// TODO (Antony#1#): Try increasing network by adding random neurons in areas of high activitity.\

class NInput
{
public:
	void addWatch(){
		dat->echoOutput(true);
	};
	void value(double input)
    {
        dat->setOutput( input );
    }
	double getValue(){
		return dat->getOutput();
	};
    Neuron *getNeuron(){
        return dat;
    };
    void setNeuron(Neuron *an){
        dat = an;
    };
	
	protected:
    Neuron *dat;

};

class NOutput
{
public:
	NOutput(){
		desired=0;
	};
	~NOutput(){
	};
    double value()
    {
        return dat->getOutput();
    }
    Neuron *getNeuron(){
        return dat;
    };
    void setNeuron(Neuron *an){
        dat = an;
    };
	void target( double val){
		desired = val;
	};
	double getTarget(){
		return desired;
	};

    protected:
    Neuron *dat;
    const char *name;
	double desired;
};



class NeuralNet
{
public:
   NeuralNet(){
	   ic=oc=hc=0;
	   doBackprop=true;
   };
   ~NeuralNet(){
   };

    void addHiddenLayer( int neurons=8)
    {
		hc=0;
        for(int j=0;j<neurons;j++)
        {
            
            hidden.push_back( new Neuron);
            hidden[j]->outputMode( 1 );
            hc++;
        };
        //        hc=neurons;
    };

    NInput* addInput()
    {
        NInput *out = new NInput;
        out->setNeuron( new Neuron);
        out->getNeuron()->init();
		out->getNeuron()->outputMode( 1);
		inputs.push_back( out );
        ic++;
		return out;
    };

    NOutput *addOutput()
    {
        NOutput *out = new NOutput;
        out->setNeuron( new Neuron);
        out->getNeuron()->init();
        outputs.push_back( out );
        oc++;
        
        return out;

    };

    void connectNetwork()
    {
        for(int j=0;j<ic;j++)
        {
            for(int k=0;k<hc;k++)
            {
               Neuron *neuron;
                Neuron *hneuron = hidden[k];
                NInput *tempi = inputs[j];
               neuron = tempi->getNeuron();
                neuron->connectNeuron( hneuron );
            };
        };
		
        for(int j=0;j<hc;j++)
        {
            for(int k=0;k<oc;k++)
            {
                Neuron *neuron = hidden[j];
                Neuron *oneuron;
                NOutput *tempo=outputs[k];
                oneuron = tempo->getNeuron();
                neuron->connectNeuron( oneuron );
            };
        };
    };
    
    double cycle(){
        //Feed network.
		for(int j=0;j<hc;j++){
            hidden[j]->sumInputs();
		
		};
        for(int j=0;j<oc;j++){
            outputs[j]->getNeuron()->sumInputs();
        };
		double avg_err=0;
		//Calculate output neurons error.
		for(int j=0;j<oc;j++){
			double error;
		    double target=outputs[j]->getTarget();
			double actual=outputs[j]->value();
	//		error=(target - actual) * actual * (1 - actual);
	//	error = actual * ( 1-actual)*(target-actual);
			error = target-actual ;
			avg_err+=sqrt( error*error );
			outputs[j]->getNeuron()->setDelta( error );
		};
		if(doBackprop==false) return 0;
		double yout[255];
		double hout[255];
		double hout2[255];
		for(int i=0;i<oc;i++){
			yout[i] = 0;
			for (int j=0;j<hc+1;j++)
			{
				if(j<hc){
				yout[i] += outputs[i]->getNeuron()->getWeight( j )*hidden[j]->getOutput();		
				}else{
				yout[i] += outputs[i]->getNeuron()->getWeight( j )*1 ;
				};
			}

			// linear derivative = 1
			yout[i] = 1*outputs[i]->getNeuron()->getDelta();
		};

// calculate the hout derivatives
		for (int i=0;i<hc;i++)
		{
			hout[i]=0;
			for (int j=0;j<ic+1;j++)
			{
				if(j<ic){
				hout[i] += hidden[i]->getWeight(j)*inputs[j]->getNeuron()->getOutput();
				}else{
				hout[i] += hidden[i]->getWeight(j)*1;
				};
			}
				// derivative of 1/(1+exp(-x))
			hout[i] = exp( -hout[i] ) / ((1+exp( -hout[i])) *(1+ exp(-hout[i])));
		}

		for (int i=0;i<hc;i++)
		{
			hout2[i]=0;
			for (int j=0;j<oc;j++)
			{
				hout2[i] += yout[j]*outputs[j]->getNeuron()->getWeight(i);
			}
			hout[i] = hout[i]*hout2[i];
		}
		double learning_rate = 0.1;
		for (int i=0;i<oc;i++)
		{
			for (int j=0;j<hc+1;j++)
			{
				if(j<hc){		
					outputs[i]->getNeuron()->modWeight( j,learning_rate*yout[i]*hidden[j]->getOutput() );
				}else{
					outputs[i]->getNeuron()->modWeight( j,learning_rate*yout[i]*1 );
				};
			}
		};

// input_weight changes
		for (int i=0;i<hc;i++)
		{
			for (int j=0;j<ic+1;j++)
			{
				if(j<ic){
					hidden[i]->modWeight(j,learning_rate*hout[i]*inputs[j]->getNeuron()->getOutput() );
				}else{
					hidden[i]->modWeight(j,learning_rate*hout[i]*1);
				};
			}
		}

		return avg_err;
	//Calculate hidden neurons error.
    };
	void learn( bool enable = true ){
		doBackprop = enable;
	};
protected:
	bool doBackprop;
    vector<NInput *> inputs;
    int ic;
    vector<Neuron *> hidden;
    int hc;
    vector<NOutput*> outputs;
    int oc;
private:

};
class DataSet{
public:
	DataSet(){
		pCount=0;
		dtype=-1;
		out=NULL;
	};

	~DataSet(){
	};
	void setInput( NInput *inp){
		in=inp;
		dtype=1;
	};
	void setOutput( NOutput *outp){
		out = outp;
		dtype=2;
	};

	void addInputRecord( double input){
		inValue.push_back( input );
		pCount++;
	};
	void addTargetRecord( double target ){
		targetValue.push_back( target );
		pCount++;
	};
	double getInput( int index=0){
		return inValue[index];
	};
	double getTarget( int index=0){
		return targetValue[index];
	};
	void activeSet( int index=0){
		switch(dtype){
			case 1:
				in->value( inValue[ index ] );						
				break;
			case 2:
				if(out==NULL){
				cout<<"Out does not exist. We got a prob."<<endl;
					exit(-5);
				};
				out->target( targetValue[ index ] );
				break;
			default:
				exit(-2);
				break;
		};
	};
	int dataCount(){
		if(dtype==1){
			return (int)inValue.size();
		};
		return (int)targetValue.size();
	};

private:
	int pCount;
	vector<double> inValue;
	vector<double> targetValue;
	NInput *in;
	NOutput *out;
	short dtype;
};


class Supervisor{
public:
	Supervisor(){
		datSet=0;
		datCount=-99;
	};
	~Supervisor(){
	};
	DataSet* addInput( NInput *input){
		inputs.push_back( input );
		DataSet* out = new DataSet;
		out->setInput( input );
		inset.push_back( out );
		return out;
	};

	DataSet* addOutput( NOutput *output){
		outputs.push_back( output );
		DataSet* out = new DataSet;
		if( output==NULL){
			cout<<"NULL OUTPUT!"<<endl;
		};
		out->setOutput( output );
		outset.push_back( out );
		return out;
	};

	void setNetwork( NeuralNet *net){
		ann=net;
	};
	void activeDataSets( int index=0){
		datSet=0;
	};
	double train (bool incrementData=false){
	//	cout<<"Reached Train"<<endl;
		if(datCount==-99){
			datCount = inset[0]->dataCount();
		};
		int ds=0;
		while( ds<(int)inset.size() ){
			inset[ds]->activeSet( datSet );
			ds++;
		};
		
		ds=0;
		while( ds<(int)outset.size() ){
			outset[ds]->activeSet( datSet );
			ds++;
		};
	//	cout<<"set vars"<<endl;
		if( incrementData==true ){
			datSet++;
			if(datSet==datCount){
				datSet=0;
			};
		};
//		cout<<"Training set:"<<datSet<<endl;
		return ann->cycle();
	};
	
private:
	int datCount;
	int datSet;
	NeuralNet *ann;
	vector<NInput *>inputs;
	vector<NOutput *>outputs;
	vector<DataSet *>inset;
	vector<DataSet *>outset;
};

#endif // NEURALNET_H





A....A......ARGGGH!(Posted 2005-07-30)
A.I sucks. And not in the good way, like a hooker, but the really bad way, like a swoard wileding pirate.

The method belows works fine, but it's...still stupid. It gets caught between points that are 50/50 calls.

So I've gone back to the Neural network thing...

It's going well, the network is practically coded, just need to do some backprogadon(bah!) learning.

In case you're wondering what pure pain looks like however, here's the code. I had to switch from VC2003 toolkit, to mingw and then finally to Visual C++ Express 2005 beta 2.
For the debugger. (Note to mark. THAT'S WHAT A WINDOWS DEBUGGER SHOULD HAVE :) NONE OF THIS COMMAND LINE BULL WHOOP )

#ifndef NEURALNET_H
#define NEURALNET_H

using namespace std;
double rndn( double from,double fin)
{
    double rndr =(double) rand()/RAND_MAX;
    return from+(fin-from)*rndr;
};

double rndn()
{
    return (double)rand()/RAND_MAX;
};
double sigmoid(double netinput, double response=1)
{
    return ( 1.0 / ( 1.0 + exp(-netinput / response)));
}


class Neuron
{
public:


    ~Neuron()
    {}

	Neuron(){
		ic=0;
		oc=0;
		output=0;
		echoOut=false;
	};
    void connectNeuron( Neuron *to){
        out.push_back( to );
        oc++;
        to->addInput( (Neuron *)this);
      
//		cout<<"Connected Neuron"<<endl;
//		cout<<"Oc:"+oc<<endl;
//		cout<<"ic:"+to->ic;
	};
    
    void init(){
        oc=0;
        ic=0;
        double totw=0;
      
        for(int j=0;j<255;j++)
        {
            w[j]=rndn();
       
        };
        
        output =0;
    };
    
    
    
    void sumInputs()
    {
        double weight =0;
		if(ic==0) return;
	
        for(int i=0;i<ic;i++)
        {
		    weight += w[i] * in[i]->getOutput() ;
		};


        weight+= w[ic]*-1;
       // if(output>w[ic]*-1){
           output =sigmoid(weight,-1);
       // }else{
        //    output=0;
        //};
        
    };
    
    void fire(){
        
    };

    void setOutput( double noutput)
    {
        output=noutput;
    };

    double getOutput()
    {
		if(echoOut==true){
		cout<<"Echo Neuron called."<<endl;
		cout<<"Output is:"<<output<<endl;
		};

		return output;

    };
	void incInput(){
		ic++;
	};
	void addInput( Neuron *inN){
		in.push_back( inN );
		ic++;
		cout <<"Added input>"<<ic<<endl;
	};
	void echoOutput( bool enable=true){
		echoOut=enable;
	};
	double getErr(){
		return err;
	};
	void setErr( double val){
		err=val;
	};
private:
    vector<Neuron *>in;
    vector<Neuron *>out;
    double w[255];
    double output;
    int ic,oc;
	bool echoOut;
	double err;
};
// TODO (Antony#1#): Try increasing network by adding random neurons in areas of high activitity.\

class NInput
{
public:
	void addWatch(){
		dat->echoOutput(true);
	};
	void value(double input)
    {
        dat->setOutput( input );
    }
    Neuron *getNeuron(){
        return dat;
    };
    void setNeuron(Neuron *an){
        dat = an;
    };
	
	protected:
    Neuron *dat;

};

class NOutput
{
public:
    double value()
    {
        return dat->getOutput();
    }
    Neuron *getNeuron(){
        return dat;
    };
    void setNeuron(Neuron *an){
        dat = an;
    };
	void target( double val){
		desired = val;
	};

    protected:
    Neuron *dat;
    const char *name;
	double desired;
};



class NeuralNet
{
public:
   NeuralNet(){
	   ic=oc=hc=0;
   };
   ~NeuralNet(){
   };

    void addHiddenLayer( int neurons=8)
    {
        for(int j=0;j<neurons;j++)
        {
            
            hidden.push_back( new Neuron);
            //hidden[j]->init();
            
        };
        
        hc=neurons;
    };

    NInput* addInput()
    {
        NInput *out = new NInput;
        out->setNeuron( new Neuron);
        out->getNeuron()->init();
        inputs.push_back( out );
        ic++;
        return out;
    };

    NOutput *addOutput()
    {
        NOutput *out = new NOutput;
        out->setNeuron( new Neuron);
        out->getNeuron()->init();
        outputs.push_back( out );
        oc++;
        
        return out;

    };

    void connectNetwork()
    {
        for(int j=0;j<ic;j++)
        {
            for(int k=0;k<hc;k++)
            {
               Neuron *neuron;
                Neuron *hneuron = hidden[k];
                NInput *tempi = inputs[j];
               neuron = tempi->getNeuron();
                neuron->connectNeuron( hneuron );
            };
        };
		
        for(int j=0;j<hc;j++)
        {
            for(int k=0;k<oc;k++)
            {
                Neuron *neuron = hidden[j];
                Neuron *oneuron;
                NOutput *tempo=outputs[k];
                oneuron = tempo->getNeuron();
                neuron->connectNeuron( oneuron );
            };
        };
    };
    
    void cycle(){
        //Feed network.
		for(int j=0;j<hc;j++){
            hidden[j]->sumInputs();
        };
        for(int j=0;j<oc;j++){
            outputs[j]->getNeuron()->sumInputs();
        };
		//Calculate output neurons error.
		for(int j=0;j<oc;j++){
			double error;
		    double target=outputs[j]->getTarget;
			double actual=outputs[j]->value();
			error=(target - actual) * actual * (1 - actual);
			outputs[j]->getNeuron()->setErr( error );
		};

		for(int j=0;j<hc;j++){
			hidden[j]->hiddenError();
		};




		//Calculate hidden neurons error.
    };

protected:
    vector<NInput *> inputs;
    int ic;
    vector<Neuron *> hidden;
        int hc;
    vector<NOutput*> outputs;
    int oc;
private:

};

#endif // NEURALNET_H





A.I(Posted 2005-07-27)
Begun coding the A.I engine.

Basically, every actor that is not under direct player control(Although even the player can be controlled by a.i) has a VPU class. (VirtualPersonaUnit)

This is an high level governer of the bots actions.
Once the series of weighted tasks is processed, a set of orders is issued via an order class, which is returned back to the actor update class.

Then, to move, the vpu passes it's agent(Agent = Memory Unit) to the pathfinder class.

Pathfinding is a revelation. No maps, no pre-set up nodes are required. It learns.(Or at least it will. Nearly there!)

Firstly, it casts a net of 8 bi-directional linepicks out to establish if there are any walls near by.

If there are, what does it do? It adds an influence class to the local agent stack.

Influences are either local or global and have just two propertities. Fear and Attract.

At this point where the wall/obstacle was hit, a low-radius influence sphere is established that prevents the player from going towards the wall anymore.

Influences will be generated by all sorts of thigns. Missiles would be high fear influences. Health packs would be high attract influences.
Fellow bots would be high influneces too, to encourage flocking.

A score is generated for each bi-directional 'pathway' and this in turn is multiplied by each agent's Movement weight. Which is self-stablizing.

I also coded a Neural net class, but I decided against that in the end!

This is just a smidgen of the pathfinder/influence class. The real nuts and bolts resise in AINet/AITast/AIOrder.
#ifndef PATHFINDER_H
#define PATHFINDER_H
double sigmoid(double netinput, double response=1)
{
    return ( 1 / ( 1 + exp(-netinput / response)));
}
const Influence_Obstacle=1;

class Influence
{
public:
    Influence()
    {
        life=1;
        fade=true;
        fear=0;
        attract=0;
        lifeScale=1;
    };
    ~Influence()
    {}
    ;

    void position( float x,float y,float z)
    {
        loc.x=x;
        loc.y=y;
        loc.z=z;
    };
    
    Vector3 getPosition(){
        return loc;
    };

    void affectors( double nfear,double nattract,float decScale=0.95 )
    {
        fear = nfear;
        attract=nattract;
    };

    void update()
    {
        if(fade==true)
        {
            life=life*lifeScale;
        };
    };

    void setType( int nId)
    {
        type = nId;
    };
    double fearFrom( Vector3 from )
    {
        Vector3 dis;
        dis = from-loc;
        double adis = sqrt( dis.x*dis.x+dis.y*dis.y+dis.z*dis.z);
         double fscale = adis/radius;
        switch( scaleType )
        {
        case 1: //range based
           
            if(fscale>1)
                fscale=1;
            if(fscale<0)
                fscale=0;
            return fear*(1.0-fscale);
            break;
        case 2: //scaleless radius-bound
            if(adis<radius)
            {
                return fear;
            };
            break;
        };
    };
    double attractFrom( Vector3 from)
    {
        Vector3 dis;
        dis = from-loc;
        double adis = sqrt( dis.x*dis.x+dis.y*dis.y+dis.z*dis.z);
        double fscale = adis/radius; 
        switch( scaleType )
        {
        case 1: //range based
      
            if(fscale>1)
                fscale=1;
            if(fscale<0)
                fscale=0;
            return attract*(1.0-fscale);
            break;
        case 2: //scaleless radius-bound
            if(adis<radius)
            {
                return attract;
            };
            break;
        };
    };
    void fadeScale()
    {
        scaleType=1;
    };
    void radiusScale()
    {
        scaleType =2;
    };
    void setRadius( double nradius)
    {
        radius = nradius;
    };
private:
    double fear,attract;
    float life;
    float lifeScale;
    bool fade;
    Vector3 loc;
    int type;
    int scaleType;
    double radius;
};

List<Influence *>Influence_Global;

class Agent
{
public:
    Agent()
    {}
    ;
    Agent(int nId)
    {
        id=nId;
    };
    ~Agent()
    {}
    ;

    double scorePoint( Vector3 point )
    {
        double out;
        out = scorePoint(point, local )+scorePoint(point, Influence_Global );
        return out;
           };

    double scorePoint( Vector3 point,List<Influence*>ilist)
    {
        ilist.start();
        double tfear,tattract;
        tfear=tattract=0;
        while( ilist.next() )
        {
            Influence *inf = ilist.get();
            tfear+=inf->fearFrom( point );
            tattract+=inf->attractFrom( point );
        };
        double score = tattract-tfear;
        return score;
    };
    Influence *createInfluence()
    {
        Influence *out = new Influence;
        local.add( out );
        return out;
    };

    Influence* findInfluence( int type,Vector3 near,float radius)
    {
        local.start();
        while( local.next() )
        {
            Influence *tif = local.get();
            Vector3 dis = tif->getPosition();
            
            float adist = sqrt( dis.x*dis.x+dis.y*dis.y+dis.z*dis.z );
            if(adist<radius)
            {
                return tif;
            };
        };
        return NULL;
    };


private:
    int id;
    List<Influence *>local;
};

Influence * createGlobalInfluence()
{
    Influence *out;
    out = new Influence;
    Influence_Global.add( out );
    return out;
};

class PathFinder
{
public:
    PathFinder();
    virtual ~PathFinder();
    Vector3 find(Agent *agent, Vector3 from,Vector3 to);
protected:

private:
};
#endif // PATHFINDER_H
PathFinder::PathFinder()
{
    //ctor
    Speech<<"Sigmoid test";
    Speech<<"Sigmoid value of 200 is";
    Speech<< sigmoid(200,1);
    Speech<< "Sigmoid value of 20000 is";
    Speech<< sigmoid(20000,1);

}
PathFinder::~PathFinder()
{
    //dtor
}
Vector3 PathFinder::find( Agent *agent,Vector3 from,Vector3 to)
{
    Vector3 out;
    Hit *hit[8];

    hit[0] = colm->linePickRoot( from,from+Vector3( 200,0,0 ));
    hit[1] = colm->linePickRoot( from,from+Vector3( 200,0,200 ));
    hit[1] = colm->linePickRoot( from,from+Vector3( 0,0,200 ));
    hit[2] = colm->linePickRoot( from,from+Vector3( -200,0,200 ));
    hit[3] = colm->linePickRoot( from,from+Vector3( -200,0,0 ));
    hit[4] = colm->linePickRoot( from,from+Vector3( -200,0,-200));
    hit[5] = colm->linePickRoot( from,from+Vector3( 0,0,-200 ));
    hit[6] = colm->linePickRoot( from,from+Vector3( 200,0,-200));

    for( int j=0;j<7;j++)
    {
        if( hit[j]!=NULL)
        {
            Influence *exist = agent->findInfluence( Influence_Obstacle,hit[j]->position(),60);
            if(exist!=NULL)
            {}
            else
            {
                Speech<<"Wall influence added";
                exist =agent->createInfluence();
                exist->setType( Influence_Obstacle );
                exist->affectors( 10000,0,1 );
                exist->radiusScale();
                exist->setRadius( 100 );

            };
        };
    };


    return out;
};



Learning yet?

GOOD.



SpeechMarks(Posted 2005-07-25)
/\SkidMarks? ACIIIDDD!

Anyway, just finished the speech lib for the game. And I've already took advantage of it in the debug class.
It's like the ship's computer and I'm kirk hurtling through space, boldly coding what no man has coded before.

Now, when I boot up, I'm greeted by a computer voice "DebugLog Manager v0.1".

Whenever anything happens in game, like an exception or a note-worthy piece of info I decided to indicate to..myself in code, using debugLog->write("blah blah") is read out to me, as the game continually plays.

I am Kirk. Hear. Me. Ro. ar.

 void write( const char *text,bool audible = true)
    {
        char *ntext = (char*)text;
        if( audible==true ){
        Speech << ntext;
        }
        fprintf( handle,"Info:");
        fprintf( handle,text );
        fprintf( handle,"\n" );
        fprintf( handle,"-------------------");
        fprintf( handle,"\n");
    };
    


Next up I'll be using some sort of inverted flux streamable instanced object to spool the asyned pcm raw data into an openAL queue buffer channel - You know, like pouring sand through a funnel into a different shaped bottle (Star trek 101 - Explain it with a simple analogy ) - to virtualize the voices outputed into 3d space. - You know, like when Simon drops acid -


And..well, I think you can guess where it goes from there...



Sonic The Sound lib.(Posted 2005-07-24)
The sound system is now pretty cool. Has sound queues and a few simple fx (echo and amplifcation) that are performed in software.

The approach I'm going for(And am 95% there, the fx are baked in pre-play. The queue system will be used to dynamically process samples chunks at a time. This is to allow fx bleeding over the original smaple's length. Vital for real time echo etc. (Wouldn't want the sound cutting off just cos the file ends))

Here's the latest source of the sound engine only. I suggest someone wraps it in bmax(Save me the trouble :) ).you should be able to import it just fine as long as you copy the openAL lib/header files into your mingw folder.

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <iostream>
#include <stdio.h>
#include <string>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <al/al.h>
#include <al/alut.h>
#include <math.h>

template <class T>
class ListNode
{

public:
    T &get
    ()
    {
        return object;
    };
    void set
        (T &object)
    {
        this->object = object;
    };

    ListNode<T> *getNext()
    {
        return nextNode;
    };
    void setNext(ListNode<T> *nextNode)
    {
        this->nextNode = nextNode;
    };

private:
    T object;
    ListNode<T> *nextNode;
};

template <class T>
class List
{

public:
    // Constructor
    List()
    {
        headNode = new ListNode<T>;
        headNode->setNext(NULL);

        currentNode = NULL;
        size = 0;
    };

    // Destructor
    ~List()
    {

        ListNode<T> *pointerToDelete, *pointer = headNode;

        while (pointer != NULL)
        {
            pointerToDelete = pointer;
            pointer = pointer->getNext();
            delete pointerToDelete;
        }
    };

    T &get
    ()
    {

        if (currentNode == NULL)
            start();

        return currentNode->get
               ();
    };

    void add
        (T &addObject)
    {

        ListNode<T> *newNode = new ListNode<T>;

        newNode->set
        (addObject);

        newNode->setNext(headNode->getNext());
        headNode->setNext(newNode);

        size++;
    };

    void remove
        ()
    {

        lastCurrentNode->setNext(currentNode->getNext());

        delete currentNode;

        currentNode = lastCurrentNode;

        size--;
    };

    void start()
    {
        lastCurrentNode = headNode;
        currentNode = headNode;
    };

    bool next()
    {

        // If the currentNode now points at nothing, we've reached the end
        if (currentNode == NULL)
            return false;

        // Update the last node and current node
        lastCurrentNode = currentNode;
        currentNode = currentNode->getNext();

        // If currentNode points at nothing or there is nothing added, we can immediately return false
        if (currentNode == NULL || size == 0)
            return false;
        else
            return true;
    };

    int getSize()
    {
        return size;
    };

private:
    int size;
    ListNode<T> *headNode;
    ListNode<T> *currentNode, *lastCurrentNode;
};

float Audio_XScale =1;
float Audio_YScale =1;
float Audio_ZScale =1;

class Channel
{
public:
    Channel() //empty channel initilizations are always streams. it is the way.
    {
        loopData=false;
        isStream = true;
        init();
        bufsProcessed=0;
    }

    Channel( unsigned int bufferData,ALboolean nloopData =false  )
    {
        cSampleSet = bufferData;
        loopData=nloopData;
        isStream=false;
        init();

    //    debugLog->write("Channel constructed");
    };

    ~Channel()
    {
        alDeleteSources( 1,&cSource );
  //      debugLog->write("Channel deconstructed");
    };


    void queueBuffer( unsigned int bufferData)
                  {
                      ALuint tempi[5];
                      tempi[0]=(ALuint)bufferData;
                      alSourceQueueBuffers(cSource,1,&tempi[0] );
                      queued.add( (ALuint)bufferData );
                  };


void unqueueProcessed()
{

    ALint procBufs;
    alGetSourcei( cSource,AL_BUFFERS_PROCESSED,&procBufs);
    bufsProcessed = procBufs;
    if(procBufs>0)
    {
      
        queued.start();

        while( procBufs>0 )
        {
            queued.next();
            ALuint bufferData = queued.get();
            queued.remove();
            alSourceUnqueueBuffers(cSource,1,&bufferData);
            procBufs--;

        };
    };
};

int buffersProcessed(){
      return (int)bufsProcessed;
  };

bool isBufferQueued( ALuint bufferData ){
    queued.start();
    while( queued.next() ){
        if(queued.get() == bufferData){
            return true;
        };
    };
    return false;
};

void init()
{
    alGenSources( 1,&cSource );
    if(isStream==false)
    {
        alSourcei( cSource,AL_BUFFER,cSampleSet );
    };
    alSourcef(cSource,AL_PITCH,1.0f);
    alSourcef(cSource,AL_GAIN,1.0f);
    if(loopData==true)
    {
        alSourcei(cSource,AL_LOOPING,AL_TRUE);
        //debugLog->write("Sample looping activated");
    };
};

void position( float x,float y,float z )
{
    alSource3f( cSource,AL_POSITION,x*Audio_XScale,y*Audio_YScale,z*Audio_ZScale );
}
void velocity( float vx,float vy,float vz)
{
    alSource3f( cSource,AL_VELOCITY,vx,vy,vz);
};

void play()
{
    alSourcePlay( cSource );
};

void pitch( float scale)
{
    alSourcef( cSource,AL_PITCH, scale );
};
void volume( float vol )
{
    alSourcef( cSource, AL_GAIN,(vol/100.0) );
};

void play( float x,float y,float z )
{
    position( x,y,z );
    play();
};

void play( float x,float y,float z,float vx,float vy,float vz)
{
    position(x,y,z);
    velocity( vx,vy,vz);
    play();
};

void stop()
{
    alSourceStop( cSource );
};

void pause()
{
    alSourcePause( cSource );
};
bool isStopped()
{
    return 1-isPlaying();
};

bool isPlaying()
{
    ALint state;
    alGetSourcei( cSource,AL_SOURCE_STATE,&state );
    switch( state)
    {
    case AL_STOPPED:
        return false;
        break;
    case AL_PLAYING:
        return true;
        break;
    };
    return false;
};

protected:
ALint bufsProcessed;
bool isStream;
bool loopData;
unsigned int cSource;
unsigned int cSampleSet;
List <ALuint>queued;
};



class Sound
{
public:
    Sound()
    {
        inUse=false;
    };
    ~Sound()
    {
        alDeleteBuffers( 1,&sSampleSet );
        active.start();
        while( active.next() )
        {
            Channel *chan = active.get();
            active.remove();
            if(chan->isPlaying())
                chan->stop();
            delete chan;
        };
        //  delete active;
    };

    void freeChannel( Channel *in)
    {
        active.start();
        while( active.next() )
        {
            Channel *chan = active.get();
            if(chan == in)
            {
                active.remove();
                delete chan;
                break;
            };
        };
    };

    void loadRaw( const char *nfile)
    {
        try
        {
            int tfile;
            int fileSize;
            tfile =_open( nfile,_O_RDONLY );
            fileSize =_filelength( tfile );
            _close( tfile );

            FILE *fin;
            fin =fopen( nfile,"r");
            if(fin==NULL)
            {
          //      debugLog->write( nfile );
        //        debugLog->write( "was not found");
                exit(1);
            };
            raw = new ALshort[ fileSize ];
            int actr = fread( raw,2,fileSize/2,fin);
            if(actr!=fileSize)
            {
      //          debugLog->write("Pcm data read size mismatch");
            };
            fclose( fin );
            alGenBuffers(1,&sSampleSet);
            alBufferData( sSampleSet,AL_FORMAT_MONO16,raw,fileSize,11000);
        }
        catch(...)
        {
           // debugLog->write("Pcm loader, uncaught exception");
          //  debugLog->write( nfile );
        };

    };

    void createNoise( ALsizei length )
    {
        try
        {
            raw = new ALshort[ length ];
            ALint amp = 32700;
            for( ALsizei j=0;j<length;j++)
            {
                raw[j] = amp*sin( (float)j );
            };
            alGenBuffers(1,&sSampleSet);
            alBufferData( sSampleSet,AL_FORMAT_MONO16,raw,length,22000 );
        }
        catch(...)
        {
       //     debugLog->write("Create Noise threw an exception");
        };
    };
    void amplify( float scale ){
        
        for( ALsizei j=0;j<sLength/2;j++){
            float k = (float)raw[j];
            k=k*scale;
            raw[j]=(ALshort)k;
        };
        alBufferData( sSampleSet,sFormat,raw,sLength,sFreq);
   
    };
    
    void echo( float delay ){
        float rb = delay/1000;
        ALsizei backN = (ALsizei)((float)sFreq * rb);
        ALsizei ni=0;
        
        for( ALsizei j=0;j<sLength/2;j++){
            float k = (float)raw[j];
            ni=j-backN;
            if(ni>0){
            if(ni>=sLength) ni=sLength-1;
            raw[j] = (ALshort)k+raw[ni]/4;
            if(raw[j]<-20000) raw[j]=20000;
            if(raw[j]>20000) raw[j]=20000;
            }else{
            raw[j] =(ALshort)k;
            };
        };
        alBufferData( sSampleSet,sFormat,raw,sLength,sFreq);
    };
    
    void setLoop( bool loopData )
    {
        isLooped = loopData;
    };

    void loadRaw(const char *file,ALboolean loop = false )
    {
        ALboolean floop; //is file looped naturally?
        alutLoadWAVFile((ALbyte*) file,&sFormat,&sBuffer,&sLength,&sFreq,&floop);
        processBuffer();
        raw = new ALshort[ sLength ];
        memcpy( (void *) raw,(void *)sBuffer,sLength );
        alutUnloadWAV( sFormat,sBuffer,sLength,sFreq);
        ALenum error;
        if ((error = alGetError()) != AL_NO_ERROR)
        {
            printf("loadWav faliure %d", error);
        }
        isLooped = loop;
        alGenBuffers(1,&sSampleSet);
        alBufferData( sSampleSet,sFormat,raw,sLength,sFreq);
    };
    void loadWav(const char *file,ALboolean loop = false)
    {
        ALboolean floop; //is file looped naturally?
        alutLoadWAVFile((ALbyte*) file,&sFormat,&sBuffer,&sLength,&sFreq,&floop);
        processBuffer();

        alutUnloadWAV( sFormat,sBuffer,sLength,sFreq);
        ALenum error;
        if ((error = alGetError()) != AL_NO_ERROR)
        {
            printf("loadWav faliure %d", error);
        }
        isLooped = loop;
    };

    void processBuffer()
    {
        inUse = true;
        alGenBuffers(1,&sSampleSet);
        alBufferData( sSampleSet,sFormat,sBuffer,sLength,sFreq );
    };

    void registerChannel( Channel *in)
    {
        active.add( in );
    };

    Channel * playAt( float x,float y,float z)
    {
        Channel *out = new Channel( sSampleSet,isLooped );
        out->play( x,y,z,0,0,0 );
        registerChannel( out );
        return out;

    };

    Channel * playAt( float x,float y,float z,float vx,float vy,float vz)
    {
        Channel *out = new Channel( sSampleSet,isLooped );
        out->play( x,y,z,vx,vy,vz );
        registerChannel( out );
        return out;
    };

  

    void queue( Channel *to){
        to->queueBuffer( sSampleSet );
    };


    void update()
    {
        active.start();
        while( active.next() )
        {
            Channel *chan = active.get();
            if( chan->isStopped()==true )
            {
                active.remove();
                delete chan;
        //        debugLog->write("Channel finished playing.");
            };
            
        };
      
    };

    unsigned int alBuffer(){
        return( sSampleSet );
    };

protected:
    bool inUse;
    ALshort *raw;
    ALvoid *sBuffer; //Sound buffer.
    ALenum sFormat;
    ALsizei sFreq;
    ALsizei sLength;
    ALboolean sLoop;
    unsigned int sSource;
    unsigned int sSampleSet;
    ALboolean isLooped;
    List<Channel *>active;
    List<Channel *>queues;
    
};

class AudioManager
{
public:
    AudioManager()
    {
        initialize();
        setEar2d();
    };

    ~AudioManager()
    {
        active.start();
        while( active.next() )
        {
            Sound *snd = active.get();
            active.remove();
            delete snd;
        };

        //       delete active;
    };
    bool initialize()
    {
        alutInit( 0,NULL );
        return true;
    };
    void freeSound( Sound *in )
    {
        active.start();
        while( active.next() )
        {
            if( active.get()==in )
            {
                active.remove();
            };
        };
        delete in;
    };
    static AudioManager * createAudioManager()
    {
        return new AudioManager;
    };
    Sound * createSound()
    {
        Sound *out = new Sound;
        active.add( out );
        return out;
    };
    Sound * loadWav( const char *file,ALboolean loop = false )
    {
        Sound *out = new Sound;
        out->loadWav( file,loop );
        active.add( out );

        return out;
    };

    Sound * loadRaw( const char *file,ALboolean loop = false )
    {
        Sound *out = new Sound;
        out->loadRaw( file,loop );
        active.add( out );
        return out;
    };

    Channel * createQueueChannel(){
        Channel *out = new Channel;
        queues.add( out );
        return out;
    };

    void update()
    {
        active.start();
        while( active.next() )
        {
            Sound *snd = active.get();
            snd->update();
        };
        queues.start();
        while( queues.next() ){
            Channel *chan =queues.get();
            chan->unqueueProcessed();
        };
    };

    void setEar2d()
    {
        setEar( 0,0,0,0,0,-1,0,1,0 );
    };
    void setEar( float x,float y,float z,float fx,float fy,float fz,float ux,float uy,float uz)
    {
        float vec[6];
        vec[0]=fx;
        vec[1]=fy;
        vec[2]=fz;
        vec[3]=ux;
        vec[4]=uy;
        vec[5]=uz;
        alListener3f( AL_POSITION,x*Audio_XScale,y*Audio_YScale,z*Audio_ZScale );
        alListenerfv( AL_ORIENTATION,vec );
    };
protected:
    List<Sound *>active;
    List<Channel *>queues;
};

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nFunsterStil)
{
  AudioManager *audio = new AudioManager;
  audio->setEar2d();
  Sound *test = audio->loadRaw("test1.wav",false);
  Channel *spk = audio->createQueueChannel();
  spk->volume( 100 );
  test->queue( spk );
  spk->play( 0,0,0 );
  while( true ){
  audio->update();
  if( spk->isBufferQueued( test->alBuffer() )==false){
      test->echo( 200 );
      test->queue( spk );
      spk->play( 0,0,0 );
  };
 
  };
  
  return 0;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}





C++ Saw.(Posted 2005-07-23)
One last look at the life of a single source C++ game.

Just finished a custom sound lib using OpenAL(Like gl, but for sound.) can load wavs presently.
(Incidentally, if anyone wants to rip the source(I use mingw, so it'll work.) to the audio manager only, and use it to wrap openal for bmax..feel free.

I'll be making use of the really cool openal queue buffers which basically allow you to set up a queue of buffers to be streamed without pause, but you can dynamically remove and adder buffers to the queue as they are being played.

Allowing for all kinds of cpu realised special sound fx in 3d. I'm going to do a fully integrated 3d sound engine with fx like material dampening (I.e if a door's shut,it'll muffle sounds behind it.)
and other..stuff. Audio will be a big part of the experiance.

Going to start on the bmax side of things soon.

#include <iostream>
#include <stdio.h>
#include <string>
#include <windows.h>
#include "Ogre.h"
#include <al/al.h>
#include <al/alut.h>

using namespace Ogre;
 
SceneManager *gsmgr;
SceneNode *tformn;

void destroyNode( SceneNode *myNode){
   if (myNode==NULL) return;
   while(myNode->numAttachedObjects() > 0)
   {
     MovableObject* thisObject = myNode->detachObject(static_cast<unsigned short>(0));
     delete thisObject;
   }
   myNode->removeAndDestroyAllChildren();
   gsmgr->getRootSceneNode()->removeAndDestroyChild(myNode->getName());
};

template <class T> class ListNode {

public:
T &get() { return object; };
void set(T &object) { this->object = object; };

ListNode<T> *getNext() { return nextNode; };
void setNext(ListNode<T> *nextNode) { this->nextNode = nextNode; };

private:
T object;
ListNode<T> *nextNode;
};

template <class T> class List {

public:
// Constructor
List() {
headNode = new ListNode<T>;
headNode->setNext(NULL);

currentNode = NULL;
size = 0;
};

// Destructor
~List() {

ListNode<T> *pointerToDelete, *pointer = headNode;

while (pointer != NULL) {
pointerToDelete = pointer;
pointer = pointer->getNext();
delete pointerToDelete;
}
};

T &get() { 

if (currentNode == NULL) 
start();

return currentNode->get(); 
};

void add(T &addObject) {

ListNode<T> *newNode = new ListNode<T>;

newNode->set(addObject);

newNode->setNext(headNode->getNext());
headNode->setNext(newNode);

size++;
};

void remove() {

lastCurrentNode->setNext(currentNode->getNext());

delete currentNode;

currentNode = lastCurrentNode;

size--;
};

void start() {
lastCurrentNode = headNode;
currentNode = headNode;
};

bool next() {

// If the currentNode now points at nothing, we've reached the end
if (currentNode == NULL)
return false;

// Update the last node and current node
lastCurrentNode = currentNode;
currentNode = currentNode->getNext();

// If currentNode points at nothing or there is nothing added, we can immediately return false
if (currentNode == NULL || size == 0) 
return false;
else
return true;
};

int getSize() { return size; };

private:
int size;
ListNode<T> *headNode;
ListNode<T> *currentNode, *lastCurrentNode;
};

float Audio_XScale =0.01;
float Audio_YScale =0.01;
float Audio_ZScale =0.01;

class Channel{
public:
       Channel(){
       
       }
       
       Channel( unsigned int bufferData,ALboolean nloopData =false  ){
                cSampleSet = bufferData;          
                loopData=nloopData;
                init();      
       };
       
       ~Channel(){
         alDeleteSources( 1,&cSource );
         printf("Deleting Channel.");
       };
       
       
       void init(){
            alGenSources( 1,&cSource );
            alSourcei( cSource,AL_BUFFER,cSampleSet );
            alSourcef(cSource,AL_PITCH,1.0f);
	        alSourcef(cSource,AL_GAIN,1.0f);
	        if(loopData){
	           alSourcei(cSource,AL_LOOPING,AL_TRUE);
            };
       };
       
       void position( float x,float y,float z ){
            alSource3f( cSource,AL_POSITION,x*Audio_XScale,y*Audio_YScale,z*Audio_ZScale );
       }
       void velocity( float vx,float vy,float vz){
            alSource3f( cSource,AL_VELOCITY,vx,vy,vz);
       };
              
       void play(){
           alSourcePlay( cSource );
       };
       
       void pitch( float scale){
            alSourcef( cSource,AL_PITCH, scale );
       };
       void volume( float vol ){
            alSourcef( cSource, AL_GAIN,(vol/100.0) );
       };
       
       void play( float x,float y,float z ){
            position( x,y,z );
            play();
       };
       
       void play( float x,float y,float z,float vx,float vy,float vz){
            position(x,y,z);
            velocity( vx,vy,vz);     
            play();
       };
              
       void stop(){
            alSourceStop( cSource );
       };
       
       void pause(){
            alSourcePause( cSource );
       };
       bool isStopped(){
            return 1-isPlaying();
       };
       bool isPlaying(){
            ALint state;
            alGetSourcei( cSource,AL_SOURCE_STATE,&state );
            switch( state){
            case AL_STOPPED:
                 return false;
                 break;
            case AL_PLAYING:
                return true;
                break; 
            };
            printf("Warning - Channel in undefined state");
            printf("\n");
            return false;
       };
       
protected:
ALboolean loopData;
unsigned int cSource;
unsigned int cSampleSet;
};


class Sound{
public:
       Sound(){
               inUse=false;
       };
       ~Sound(){
                alDeleteBuffers( 1,&sSampleSet );
                active.start();
                while( active.next() ){
                       Channel *chan = active.get();
                       active.remove();
                       if(chan->isPlaying()) chan->stop();
                       delete chan;
                };
              //  delete active;
       };
       
       void loadWav(const char *file,ALboolean loop = false){
                 alutLoadWAVFile((ALbyte*) file,&sFormat,&sBuffer,&sLength,&sFreq,&loop);
                 processBuffer();
                 alutUnloadWAV( sFormat,sBuffer,sLength,sFreq);
                 ALenum error;
                 if ((error = alGetError()) != AL_NO_ERROR)
                 {
                  printf("loadWav faliure %d", error);
                 }
                 isLooped = loop;
       };
       
       void processBuffer(){
            inUse = true;
            alGenBuffers(1,&sSampleSet);
            alBufferData( sSampleSet,sFormat,sBuffer,sLength,sFreq );
       };
       
       void registerChannel( Channel *in){
            active.add( in );
       };
       
       Channel * playAt( float x,float y,float z){
               Channel *out = new Channel( sSampleSet,isLooped );
               out->play( x,y,z,0,0,0 );
               registerChannel( out );
               return out;
               
       };   
 
       Channel * playAt( float x,float y,float z,float vx,float vy,float vz){
               Channel *out = new Channel( sSampleSet,isLooped );
               out->play( x,y,z,vx,vy,vz );
               registerChannel( out );
               return out;
       };   
       
       void update(){
            active.start();
            while( active.next() ){
                   Channel *chan = active.get();
                   if( chan->isStopped()==true ){
                       printf("Channel Stopped!");
                       printf("\n");
                       active.remove();
                       delete chan;
                       chan->stop();
                   
                   };
            };
       };
       
              
protected:
bool inUse;
ALvoid *sBuffer; //Sound buffer.
ALenum sFormat;
ALsizei sFreq;
ALsizei sLength;
ALboolean sLoop;
unsigned int sSource;
unsigned int sSampleSet;
ALboolean isLooped;
List<Channel *>active;
};

class AudioManager{
public:
       AudioManager(){
           initialize();
           setEar2d();
       };
       
       ~AudioManager(){
            active.start();
            while( active.next() ){
                 Sound *snd = active.get();
                 active.remove();
                 delete snd;
            };    
          
   //       delete active;
       };
       bool initialize(){
            alutInit( 0,NULL );
            return true;
       };
       void freeSound( Sound *in ){
            active.start();
            while( active.next() ){
                   if( active.get()==in ){
                       active.remove();
                   };
            };
            delete in;
       };
       static AudioManager * createAudioManager(){
              return new AudioManager;
       };       
       Sound * loadWav( const char *file,ALboolean loop = false ){
              Sound *out = new Sound;
              loop = true;
              out->loadWav( file,loop );
              active.add( out );
              
              return out;
       };
       
       void update(){
             active.start();
              while( active.next() ){
                     Sound *snd = active.get();
                     snd->update();
              };
       };
              
       void setEar2d(){
            setEar( 0,0,0,0,0,-1,0,1,0 );
       };
       void setEar( float x,float y,float z,float fx,float fy,float fz,float ux,float uy,float uz){
            float vec[6];
            vec[0]=fx;
            vec[1]=fy;
            vec[2]=fz;
            vec[3]=ux;
            vec[4]=uy;
            vec[5]=uz;
            alListener3f( AL_POSITION,x,y,z );
            alListenerfv( AL_ORIENTATION,vec );
       };
protected:
List<Sound *>active;
};

AudioManager *audio;

const char * rts( float val ){
      String tmp = StringConverter::toString( val );
      return tmp.c_str();
};
const char * rts( int val ){
      String tmp = StringConverter::toString( (float)val);
      return tmp.c_str();
};

const char * rts( size_t val){
      String tmp = StringConverter::toString( (float)val);
      return tmp.c_str();
};

Vector3 tFormPoint( Vector3 Vec,SceneNode *around){
    if(tformn==NULL){
    tformn = gsmgr->getRootSceneNode()->createChildSceneNode();
    };
    SceneNode *temp=tformn;
    Vector3 tempv;
    Quaternion tempq;
    Matrix3 tempm;
    tempq = around->getOrientation();
    temp->setOrientation( tempq );
    tempv = around->getPosition();
    temp->setPosition( tempv );
    tempm = around->getLocalAxes();
    temp->translate( tempm,Vec );
    tempv = temp->getPosition();
    return tempv;        
};

float psysn;
class Particles{
public:
       Particles( String name,String psys,Entity *ent,String boneName){
             rSys = ParticleSystemManager::getSingleton().createSystem( name,psys );
             ent->attachObjectToBone( boneName,rSys );
             bone=NULL;
             
       };
       Particles( String psys,Entity *ent,String boneName){
             rSys = ParticleSystemManager::getSingleton().createSystem( "Particles "+StringConverter::toString( psysn ),psys );
             ent->attachObjectToBone( boneName,rSys );
             bone=NULL;
             psysn++; 
       };
       
       Particles( String psys,SceneNode * parent=NULL ){
         rSys = ParticleSystemManager::getSingleton().createSystem( "Particles "+StringConverter::toString( psysn ),psys );
             if(parent==NULL){
                 node = gsmgr->getRootSceneNode()->createChildSceneNode();
             }else{
                 node = parent->createChildSceneNode();
             };
             node->attachObject( rSys );        
             rSys->setCastShadows( true );                         
             bone = NULL;   
             psysn++;
       };
       
       Particles( String name,String psys,SceneNode* parent=NULL){
             rSys = ParticleSystemManager::getSingleton().createSystem( name,psys );
             if(parent==NULL){
                 node = gsmgr->getRootSceneNode()->createChildSceneNode();
             }else{
                 node = parent->createChildSceneNode();
             };
             node->attachObject( rSys );        
             rSys->setCastShadows( true );                         
             bone = NULL;             

       };
       ~Particles(){
       };
       void update(){
            if(bone!=NULL){
               node->setOrientation( bone->getWorldOrientation() );
               node->setPosition( bone->getWorldPosition() );
            };
       };
       
       void AttachTo( SceneNode *aTo){
           //      aTo->attachObject( node );
       };
       void AttachSub( SceneNode *aSub){
       //      node->attachObject( aSub );
       };
private:
SceneNode *node;
ParticleSystem* rSys;
Bone *bone;
};


class MatHold{
public:
       MatHold(){
         changed=false;
         sub=NULL;
       };
       MatHold(SubEntity *asub){
           changed=false;  
           sub = asub;
       }
       ~MatHold(){
       };
       void setEntity( SubEntity *asub ){
            sub=asub;
       }
       void setMaterial( String MatName ){
             if(changed==true) return;
             lastMat = sub->getMaterialName();
             sub->setMaterialName( MatName );
             changed = true;
       };
       
       void resync(){
            if(changed==true){
             sub->setMaterialName( lastMat );
             changed=false;
            };
       };
              

MatHold *next;
protected:
SubEntity * sub;
bool changed;
String lastMat;
};

MatHold * getLastMatHold( MatHold *root){
   if(root->next==NULL) return root;
   while(root->next!=NULL){
        root = root->next;
   };
   return root;
};


class MaterialOverider{
public:
      MaterialOverider(){
      root=NULL;
      };

      ~MaterialOverider(){
         
      };
      void addEntity( Entity *in){
           unsigned int nsubs = in->getNumSubEntities();
           MatHold *holds=NULL;
           if(root==NULL){
                       root = new MatHold;
                       holds = root;
           }else{
                       holds=getLastMatHold( root );
                       holds->next = new MatHold;
                       holds=holds->next;
           };
           
           for(size_t j=0;j<nsubs;j++){
                   holds->setEntity( in->getSubEntity( j ) );
                   if(j<(nsubs-1)){
                    holds->next = new MatHold;
                    holds=holds->next;
                   };
           };
      };      
      void clean(){
         delete root; //TO-DO - Clean up properly, including sub holds.
      };
      void setMaterial( String matName){
           MatHold *hold=root;
           while( hold->next!=NULL){
                 hold->setMaterial( matName );
                 hold=hold->next;
           }
           hold->setMaterial( matName );
      };
      void resync(){
           MatHold *hold;
           while( hold->next!=NULL){
                  hold->resync();
                  hold=hold->next;
           };  
           hold->resync();
      };
protected:
  MatHold *root;
  size_t hcount;
};


class AnimationBlender 
{ 
public: 
   enum BlendingTransition 
   { 
      BlendSwitch,         // stop source and start dest 
      BlendWhileAnimating,   // cross fade, blend source animation out while blending destination animation in 
      BlendThenAnimate      // blend source to first frame of dest, when done, start dest anim 
   }; 
    
private: 
   Entity *mEntity; 
   AnimationState *mSource; 
   AnimationState *mTarget; 
   Real mTimeleft, mDuration; 
   BlendingTransition mTransition;    

public: 
   void blend( const String &, BlendingTransition, Real ); 
   void addTime( Real ); 
   Real getProgress() { return mTimeleft/ mDuration; } 
   AnimationState *getSource() { return mSource; } 
   AnimationState *getTarget() { return mTarget; } 
   AnimationBlender( Entity *); 
   void init( const String &animation ); 
};

void AnimationBlender::init( const String &animation ) 
{ 
   AnimationStateSet *set = mEntity->getAllAnimationStates(); 
   AnimationStateSet::iterator it = set->begin(); 
   while(it != set->end()) 
   { 
      AnimationState &anim = it->second; 
      anim.setEnabled(false); 
      anim.setWeight(0); 
      anim.setTimePosition(0); 
      ++it; 
   } 
   mSource = mEntity->getAnimationState( animation ); 
   mSource->setEnabled(true); 
   mSource->setWeight(1); 
   mTimeleft = 0; 
   mDuration = 1; 
   mTarget = 0; 
} 

void AnimationBlender::blend( const String &animation, BlendingTransition transition, Real duration ) 
{ 
   if( transition == AnimationBlender::BlendSwitch ) 
   { 
      if( mSource != 0 ) 
         mSource->setEnabled(false); 
      mSource = mEntity->getAnimationState( animation ); 
      mSource->setEnabled(true); 
      mSource->setWeight(1); 
      mSource->setTimePosition(0); 
      mTimeleft = 0; 
   } 
   else 
   { 
      AnimationState *newTarget = mEntity->getAnimationState( animation ); 

      if( mTimeleft > 0 ) 
      { 
         // oops, weren't finished yet 
         if( newTarget == mTarget ) 
         { 
            // nothing to do! (ignoring duration here) 
         } 
         else if( newTarget == mSource ) 
         { 
            // going back to the source state, so let's switch 
            mSource = mTarget; 
            mTarget = newTarget; 
            mTimeleft = mDuration - mTimeleft; // i'm ignoring the new duration here 
         } 
         else 
         { 
            // ok, newTarget is really new, so either we simply replace the target with this one, or 
            // we make the target the new source 
            if( mTimeleft < mDuration * 0.5 ) 
            { 
               // simply replace the target with this one 
               mTarget->setEnabled(false); 
               mTarget->setWeight(0); 
            } 
            else 
            { 
               // old target becomes new source 
               mSource->setEnabled(false); 
               mSource->setWeight(0); 
               mSource = mTarget; 
            } 
            mTarget = newTarget; 
            mTarget->setEnabled(true); 
            mTarget->setWeight( 1.0 - mTimeleft / mDuration ); 
            mTarget->setTimePosition(0); 
         } 
      } 
      else 
      { 
         // assert( target == 0, "target should be 0 when not blending" ) 
         // mSource->setEnabled(true); 
         // mSource->setWeight(1); 
         mTransition = transition; 
         mTimeleft = mDuration = duration; 
         mTarget = newTarget; 
         mTarget->setEnabled(true); 
         mTarget->setWeight(0); 
         mTarget->setTimePosition(0); 
      } 
   } 
} 

void AnimationBlender::addTime( Real time ) 
{ 
   if( mSource != 0 ) 
   { 
      if( mTimeleft > 0 ) 
      { 
         mTimeleft -= time; 
         if( mTimeleft < 0 ) 
         { 
            // finish blending 
            mSource->setEnabled(false); 
            mSource->setWeight(0); 
            mSource = mTarget; 
            mSource->setEnabled(true); 
            mSource->setWeight(1); 
            mTarget = 0; 
         } 
         else 
         { 
            // still blending, advance weights 
            mSource->setWeight( mTimeleft / mDuration ); 
            mTarget->setWeight( 1.0 - mTimeleft / mDuration ); 

            if( mTransition == AnimationBlender::BlendWhileAnimating ) 
               mTarget->addTime( time ); 
         } 
      } 
      mSource->addTime( time ); 
   } 
} 

AnimationBlender::AnimationBlender( Entity *entity ) : mEntity(entity) {}

void printb( const char *out){
     printf( out);
     printf("\n");
};

class Geo{
public:
      ~Geo(){
      };
      Geo( Mesh *mesh,const Vector3& position,const Quaternion& orient,const Vector3& scale){
           printb("Entered Geo Creation");
           bool added_shared = false;
           _index_count =0;
           _vertex_count=0;
           
           size_t current_offset = _vertex_count,shared_offset = _vertex_count,next_offset = _vertex_count,index_offset = _index_count;
           size_t prev_vert = _vertex_count,prev_ind = _index_count;
           
           _got_size = _got_radius = false;
           printb("About to calculate vertices/indices");
// Calculate how many vertices and indices we're going to need
for(int i = 0;i < mesh->getNumSubMeshes();i++)
{
SubMesh* submesh = mesh->getSubMesh(i);

// We only need to add the shared vertices once
if(submesh->useSharedVertices)
{
if(!added_shared)
{
VertexData* vertex_data = mesh->sharedVertexData;
_vertex_count += vertex_data->vertexCount;
added_shared = true;
}
}
else
{
VertexData* vertex_data = submesh->vertexData;
_vertex_count += vertex_data->vertexCount;
}

// Add the indices
Ogre::IndexData* index_data = submesh->indexData;
_index_count += index_data->indexCount;
}
printb("Finished calcing");

printf("Tris:");
printf( rts( _index_count) );
printf("\n");
printf("Verts:");
printf( rts( _vertex_count) );
printf("\n");
printb("Allocating geo space");
// (re)allocate space for the vertices and indices
Vector3* tmp_vert = new Vector3[_vertex_count];
if(prev_vert)
{
memcpy(tmp_vert,_vertices,sizeof(Vector3) * prev_vert);
delete[] _vertices;
}
_vertices = tmp_vert;

int* tmp_ind = new int[_index_count];
if(prev_ind)
{
memcpy(tmp_ind,_indices,sizeof(int) * prev_ind);
delete[] _indices;
}
_indices = tmp_ind;

added_shared = false;
printb("Finished adding space");

printb("Adding mesh data");
// Run through the submeshes again, adding the data into the arrays
for(int i = 0;i < mesh->getNumSubMeshes();i++)
{
SubMesh* submesh = mesh->getSubMesh(i);

Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
{
if(submesh->useSharedVertices)
{
added_shared = true;
shared_offset = current_offset;
}

const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
Ogre::Real* pReal;

for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
{
posElem->baseVertexPointerToElement(vertex, &pReal);

Vector3 pt;

pt.x = (*pReal++);
pt.y = (*pReal++);
pt.z = (*pReal++);

pt = (orient * (pt * scale)) + position;

_vertices[current_offset + j].x = pt.x;
_vertices[current_offset + j].y = pt.y;
_vertices[current_offset + j].z = pt.z;
}
vbuf->unlock();
next_offset += vertex_data->vertexCount;
}

Ogre::IndexData* index_data = submesh->indexData;

size_t numTris = index_data->indexCount / 3;
unsigned short* pShort;
unsigned int* pInt;
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
if (use32bitindexes) pInt = static_cast<unsigned int*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
else pShort = static_cast<unsigned short*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));

for(size_t k = 0; k < numTris; ++k)
{
size_t offset = (submesh->useSharedVertices)?shared_offset:current_offset;

unsigned int vindex = use32bitindexes? *pInt++ : *pShort++;
_indices[index_offset + 0] = vindex + offset;
vindex = use32bitindexes? *pInt++ : *pShort++;
_indices[index_offset + 1] = vindex + offset;
vindex = use32bitindexes? *pInt++ : *pShort++;
_indices[index_offset + 2] = vindex + offset;

index_offset += 3;
}
ibuf->unlock();
current_offset = next_offset;
}
};

  int countVertices(){
      return _vertex_count;
  }
  int countTris(){
      return _index_count/3;
  };
  Vector3 getVertex( int index=0){
     return _vertices[index];
  };
  Vector3 triVertex( int triIndex,int vertIndex){
      return _vertices[ _indices[triIndex*3+vertIndex] ];
  };
  Geo *next;      
protected:
  Vector3* _vertices;
  int *_indices;
  size_t _vertex_count;
  size_t _index_count;
  int _got_radius,_got_size;
};

class Hit{
public:
   Hit( Vector3 nnormal,Vector3 npoint,Vector3 ndepth,int triId){
        dnormal=nnormal;
        dpoint=npoint;
        ddepth=ndepth;
        idTri=triId;
   };
   ~Hit(){
   }
   Vector3 position(){
           return dpoint;
} 
   Vector3 normal(){
           return dnormal;
}
   Vector3 depth(){
           return ddepth;
};
   int triHit(){
       return idTri;
   };
protected:
  Vector3 dnormal;
  int idTri;
  Vector3 dpoint;
  Vector3 ddepth;
};

class Collision{
public:
   Collision(){
      root=NULL;
   };
   ~Collision(){
   };

   void addGeo(Geo* geo){
      if(root==NULL){
         root=geo;
      }else{
         Geo * tempg=root;
         Geo *lastg=NULL;
         while( tempg->next!=NULL){
              lastg=tempg;
              tempg = tempg->next;
              if(tempg==NULL){
                 tempg=lastg;
              };
         };
         tempg->next=geo;
       };   
   };
      Hit* linePick( Geo *geo,Vector3 start,Vector3 dir){
           bool Extend_To_Infinity = false;
           bool Cull_Backfaces = false; 
//Function rit(Px#,Py#,Pz#, Dx#,Dy#,Dz#, V0x#,V0y#,V0z#, V1x#,V1y#,V1z#, V2x#,V2y#,V2z#, Extend_To_Infinity=1, Cull_Backfaces=0)
           int triCount =geo->countTris();

           Vector3 v0,v1,v2;
           float smallDis=9999999;
           int triHit=-1;
           Vector3 closePoint;
           for(int j=0;j<triCount;j++){
              v0 = geo->triVertex( j,0 );
              v1 = geo->triVertex( j,1 );
              v2 = geo->triVertex( j,2 );
    //;-
              float E1x = v2.x - v0.x;
              float E1y = v2.y - v0.y;
              float E1z = v2.z - v0.z;
    
    //;-
              float E2x = v1.x - v0.x;
                float E2y = v1.y - v0.y;
                float E2z = v1.z - v0.z;
                  float Hx = (dir.y * E2z) - (E2y * dir.z);
                  float Hy = (dir.z * E2x) - (E2z * dir.x);
      float Hz = (dir.x * E2y) - (E2x * dir.y);
    
    // Calculate the dot product of the above vector and the vector between point 0 and point 2.
    float A = (E1x * Hx) + (E1y * Hy) + (E1z * Hz);
    
    if( (A >= 0) ) continue;

    if ( A > -0.00001){
       if(A < 0.00001){ 
          continue;
          }
          }
       
//;Inverse Determinant
     float F = 1.0 / A;

//;-
     float Sx = start.x - v0.x;
      float Sy = start.y - v0.y;
      float Sz = start.z - v0.z;


//; U# = F# * (DotProduct(Sxyz, Hxyz))
    float U = F * ((Sx * Hx) + (Sy * Hy) + (Sz * Hz));


//;check u
         if ( U < 0.0) continue; 
         if (U > 1.0) continue;

//; Qxyz = CrossProduct(Sxyz, E1xyz)

    float Qx = (Sy * E1z) - (E1y * Sz);
      float Qy = (Sz * E1x) - (E1z * Sx);
      float Qz = (Sx * E1y) - (E1x * Sy);

//; V# = F# * DotProduct(Dxyz, Qxyz)
       float V = F * ((dir.x * Qx) + (dir.y * Qy) + (dir.z * Qz));


//;check v
         if( V < 0.0){
             continue;
         }; 
         if ((U + V) > 1.0) continue;

        float T = F*((E2x*Qx)+(E2y*Qy)+(E2z*Qz)); 

        if(T<0.0) continue;
        if( T>1) continue;

//;Calculate intersection point
             float nx=(E1y*E2z)-(E1z*E2y);
             float ny=(E1z*E2x)-(E1x*E2z);
             float nz=(E1x*E2y)-(E1y*E2x);
          float d = -  nx*v0.x - ny*v0.y - nz*v0.z ;
          float denom = nx*dir.x + ny*dir.y + nz*dir.z;
          float mu = - (d + nx*start.x + ny*start.y + nz*start.z)/denom; // denom;
          Vector3 ip;
           ip.x = start.x + mu * dir.x;
           ip.y = start.y + mu * dir.y;
           ip.z = start.z + mu * dir.z;
           float xd,yd,zd,dis;
           xd = ip.x-start.x;
           yd = ip.y-start.y;
           zd = ip.z-start.z;
           dis = Math::Sqrt( xd*xd+yd*yd+zd*zd );
           if(dis<smallDis){
              closePoint = ip;
              smallDis =dis;
              triHit = j;
           }; 
          }
          if(triHit>-1){
             Hit *out = new Hit( Vector3(0,0,0),closePoint,Vector3(0,0,0),triHit );
            
             return out;
          };
       
          return NULL;
      };
      
      Hit* linePickRoot( Vector3 start,Vector3 dir){
           return linePick( root,start,dir );
      };

      Hit* linePick( Vector3 start,Vector3 dir){
         if(root==NULL) return NULL;
         
         linePick( root,start,dir );
         while( root->next!=NULL){
              linePick( root->next,start,dir );
              root=root->next;
         };
      };
protected:
 Geo *root; //*Static Geo.
};

Collision *colm = new Collision;

class Cam{
public:
       void registerObjs( Camera *in,InputReader *inputIn){
           aCam = in;
           input = inputIn;
      };
      void freeLook(){
           state =1;
      }
      void chaseNode(SceneNode *chase,Vector3 *RotOff){
           chaser=chase;
           rotOff = RotOff;
           state=2;
      };
      void update(){
           Degree xRot,yRot;
           Vector3 dir;
            Vector3 cPos;
           switch( state){
           case 1: //Free Look, yo.
            
                dir.x=0;
                dir.y=0;
                dir.z=0;
                xRot = input->getMouseRelY();
                yRot = input->getMouseRelX();
                aCam->pitch( -xRot );
                aCam->yaw( -yRot );
                if( input->isKeyDown(KC_W) ){
                    dir.x=1;
                }
                if( input->isKeyDown(KC_S) ){
                    dir.x=-1;
                };
                if( input->isKeyDown(KC_A) ){
                    dir.z=-1;
                };
                if( input->isKeyDown(KC_D) ){
                    dir.z=1;
                };
                aCam->moveRelative( dir);        
           break;
           case 2:
               
               cPos.x=-250;
               cPos.y=100;
               cPos.z=0;
               cPos.y-=rotOff->x*11;
               cPos.z+=rotOff->y*11;
               cPos.x+=Math::Sqrt( rotOff->x*rotOff->x+rotOff->y*rotOff->y )*12;
               if(cPos.x>-10) cPos.x=-10;
               cPos =tFormPoint( cPos,chaser );
               
             
               Vector3 tmpv =chaser->getPosition();
               tmpv.y+=50;
               Hit *hit = colm->linePickRoot( tmpv,Vector3( cPos.x-chaser->getPosition().x,
                                                                             cPos.y-chaser->getPosition().y,
                                                                             cPos.z-chaser->getPosition().z) );
               if(hit!=NULL){
                 cPos = hit->position();
               };
                                                                          
               aPos.x=aPos.x+(cPos.x-aPos.x)*0.35;
               aPos.y=aPos.y+(cPos.y-aPos.y)*0.35;
               aPos.z=aPos.z+(cPos.z-aPos.z)*0.35;
               aCam->setPosition( aPos );
               cPos = chaser->getPosition();
               cPos.y=cPos.y+110;
               aCam->lookAt( cPos );
               Degree trot;
               trot= rotOff->y;
               aCam->yaw( trot );
               trot =rotOff->x;
               aCam->pitch( trot );
               
               /*              
                cPos = chaser->getPosition();
                aPos.x=aPos.x+(cPos.x-aPos.x)*0.2;
                aPos.y=aPos.y+(cPos.y-aPos.y)*0.2;
                aPos.z=aPos.z+(cPos.z-aPos.z)*0.2;
                aCam->setPosition(aPos);
                cPos.x =0;
                cPos.y = 20;
                cPos.z = 450;
                aCam->moveRelative( cPos );
                cPos = chaser->getPosition();
                aCam->lookAt( cPos );
                */
            break;
           };             
      };
   
protected:
Camera *aCam;    
Vector3 aPos;
Vector3* rotOff;
int state;
SceneNode *chaser;
SceneNode *offNode;
InputReader *input;
};


        
//Prop class. Levels are comprised entirely out of props. Sing it biyach.
class Prop{
public:
      Prop( const char *propName,const char* mesh,bool castShadows = true){
            realMesh = MeshManager::getSingleton().load( mesh,
                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,    
                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 
				HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
				true, true);          
            unsigned short src, dest;
            if (!realMesh->suggestTangentVectorBuildParams(src, dest))
            {
                realMesh->buildTangentVectors(src, dest);
            }
            ent = gsmgr->createEntity( propName,mesh );
            node=gsmgr->getRootSceneNode()->createChildSceneNode();
            node->attachObject( ent );
            ent->setCastShadows( castShadows );
          //  materialOverider->addEntity( ent );
            dposition = node->getPosition();
            orient = node->getOrientation();
            scale.x=1;
            scale.y=1;
            scale.z=1;
           geo = new Geo( realMesh.getPointer(),dposition,orient,scale);
    };
    Geo * getGeo(){
       return geo;
    };
    Entity* getEntity(){
            return ent;
    }; 
    void turn( Degree pitch,Degree yaw,Degree roll ){
         node->pitch( pitch );
         node->yaw( yaw );
         node->roll( roll );
    };
    void position( float x,float y,float z ){
         node->setPosition( Vector3( x,y,z) );
    };         
protected:
MeshPtr realMesh;
Entity *ent;
SceneNode *node;
Geo *geo;
Vector3 dposition,scale;
Quaternion orient;
};

//Ominous Class. For all types of lights.
class Omni{
public:
      Omni(const char*lightName){
             light =gsmgr->createLight( lightName );
             light->setType( Light::LT_POINT );
             light->setDiffuseColour( 1.0, 1.0, 1.0 );
             light->setSpecularColour( 0.0, 0.0, 0.0 );
      };
      ~Omni(){
      };
      void position( Vector3 toPos ){
           light->setPosition( toPos );
      };
      void position( float x,float y,float z){
           light->setPosition( Vector3( x,y,z) );
      };
           
      Vector3 getPosition(){
           return light->getPosition();
      };
      void setColor( float red,float green,float blue ){
           light->setDiffuseColour( red/255.0,green/255.0,blue/255.0 );
      };
      void setSpecular( float red,float green,float blue){
           light->setSpecularColour( red/255.0,green/255.0,blue/255.0 );
      };
protected:
Light *light;
};
      
SceneNode *baseNode;


class Bullet{
public:
       Bullet(){
       };
       Bullet( String bulletName,String bulletMesh,bool castShadows = true){
               MeshPtr realMesh = MeshManager::getSingleton().load( bulletMesh,
                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,    
                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 
				HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
				true, true);          
            unsigned short src, dest;
            if (!realMesh->suggestTangentVectorBuildParams(src, dest))
            {
                realMesh->buildTangentVectors(src, dest);
            }
            ent = gsmgr->createEntity( bulletName,bulletMesh );
            node=gsmgr->getRootSceneNode()->createChildSceneNode();
            node->attachObject( ent );
            ent->setCastShadows( castShadows );    
            setWeight( 0.8 );
            smokeTrail = NULL;
       };
       
       
       ~Bullet(){
          // destroyNode( node );
         //  if(smokeTrail!=NULL){
           //    delete smokeTrail;
         //  };
           
         
       };
       
       void copyBone( SceneNode *snode,Bone *bone ){
            Vector3 tPos = snode->getPosition()+bone->getWorldPosition();
            Quaternion tQuat =snode->getOrientation() * bone->getWorldOrientation();
            node->setPosition( tPos );
            node->setOrientation( tQuat );
            
       };
       void addSmoke(){
            smokeTrail = new Particles( "Examples/Smoke2",node);
                        
       };       
       void setList( List<Bullet*> bList){
         brList = bList;
       };
       
       void setThrust( float speed,float speedinc){
      //     dir = node->getOrientation()*Vector3( speed,0,0 );
        spd=speed;
        spdinc=speedinc;
           // Vector3 nPos = node->getPosition();
           // node->setPosition( Vector3(0,0,0) );
            
           // dir = tFormPoint( Vector3(speed,0,0),node );
           // node->setPosition( nPos );
       };
       
       void setDirection( Vector3 mDirection ){
            dir = mDirection;
       };
       void setWeight( float mWeight){
            weight = mWeight;
       };
       void update(){
           // Vector3 tpos;
          //  tpos =node->getPosition();
          //  tpos.x+=dir.x;
          //  tpos.y+=dir.y;
          //  tpos.z+=dir.z;
          //node->setPosition( tpos );
            Vector3 dTra,lPos;
            dTra=node->getPosition();
            lPos = dTra;
            node->translate( node->getLocalAxes(),spd,0,0 ); 
            dTra= node->getPosition()-dTra ;
            
            Hit *hit = colm->linePickRoot( lPos,dTra );
            if (hit!=NULL){
              // delete this;
      
                brList.start();
           while( brList.next() ){
             if( brList.get() == this ){
                 brList.remove();
                 break;
             };
           }; 
               return;
            };
            spd=spd*spdinc;
            if(spd>35) spd=35;                    
//          node->lookAt( node->getPosition()+dir );
       }; 
        

protected:
SceneNode *node;
Entity *ent;
Vector3 dir;
Vector3 vInc;
float spd,spdinc;
float weight;
static Bullet *next;
Particles *smokeTrail;
List<Bullet*> brList;
};

List<Bullet*> bullets;

float gbulc;
// Calling all Actors. 
class Actor{
public:
       Actor(){
       }
       ~Actor(){
       }
       int boneCount(){
           Ogre::Skeleton::BoneIterator loop = skl->getBoneIterator();
           int boneCount=0;
           while( loop.hasMoreElements() ){
                  Bone *nullBone = loop.getNext();
                  boneCount+=1;
           };
           return boneCount;
       };
           Bone * getBone(int index){
           Ogre::Skeleton::BoneIterator loop = skl->getBoneIterator();
           int boneCount=0;
           if(index<1) index=1;
           Bone *nullBone;
           while( !boneCount==index ){
                  nullBone = loop.getNext();
                  boneCount+=1;
           };
           return nullBone;
       };
       
       Actor( const char *name,const char *mesh,short acpu=1,InputReader *cInput=NULL){
              ent = gsmgr->createEntity( name,mesh );
              ent->setCastShadows( true );
              node=gsmgr->getRootSceneNode()->createChildSceneNode();
              node->attachObject( ent );           
              input = cInput;
           //   materialOverider->addEntity( ent );
              bRot=0;
              lastBul= NULL;
              aBone=0;
              keys=0;
              lastFire=0;
              rotOff = new Vector3;
              rotOff->x=0;
              rotOff->y=0;
              rotOff->z=0;
              xi=yi=zi=0;
              cBone=NULL;
              aAnim=NULL;
              state=0;
              aimlock=0;
              cpu=acpu;
              cAnim = NULL;
              aState=0;
              state=0;
              aimNode = gsmgr->getRootSceneNode()->createChildSceneNode();
              if( ent->hasSkeleton()==true){
                  skl = ent->getSkeleton();
              }else{
                printf("Spawned Actor with no skeleton");
                printf("\n");
              };
              Ogre::Skeleton::BoneIterator bdat = skl->getBoneIterator();
              while( bdat.hasMoreElements())
              {
                     Bone *tbone = bdat.getNext();
                     printf("Bone:");
                     String boneName = tbone->getName();
                     printf( (const char *)boneName.c_str() );
                     printf("\n");
              };
            
              cBone = skl->getBone("Joint10");
              if(cBone==NULL){
               printf("Skeleton had no joint 10. Shit dude.");
               printf("\n");
              };                            
              cBone->setManuallyControlled(true);
              aAnim=skl->getAnimation("Idle");
              aAnim->destroyTrack( cBone->getHandle() );
              aAnim=skl->getAnimation("Walk");
              aAnim->destroyTrack( cBone->getHandle() );
              aAnim=skl->getAnimation("Shoot");
              aAnim->destroyTrack( cBone->getHandle() );
       printf("LEAVING ACTOR CREATOR");
       printf("\n");
              //mAnimationBlender = new AnimationBlender( ent );
              //mAnimationBlender->init("Idle1");
             // gunSys = new Particles("Rain","Examples/PurpleFountain",ent,"Joint10");
       }
      
      
      SceneNode* getNode(){
           return node;
      }
      SceneNode* getAimNode(){
         return aimNode;
         }
         
           
         
      void playAnim( const char* animName,bool loop = false,float spd=0.01){
                 if( cAnim==NULL){
                 }else{
                  cAnim->setEnabled( false );
                 };
                 AnimationState * temp = cAnim;
                                               
                 cAnim = ent->getAnimationState( animName );
                 if( cAnim==temp ){
                     
                 }else{
                   aAnim = skl->getAnimation( animName );
                 };
                cAnim->setLoop( loop );
                cAnim->setEnabled( true );
               //  mAnimationBlender->blend( animName,AnimationBlender::BlendThenAnimate,0.5);
                 aState=state;
                 aSpeed=spd;

               
       }
       
       void update(){
            DWORD ticks = GetTickCount();
                                  
            switch( state){
            case 0:
              state=1;
             break;
            case 1:
               // if(cAnim==NULL){
               //     playAnim("Idle1",true,0.002);
              //  }else{
              //      if(!aState==1){
                          playAnim("Idle",true,0.002); 
                
            //        }; 
              break;
              case 2:
                   
                  // if( (!aState==2) ){
                         playAnim("Walk",true,0.02);
                //   };
                state=1;
                break;
              case 4:
                   //if(!aState==4){
                         playAnim("Shoot",false,0.02);
                   //}
                   if( (cAnim->getTimePosition() > ( cAnim->getLength()-0.2 )) ){
                     state=1;
                     lockstate=false;
                     cAnim->setTimePosition( 0 );
                    };
              break;
             }     
              int oldstate;
              Vector3 dir;
              Degree xRot,yRot;   
            Matrix3 lAx;
            switch( cpu){
            case 1:
             
                dir.x=0;
                dir.y=0;
                dir.z=0;
                xRot = input->getMouseRelY()*0.2;
                yRot = input->getMouseRelX()*0.5;
                if(aimlock==false){
                node->yaw( -yRot );
                };
                
                oldstate=state;
                dir=aimNode->getPosition();
                dir.y=dir.y+input->getMouseRelY();
                aimNode->setPosition( dir );
                dir.x=0;
                dir.y=0;
                dir.z=0;
                if(input->getMouseButton(0)==true){
                 state=4;
                 oldstate=4;
                 lockstate=true;
                }
                /*
                if( input->isKeyDown(KC_Q)==true){
                   if(keys==false){
                      keys=true;
                      aBone+=1;
                      if(cBone==NULL){
                      }else{
                            cBone->setManuallyControlled(false);
                      };
                      cBone = this->getBone( aBone );
                      cBone->setManuallyControlled(true);
                      aAnim->destroyTrack( cBone->getHandle() );            
                      
                      
                   };
                }else{
                      keys=false;
                     
                };
                */
                if(input->isKeyDown(KC_W)==true){
                   dir.x=7;
                   state=2;
                   node->yaw( yAt );
                   cBone->yaw( -yAt );
                   yAt=0;
                };
                if(input->getMouseButton(1)==true){
                      aimlock=true;
                }else{
                      aimlock=false;
                };
                  if(input->getMouseButton(0)==true){
                  if( ticks>(lastFire+150)){
                  gbulc++;
                  lastFire=ticks;
                   lastBul = new Bullet( "Bullet "+StringConverter::toString( gbulc ),"missile1.mesh",true );
                   lastBul->copyBone( node,cBone );
                   lastBul->addSmoke();
                  // Vector3 dVec;
                  // SceneNode *tnode = gsmgr->getRootSceneNode()->createChildSceneNode();
                 //  tformn->setPosition( Vector3(0,0,0) );
                  // tformn->setOrientation( node->getOrientation()*cBone->getWorldOrientation() );
                   //dVec = tFormPoint( Vector3(20,0,0),tformn );
                    lastBul->setThrust( 0.1,1.15 );
                    bullets.add( lastBul ); 
                    }; 
                   };
                                
                
                   
                if(input->isKeyDown(KC_S)){
                  dir.x=-4;
                  state=2;
                };
                lAx = node->getLocalAxes();
                node->translate( lAx,dir);
                if(lockstate==true){
                 state=oldstate;
                 };
                break;
            };
            updateAnim();
            
            pAt-=xRot;
            yAt-=yRot;
            if(aimlock==false){
                 yAt=yAt*0.95;
            };
            
       
            if(pAt.valueDegrees()<-90){
             pAt=-90.0;
            // cBone->roll( -xRot );
            };
            if(pAt.valueDegrees()>90){
             pAt=90.0;
            // cBone->roll( -xRot);
            }; 
            if(yAt.valueDegrees()<-70){
             yAt=-70.0;
             //cBone->yaw( -yRot);
            };
            if(yAt.valueDegrees()>70){
             yAt=70.0;
            // cBone->yaw( -yRot);
             };
             Vector3 axs;
             axs.x=0;
             axs.y=1;
             axs.z=0;
             cBone->setOrientation( baseNode->getOrientation() );
             Radian prt;
             Radian yrt;
             prt=pAt;
             yrt=yAt;
             cBone->rotate( axs,yrt );
             axs.z=1;
             axs.y=0;
             cBone->rotate( axs,prt );
             
                 rotOff->x+= ((pAt.valueDegrees()*0.18)-rotOff->x)*0.2;
             if( aimlock==true){
                 rotOff->y+= ((yAt.valueDegrees()*0.18)-rotOff->y)*0.2;
             }else{
                rotOff->y=rotOff->y*0.3;
             };
             Vector3 feetVec = node->getPosition();
             feetVec.y=50;
             Vector3 tar;
             tar.x=0;
             tar.y=-10000;
             tar.z=0;
             Hit *feetAt = colm->linePickRoot( feetVec,tar );
             if(feetAt!=NULL){
                Vector3 tmpn = node->getPosition();
                feetVec = feetAt->position();
                if( feetVec.y<tmpn.y ){
                    if(yi>-40){
                     yi-=-0.4;
                    };
                }else{
                    yi=0;
                    tmpn.y = feetVec.y;
                };
             };
             feetVec = node->getPosition();
             feetVec.y-=yi;
             node->setPosition( feetVec );
           //  gunSys->update();
       };
              
       Vector3* getRotationOffset(){
                return rotOff;
       };
                     
       void updateAnim(){
              if(cAnim==NULL){
                return;
              }
               //mAnimationBlender->addTime( aSpeed );
              cAnim->addTime( aSpeed );
       };
       void stopAnim(){
                  cAnim->setEnabled( false );
       };
protected:
 int aBone,keys;
 Actor *next;
 Bone *cBone;
 Vector3 *rotOff;
 Degree bRot;
 Entity *ent;
 RaySceneQuery *feetRay;
 Degree yAt,pAt;
 SkeletonInstance *skl;
 Bone *rootBone;
 SceneNode *node;
 InputReader *input;
 Particles* gunSys;
 Animation *aAnim;
 Node *aimAt;
 bool aimlock;
 short cpu;
 short state;
  AnimationState *cAnim;
 short aState;
 Bullet *lastBul;
 float aSpeed;
 DWORD lastFire;
 SceneNode *aimNode;
 int lockstate;
 float xi,yi,zi;
 AnimationBlender *mAnimationBlender;
};



const DWORD fps = 30;
DWORD period = 1000/fps;
DWORD timeAt = GetTickCount()-period;


void updateBullets(){
     bullets.start();
     while( bullets.next()){
                Bullet *bul =bullets.get();
                bul->update(); 
     };
};

void updateGame(){
     updateBullets();
};


int main()
{

      Ogre::Root* root = new Ogre::Root();

      if (!root->showConfigDialog())

            return -1;


        ConfigFile cf;
        cf.load("resources.cfg");

       
        // Go through all sections & settings in the file
        ConfigFile::SectionIterator seci = cf.getSectionIterator();

        String secName, typeName, archName;
        while (seci.hasMoreElements())
        {
            secName = seci.peekNextKey();
            ConfigFile::SettingsMultiMap *settings = seci.getNext();
            ConfigFile::SettingsMultiMap::iterator i;
            for (i = settings->begin(); i != settings->end(); ++i)
            {
                typeName = i->first;
                archName = i->second;
                ResourceGroupManager::getSingleton().addResourceLocation(
                    archName, typeName, secName);
            }
        }
 

      
      audio = new AudioManager;
      Ogre::RenderWindow* window = root->initialise(true);

      sndWav[0] = audio->loadWav("

      Ogre::SceneManager* smgr = root->getSceneManager(Ogre::ST_GENERIC);
      gsmgr = smgr;
      gbulc=0;

      Ogre::InputReader* inputDevice = Ogre::PlatformManager::getSingleton().createInputReader();

      inputDevice->initialise(window);

      Camera *vCam =smgr->createCamera("vCam");
      vCam->setNearClipDistance(5);
      Viewport *view = window->addViewport(vCam);
      view->setBackgroundColour( ColourValue(0,0,0) );
      vCam->setAspectRatio( Real( view->getActualWidth()) / Real(view->getActualHeight()) );
      //
      vCam->setPosition( Vector3(0,20,200) );
      vCam->lookAt( Vector3( 0,0,0) );
      Plane plane( Vector3::UNIT_Y, 0 );
      MeshManager::getSingleton().createPlane("ground",
           ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
           1500,1500,20,20,true,1,5,5,Vector3::UNIT_Z);
      Entity *flr;
      baseNode = smgr->getRootSceneNode()->createChildSceneNode();
        
 //    TextureManager *texMan = root->getTextureManager();
   //  TexturePtr tex = texMan->load("BumpMetal.jpg","");
       smgr->setShadowTechnique( SHADOWTYPE_STENCIL_MODULATIVE );
     // flr = smgr->createEntity("Floor","ground");
     // smgr->getRootSceneNode()->createChildSceneNode()->attachObject(flr);
       ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
      printf(" Loading prop : ");
       Prop *lev = new Prop( "Floor","testlevel.mesh",false);
      printf("Success.");
      printf("\n");
       flr = lev->getEntity();
       flr->setMaterialName("Examples/BumpMapping/MultiLightSpecular");
       smgr->setAmbientLight( ColourValue(0.1,0.1,0.1) );
       
       SceneManager *mSceneMgr = smgr;
  
       Omni *sun = new Omni("Light 1");
       sun->setColor( 255,255,255 );
       sun->position(200,200,500);
       Omni *spot = new Omni("Light 2");
       spot->position(300,500,500);
       spot->setColor(255,128,0);
      mSceneMgr->setSkyBox( true, "Examples/SpaceSkyBox" );
      Actor *player =new Actor("Ninja","robot.mesh",1,inputDevice);
      Degree camT;
      camT=1;
      Cam *viewer = new Cam;
      viewer->registerObjs(vCam,inputDevice);
      viewer->chaseNode( player->getNode(),player->getRotationOffset());
      DWORD elapsed=0;
      DWORD ticks=0;
      float ang,rad;    
      
     Geo * levGeo = lev->getGeo();
     colm->addGeo( levGeo );
     psysn=0;
    
    //  materialOverider->setMaterial("postfx/zshader");
     
      printf("Entering Main Loop");
      while (1)

      {

            MSG msg;

            while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))

            {

                  TranslateMessage(&msg);

                  DispatchMessage(&msg);

            }
            
            do{
               elapsed = GetTickCount()-timeAt;
            }while( !elapsed); 
            ticks = elapsed/period;
            for(DWORD k=0;k<ticks;k++){
               timeAt=timeAt+period;
               inputDevice->capture();
               viewer->update();
               player->update();
               updateGame();
               ang=ang+1;
             //  rad = Math::DegreesToRadians( ang );
             //  sun->position( Math::Sin( rad )*350,100,Math::Cos( rad )*350 ); 
            };


            if (!root->_fireFrameStarted())
            break;
            root->_updateAllRenderTargets();
            if (!root->_fireFrameEnded())
            break;
//End Render
            
         
            if (inputDevice->isKeyDown(Ogre::KC_ESCAPE))
            break;

      }

 

            return 0;

};





Smoke Trails(Posted 2005-07-20)
The missiles now emit glorious gulfs of fire and smoke when fired.

The main character is currently a missile shooting bad ass robot. This is likely to change!



The Da Vinchi Code.(Posted 2005-07-16)
For obvious reasons this'll be the last code I release publically, just thought it'll be interesting to see a C++ game take shape that isn't comprised of a million include files.

#include <iostream>
#include <stdio.h>
#include <string>
#include <windows.h>
#include "Ogre.h"
using namespace Ogre;
 
SceneManager *gsmgr;
SceneNode *tformn;

Vector3 tFormPoint( Vector3 Vec,SceneNode *around){
    if(tformn==NULL){
    tformn = gsmgr->getRootSceneNode()->createChildSceneNode();
    };
    SceneNode *temp=tformn;
    Vector3 tempv;
    Quaternion tempq;
    Matrix3 tempm;
    tempq = around->getOrientation();
    temp->setOrientation( tempq );
    tempv = around->getPosition();
    temp->setPosition( tempv );
    tempm = around->getLocalAxes();
    temp->translate( tempm,Vec );
    tempv = temp->getPosition();
    return tempv;        
};


class AnimationBlender 
{ 
public: 
   enum BlendingTransition 
   { 
      BlendSwitch,         // stop source and start dest 
      BlendWhileAnimating,   // cross fade, blend source animation out while blending destination animation in 
      BlendThenAnimate      // blend source to first frame of dest, when done, start dest anim 
   }; 
    
private: 
   Entity *mEntity; 
   AnimationState *mSource; 
   AnimationState *mTarget; 
   Real mTimeleft, mDuration; 
   BlendingTransition mTransition;    

public: 
   void blend( const String &, BlendingTransition, Real ); 
   void addTime( Real ); 
   Real getProgress() { return mTimeleft/ mDuration; } 
   AnimationState *getSource() { return mSource; } 
   AnimationState *getTarget() { return mTarget; } 
   AnimationBlender( Entity *); 
   void init( const String &animation ); 
};

void AnimationBlender::init( const String &animation ) 
{ 
   AnimationStateSet *set = mEntity->getAllAnimationStates(); 
   AnimationStateSet::iterator it = set->begin(); 
   while(it != set->end()) 
   { 
      AnimationState &anim = it->second; 
      anim.setEnabled(false); 
      anim.setWeight(0); 
      anim.setTimePosition(0); 
      ++it; 
   } 
   mSource = mEntity->getAnimationState( animation ); 
   mSource->setEnabled(true); 
   mSource->setWeight(1); 
   mTimeleft = 0; 
   mDuration = 1; 
   mTarget = 0; 
} 

void AnimationBlender::blend( const String &animation, BlendingTransition transition, Real duration ) 
{ 
   if( transition == AnimationBlender::BlendSwitch ) 
   { 
      if( mSource != 0 ) 
         mSource->setEnabled(false); 
      mSource = mEntity->getAnimationState( animation ); 
      mSource->setEnabled(true); 
      mSource->setWeight(1); 
      mSource->setTimePosition(0); 
      mTimeleft = 0; 
   } 
   else 
   { 
      AnimationState *newTarget = mEntity->getAnimationState( animation ); 

      if( mTimeleft > 0 ) 
      { 
         // oops, weren't finished yet 
         if( newTarget == mTarget ) 
         { 
            // nothing to do! (ignoring duration here) 
         } 
         else if( newTarget == mSource ) 
         { 
            // going back to the source state, so let's switch 
            mSource = mTarget; 
            mTarget = newTarget; 
            mTimeleft = mDuration - mTimeleft; // i'm ignoring the new duration here 
         } 
         else 
         { 
            // ok, newTarget is really new, so either we simply replace the target with this one, or 
            // we make the target the new source 
            if( mTimeleft < mDuration * 0.5 ) 
            { 
               // simply replace the target with this one 
               mTarget->setEnabled(false); 
               mTarget->setWeight(0); 
            } 
            else 
            { 
               // old target becomes new source 
               mSource->setEnabled(false); 
               mSource->setWeight(0); 
               mSource = mTarget; 
            } 
            mTarget = newTarget; 
            mTarget->setEnabled(true); 
            mTarget->setWeight( 1.0 - mTimeleft / mDuration ); 
            mTarget->setTimePosition(0); 
         } 
      } 
      else 
      { 
         // assert( target == 0, "target should be 0 when not blending" ) 
         // mSource->setEnabled(true); 
         // mSource->setWeight(1); 
         mTransition = transition; 
         mTimeleft = mDuration = duration; 
         mTarget = newTarget; 
         mTarget->setEnabled(true); 
         mTarget->setWeight(0); 
         mTarget->setTimePosition(0); 
      } 
   } 
} 

void AnimationBlender::addTime( Real time ) 
{ 
   if( mSource != 0 ) 
   { 
      if( mTimeleft > 0 ) 
      { 
         mTimeleft -= time; 
         if( mTimeleft < 0 ) 
         { 
            // finish blending 
            mSource->setEnabled(false); 
            mSource->setWeight(0); 
            mSource = mTarget; 
            mSource->setEnabled(true); 
            mSource->setWeight(1); 
            mTarget = 0; 
         } 
         else 
         { 
            // still blending, advance weights 
            mSource->setWeight( mTimeleft / mDuration ); 
            mTarget->setWeight( 1.0 - mTimeleft / mDuration ); 

            if( mTransition == AnimationBlender::BlendWhileAnimating ) 
               mTarget->addTime( time ); 
         } 
      } 
      mSource->addTime( time ); 
   } 
} 

AnimationBlender::AnimationBlender( Entity *entity ) : mEntity(entity) {}

class Geo{
public:
      ~Geo(){
      };
      Geo( Mesh *mesh,const Vector3& position,const Quaternion& orient,const Vector3& scale){
           bool added_shared = false;
           
           size_t current_offset = _vertex_count,shared_offset = _vertex_count,next_offset = _vertex_count,index_offset = _index_count;
           size_t prev_vert = _vertex_count,prev_ind = _index_count;
           
           _got_size = _got_radius = false;

// Calculate how many vertices and indices we're going to need
for(int i = 0;i < mesh->getNumSubMeshes();i++)
{
SubMesh* submesh = mesh->getSubMesh(i);

// We only need to add the shared vertices once
if(submesh->useSharedVertices)
{
if(!added_shared)
{
VertexData* vertex_data = mesh->sharedVertexData;
_vertex_count += vertex_data->vertexCount;
added_shared = true;
}
}
else
{
VertexData* vertex_data = submesh->vertexData;
_vertex_count += vertex_data->vertexCount;
}

// Add the indices
Ogre::IndexData* index_data = submesh->indexData;
_index_count += index_data->indexCount;
}

// (re)allocate space for the vertices and indices
Vector3* tmp_vert = new Vector3[_vertex_count];
if(prev_vert)
{
memcpy(tmp_vert,_vertices,sizeof(Vector3) * prev_vert);
delete[] _vertices;
}
_vertices = tmp_vert;

int* tmp_ind = new int[_index_count];
if(prev_ind)
{
memcpy(tmp_ind,_indices,sizeof(int) * prev_ind);
delete[] _indices;
}
_indices = tmp_ind;

added_shared = false;

// Run through the submeshes again, adding the data into the arrays
for(int i = 0;i < mesh->getNumSubMeshes();i++)
{
SubMesh* submesh = mesh->getSubMesh(i);

Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
{
if(submesh->useSharedVertices)
{
added_shared = true;
shared_offset = current_offset;
}

const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
Ogre::Real* pReal;

for(size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
{
posElem->baseVertexPointerToElement(vertex, &pReal);

Vector3 pt;

pt.x = (*pReal++);
pt.y = (*pReal++);
pt.z = (*pReal++);

pt = (orient * (pt * scale)) + position;

_vertices[current_offset + j].x = pt.x;
_vertices[current_offset + j].y = pt.y;
_vertices[current_offset + j].z = pt.z;
}
vbuf->unlock();
next_offset += vertex_data->vertexCount;
}

Ogre::IndexData* index_data = submesh->indexData;

size_t numTris = index_data->indexCount / 3;
unsigned short* pShort;
unsigned int* pInt;
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
if (use32bitindexes) pInt = static_cast<unsigned int*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
else pShort = static_cast<unsigned short*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));

for(size_t k = 0; k < numTris; ++k)
{
size_t offset = (submesh->useSharedVertices)?shared_offset:current_offset;

unsigned int vindex = use32bitindexes? *pInt++ : *pShort++;
_indices[index_offset + 0] = vindex + offset;
vindex = use32bitindexes? *pInt++ : *pShort++;
_indices[index_offset + 1] = vindex + offset;
vindex = use32bitindexes? *pInt++ : *pShort++;
_indices[index_offset + 2] = vindex + offset;

index_offset += 3;
}
ibuf->unlock();
current_offset = next_offset;
}
};

  int countVertices(){
      return _vertex_count;
  }
  int countTris(){
      return _index_count/3;
  };
  Vector3 getVertex( int index=0){
     return _vertices[index];
  };
  Vector3 triVertex( int triIndex,int vertIndex){
      return _vertices[ _indices[triIndex*3+vertIndex] ];
  };
  Geo *next;      
protected:
  Vector3* _vertices;
  int *_indices;
  size_t _vertex_count;
  size_t _index_count;
  int _got_radius,_got_size;
};

class Hit{
public:
   Hit( Vector3 nnormal,Vector3 npoint,Vector3 ndepth,int triId){
        dnormal=nnormal;
        dpoint=npoint;
        ddepth=ndepth;
        idTri=triId;
   };
   ~Hit(){
   }
   Vector3 position(){
           return dpoint;
} 
   Vector3 normal(){
           return dnormal;
}
   Vector3 depth(){
           return ddepth;
};
   int triHit(){
       return idTri;
   };
protected:
  Vector3 dnormal;
  int idTri;
  Vector3 dpoint;
  Vector3 ddepth;
};

class Collision{
public:
   void AddGeo(Geo* geo){
      if(root==NULL){
         root=geo;
      }else{
         while( root->next!=NULL){
              root = root->next;
         };
         root->next=geo;
      };   
   };
      Hit* linePick( Geo *geo,Vector3 start,Vector3 dir){
           bool Extend_To_Infinity = false;
           bool Cull_Backfaces = false; 
//Function rit(Px#,Py#,Pz#, Dx#,Dy#,Dz#, V0x#,V0y#,V0z#, V1x#,V1y#,V1z#, V2x#,V2y#,V2z#, Extend_To_Infinity=1, Cull_Backfaces=0)
           int triCount =geo->countTris();
           Vector3 v0,v1,v2;
           float smallDis=9999999;
           int triHit=-1;
           Vector3 closePoint;
           for(int j=0;j<triCount;j++){
              v0 = geo->triVertex( j,0 );
              v1 = geo->triVertex( j,1 );
              v2 = geo->triVertex( j,2 );
    //;-
              float E1x = v2.x - v0.x;
              float E1y = v2.y - v0.y;
              float E1z = v2.z - v0.z;
    
    //;-
              float E2x = v1.x - v0.x;
                float E2y = v1.y - v0.y;
                float E2z = v1.z - v0.z;
                  float Hx = (dir.y * E2z) - (E2y * dir.z);
                  float Hy = (dir.z * E2x) - (E2z * dir.x);
      float Hz = (dir.x * E2y) - (E2x * dir.y);
    
    // Calculate the dot product of the above vector and the vector between point 0 and point 2.
    float A = (E1x * Hx) + (E1y * Hy) + (E1z * Hz);
    
    if( ((Cull_Backfaces = 1) && (A >= 0))==true ) continue;


    if ( ((A > -0.00001) && (A < 0.00001))==true) continue;

//;Inverse Determinant
     float F = 1.0 / A;

//;-
     float Sx = start.x - v0.x;
      float Sy = start.y - v0.y;
      float Sz = start.z - v0.z;


//; U# = F# * (DotProduct(Sxyz, Hxyz))
    float U = F * ((Sx * Hx) + (Sy * Hy) + (Sz * Hz));


//;check u
         if ( ((U < 0.0) || (U > 1.0))==true ) continue;

//; Qxyz = CrossProduct(Sxyz, E1xyz)

    float Qx = (Sy * E1z) - (E1y * Sz);
      float Qy = (Sz * E1x) - (E1z * Sx);
      float Qz = (Sx * E1y) - (E1x * Sy);

//; V# = F# * DotProduct(Dxyz, Qxyz)
       float V = F * ((dir.x * Qx) + (dir.y * Qy) + (dir.z * Qz));


//;check v
         if(  ((V < 0.0) || ((U + V) > 1.0))==true) continue;

        float T = F*((E2x*Qx)+(E2y*Qy)+(E2z*Qz)); 

        if(T<0) continue;
        if( ((Extend_To_Infinity==0) && T>1)==true ) continue;

//;Calculate intersection point
             float nx=(E1y*E2z)-(E1z*E2y);
             float ny=(E1z*E2x)-(E1x*E2z);
             float nz=(E1x*E2y)-(E1y*E2x);
          float d = -  nx*v0.x - ny*v0.y - nz*v0.z ;
          float denom = nx*dir.x + ny*dir.y + nz*dir.z;
          float mu = - (d + nx*start.x + ny*start.y + nz*start.z); // denom;
          Vector3 ip;
           ip.x = start.x + mu * dir.x;
           ip.y = start.y + mu * dir.y;
           ip.z = start.z + mu * dir.z;
           float xd,yd,zd,dis;
           xd = ip.x-start.x;
           yd = ip.y-start.y;
           zd = ip.z-start.z;
           dis = Math::Sqrt( xd*xd+yd*yd+zd*zd );
           if(dis<smallDis){
              closePoint = ip;
              smallDis =dis;
              triHit = j;
           }; 
          }
          if(triHit>-1){
             Hit *out = new Hit( Vector3(0,0,0),closePoint,Vector3(0,0,0),triHit );
             return out;
          };
          return NULL;
      };
      
      Hit* linePickRoot( Vector3 start,Vector3 dir){
           return linePick( root,start,dir );
      };

      Hit* linePick( Vector3 start,Vector3 dir){
         if(root==NULL) return NULL;
         
         linePick( root,start,dir );
         while( root->next!=NULL){
              linePick( root->next,start,dir );
              root=root->next;
         };
      };
protected:
 Geo *root; //*Static Geo.
};

Collision *colm = new Collision;

class Cam{
public:
       void registerObjs( Camera *in,InputReader *inputIn){
           aCam = in;
           input = inputIn;
      };
      void freeLook(){
           state =1;
      }
      void chaseNode(SceneNode *chase,Vector3 *RotOff){
           chaser=chase;
           rotOff = RotOff;
           state=2;
      };
      void update(){
           Degree xRot,yRot;
           Vector3 dir;
            Vector3 cPos;
           switch( state){
           case 1: //Free Look, yo.
            
                dir.x=0;
                dir.y=0;
                dir.z=0;
                xRot = input->getMouseRelY();
                yRot = input->getMouseRelX();
                aCam->pitch( -xRot );
                aCam->yaw( -yRot );
                if( input->isKeyDown(KC_W) ){
                    dir.x=1;
                }
                if( input->isKeyDown(KC_S) ){
                    dir.x=-1;
                };
                if( input->isKeyDown(KC_A) ){
                    dir.z=-1;
                };
                if( input->isKeyDown(KC_D) ){
                    dir.z=1;
                };
                aCam->moveRelative( dir);        
           break;
           case 2:
               
               cPos.x=-350;
               cPos.y=100;
               cPos.z=0;
               cPos =tFormPoint( cPos,chaser );
                aPos.x=aPos.x+(cPos.x-aPos.x)*0.2;
                aPos.y=aPos.y+(cPos.y-aPos.y)*0.2;
                aPos.z=aPos.z+(cPos.z-aPos.z)*0.2;
               aCam->setPosition( aPos );
               cPos = chaser->getPosition();
               cPos.y=cPos.y+110;
               aCam->lookAt( cPos );
               Degree trot;
               trot= rotOff->y;
               aCam->yaw( trot );
               trot =rotOff->x;
               aCam->pitch( trot );
               
               /*              
                cPos = chaser->getPosition();
                aPos.x=aPos.x+(cPos.x-aPos.x)*0.2;
                aPos.y=aPos.y+(cPos.y-aPos.y)*0.2;
                aPos.z=aPos.z+(cPos.z-aPos.z)*0.2;
                aCam->setPosition(aPos);
                cPos.x =0;
                cPos.y = 20;
                cPos.z = 450;
                aCam->moveRelative( cPos );
                cPos = chaser->getPosition();
                aCam->lookAt( cPos );
                */
            break;
           };             
      };
   
protected:
Camera *aCam;    
Vector3 aPos;
Vector3* rotOff;
int state;
SceneNode *chaser;
SceneNode *offNode;
InputReader *input;
};


        
//Prop class. Levels are comprised entirely out of props. Sing it biyach.
class Prop{
public:
      Prop( const char *propName,const char* mesh,bool castShadows = true){
            realMesh = MeshManager::getSingleton().load( mesh,
                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,    
                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 
				HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
				true, true);          
            unsigned short src, dest;
            if (!realMesh->suggestTangentVectorBuildParams(src, dest))
            {
                realMesh->buildTangentVectors(src, dest);
            }
            ent = gsmgr->createEntity( propName,mesh );
            node=gsmgr->getRootSceneNode()->createChildSceneNode();
            node->attachObject( ent );
            ent->setCastShadows( castShadows );
            dposition = node->getPosition();
            orient = node->getOrientation();
            scale.x=1;
            scale.y=1;
            scale.z=1;
            geo = new Geo( realMesh.getPointer(),dposition,orient,scale);
    };
    Geo * getGeo(){
       return geo;
    };
    Entity* getEntity(){
            return ent;
    }; 
    void turn( Degree pitch,Degree yaw,Degree roll ){
         node->pitch( pitch );
         node->yaw( yaw );
         node->roll( roll );
    };
    void position( float x,float y,float z ){
         node->setPosition( Vector3( x,y,z) );
    };         
protected:
MeshPtr realMesh;
Entity *ent;
SceneNode *node;
Geo *geo;
Vector3 dposition,scale;
Quaternion orient;
};

//Ominous Class. For all types of lights.
class Omni{
public:
      Omni(const char*lightName){
             light =gsmgr->createLight( lightName );
             light->setType( Light::LT_POINT );
             light->setDiffuseColour( 1.0, 1.0, 1.0 );
             light->setSpecularColour( 0.0, 0.0, 0.0 );
      };
      ~Omni(){
      };
      void position( Vector3 toPos ){
           light->setPosition( toPos );
      };
      void position( float x,float y,float z){
           light->setPosition( Vector3( x,y,z) );
      };
           
      Vector3 getPosition(){
           return light->getPosition();
      };
      void setColor( float red,float green,float blue ){
           light->setDiffuseColour( red/255.0,green/255.0,blue/255.0 );
      };
      void setSpecular( float red,float green,float blue){
           light->setSpecularColour( red/255.0,green/255.0,blue/255.0 );
      };
protected:
Light *light;
};
      
SceneNode *baseNode;

// Calling all Actors. 
class Actor{
public:
       Actor(){
       }
       ~Actor(){
       }
       int boneCount(){
           Ogre::Skeleton::BoneIterator loop = skl->getBoneIterator();
           int boneCount=0;
           while( loop.hasMoreElements() ){
                  Bone *nullBone = loop.getNext();
                  boneCount+=1;
           };
           return boneCount;
       };
           Bone * getBone(int index){
           Ogre::Skeleton::BoneIterator loop = skl->getBoneIterator();
           int boneCount=0;
           if(index<1) index=1;
           Bone *nullBone;
           while( !boneCount==index ){
                  nullBone = loop.getNext();
                  boneCount+=1;
           };
           return nullBone;
       };
       
       Actor( const char *name,const char *mesh,short acpu=1,InputReader *cInput=NULL){
              ent = gsmgr->createEntity( name,mesh );
              ent->setCastShadows( true );
              node=gsmgr->getRootSceneNode()->createChildSceneNode();
              node->attachObject( ent );           
              input = cInput;
              bRot=0;
              aBone=0;
              keys=0;
              rotOff = new Vector3;
              rotOff->x=0;
              rotOff->y=0;
              rotOff->z=0;
              cBone=NULL;
              aAnim=NULL;
              state=0;
              aimlock=0;
              cpu=acpu;
              cAnim = NULL;
              aState=0;
              state=0;
              aimNode = gsmgr->getRootSceneNode()->createChildSceneNode();
              if( ent->hasSkeleton()==true){
                  skl = ent->getSkeleton();
              }else{
                printf("Spawned Actor with no skeleton");
                printf("\n");
              };
              Ogre::Skeleton::BoneIterator bdat = skl->getBoneIterator();
              while( bdat.hasMoreElements())
              {
                     Bone *tbone = bdat.getNext();
                     printf("Bone:");
                     String boneName = tbone->getName();
                     printf( (const char *)boneName.c_str() );
                     printf("\n");
              };
            
              cBone = skl->getBone("Joint10");
              if(cBone==NULL){
               printf("Skeleton had no joint 10. Shit dude.");
               printf("\n");
              };                            
              cBone->setManuallyControlled(true);
              aAnim=skl->getAnimation("Idle");
              aAnim->destroyTrack( cBone->getHandle() );
              aAnim=skl->getAnimation("Walk");
              aAnim->destroyTrack( cBone->getHandle() );
              aAnim=skl->getAnimation("Shoot");
              aAnim->destroyTrack( cBone->getHandle() );
       
              //mAnimationBlender = new AnimationBlender( ent );
              //mAnimationBlender->init("Idle1");
      }
      SceneNode* getNode(){
           return node;
      }
      SceneNode* getAimNode(){
         return aimNode;
         }
         
           
         
      void playAnim( const char* animName,bool loop = false,float spd=0.01){
                 if( cAnim==NULL){
                 }else{
                  cAnim->setEnabled( false );
                 };
                 AnimationState * temp = cAnim;
                                               
                 cAnim = ent->getAnimationState( animName );
                 if( cAnim==temp ){
                     
                 }else{
                   aAnim = skl->getAnimation( animName );
                 };
                cAnim->setLoop( loop );
                cAnim->setEnabled( true );
               //  mAnimationBlender->blend( animName,AnimationBlender::BlendThenAnimate,0.5);
                 aState=state;
                 aSpeed=spd;

               
       }
       
       void update(){
            
                                  
            switch( state){
            case 0:
              state=1;
             break;
            case 1:
               // if(cAnim==NULL){
               //     playAnim("Idle1",true,0.002);
              //  }else{
              //      if(!aState==1){
                          playAnim("Idle",true,0.002); 
                
            //        }; 
              break;
              case 2:
                   
                  // if( (!aState==2) ){
                         playAnim("Walk",true,0.02);
                //   };
                state=1;
                break;
              case 4:
                   //if(!aState==4){
                         playAnim("Shoot",false,0.02);
                   //}
                   if( (cAnim->getTimePosition() > ( cAnim->getLength()-0.2 )) ){
                     state=1;
                     lockstate=false;
                     cAnim->setTimePosition( 0 );
                    };
              break;
             }     
              int oldstate;
              Vector3 dir;
              Degree xRot,yRot;   
            Matrix3 lAx;
            switch( cpu){
            case 1:
             
                dir.x=0;
                dir.y=0;
                dir.z=0;
                xRot = input->getMouseRelY()*0.2;
                yRot = input->getMouseRelX()*0.5;
                if(aimlock==false){
                node->yaw( -yRot );
                };
                
                oldstate=state;
                dir=aimNode->getPosition();
                dir.y=dir.y+input->getMouseRelY();
                aimNode->setPosition( dir );
                dir.x=0;
                dir.y=0;
                dir.z=0;
                if(input->getMouseButton(0)==true){
                 state=4;
                 oldstate=4;
                 lockstate=true;
                }
                /*
                if( input->isKeyDown(KC_Q)==true){
                   if(keys==false){
                      keys=true;
                      aBone+=1;
                      if(cBone==NULL){
                      }else{
                            cBone->setManuallyControlled(false);
                      };
                      cBone = this->getBone( aBone );
                      cBone->setManuallyControlled(true);
                      aAnim->destroyTrack( cBone->getHandle() );            
                      
                      
                   };
                }else{
                      keys=false;
                     
                };
                */
                if(input->isKeyDown(KC_W)==true){
                   dir.x=7;
                   state=2;
                   node->yaw( yAt );
                   cBone->yaw( -yAt );
                   yAt=0;
                };
                if(input->getMouseButton(1)==true){
                      aimlock=true;
                }else{
                      aimlock=false;
                };
                if(input->isKeyDown(KC_S)){
                  dir.x=-4;
                  state=2;
                };
                lAx = node->getLocalAxes();
                node->translate( lAx,dir);
                if(lockstate==true){
                 state=oldstate;
                 };
                break;
            };
            updateAnim();
            
            pAt-=xRot;
            yAt-=yRot;
       
            if(pAt.valueDegrees()<-90){
             pAt=-90.0;
            // cBone->roll( -xRot );
            };
            if(pAt.valueDegrees()>90){
             pAt=90.0;
            // cBone->roll( -xRot);
            }; 
            if(yAt.valueDegrees()<-70){
             yAt=-70.0;
             //cBone->yaw( -yRot);
            };
            if(yAt.valueDegrees()>70){
             yAt=70.0;
            // cBone->yaw( -yRot);
             };
             Vector3 axs;
             axs.x=0;
             axs.y=1;
             axs.z=0;
             cBone->setOrientation( baseNode->getOrientation() );
             Radian prt;
             Radian yrt;
             prt=pAt;
             yrt=yAt;
             cBone->rotate( axs,yrt );
             axs.z=1;
             axs.y=0;
             cBone->rotate( axs,prt );
             if(aimlock==true){
                 rotOff->x+= ((pAt.valueDegrees()*0.18)-rotOff->x)*0.2;
                 rotOff->y+= ((yAt.valueDegrees()*0.18)-rotOff->y)*0.2;
             }else{
                rotOff->x=rotOff->x*0.2;
                rotOff->y=rotOff->y*0.2;
             };
             Vector3 feetVec = node->getPosition();
             feetVec.y+=5;
             Hit *feetAt = colm->linePickRoot( feetVec,Vector3(0,-100,0) );
             if(feetAt!=NULL){
                node->setPosition( feetAt->position() );
             };
       };
              
       Vector3* getRotationOffset(){
                return rotOff;
       };
                     
       void updateAnim(){
              if(cAnim==NULL){
                return;
              }
               //mAnimationBlender->addTime( aSpeed );
              cAnim->addTime( aSpeed );
       };
       void stopAnim(){
                  cAnim->setEnabled( false );
       };
protected:
 int aBone,keys;
 Bone *cBone;
 Vector3 *rotOff;
 Degree bRot;
 Entity *ent;
 RaySceneQuery *feetRay;
 Degree yAt,pAt;
 SkeletonInstance *skl;
 Bone *rootBone;
 SceneNode *node;
 InputReader *input;
 Animation *aAnim;
 Node *aimAt;
 bool aimlock;
 short cpu;
 short state;
  AnimationState *cAnim;
 short aState;
 float aSpeed;
 SceneNode *aimNode;
 int lockstate;
 AnimationBlender *mAnimationBlender;
};

const DWORD fps = 30;
DWORD period = 1000/fps;
DWORD timeAt = GetTickCount()-period;



int main()
{

      Ogre::Root* root = new Ogre::Root();

      if (!root->showConfigDialog())

            return -1;


        ConfigFile cf;
        cf.load("resources.cfg");

       
        // Go through all sections & settings in the file
        ConfigFile::SectionIterator seci = cf.getSectionIterator();

        String secName, typeName, archName;
        while (seci.hasMoreElements())
        {
            secName = seci.peekNextKey();
            ConfigFile::SettingsMultiMap *settings = seci.getNext();
            ConfigFile::SettingsMultiMap::iterator i;
            for (i = settings->begin(); i != settings->end(); ++i)
            {
                typeName = i->first;
                archName = i->second;
                ResourceGroupManager::getSingleton().addResourceLocation(
                    archName, typeName, secName);
            }
        }
 

      

      Ogre::RenderWindow* window = root->initialise(true);

 

      Ogre::SceneManager* smgr = root->getSceneManager(Ogre::ST_GENERIC);
      gsmgr = smgr;
 

      Ogre::InputReader* inputDevice = Ogre::PlatformManager::getSingleton().createInputReader();

      inputDevice->initialise(window);

      Camera *vCam =smgr->createCamera("vCam");
      vCam->setNearClipDistance(5);
      Viewport *view = window->addViewport(vCam);
      view->setBackgroundColour( ColourValue(0,0,0) );
      vCam->setAspectRatio( Real( view->getActualWidth()) / Real(view->getActualHeight()) );
      //
      vCam->setPosition( Vector3(0,20,200) );
      vCam->lookAt( Vector3( 0,0,0) );
      Plane plane( Vector3::UNIT_Y, 0 );
      MeshManager::getSingleton().createPlane("ground",
           ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
           1500,1500,20,20,true,1,5,5,Vector3::UNIT_Z);
      Entity *flr;
      baseNode = smgr->getRootSceneNode()->createChildSceneNode();
        
 //    TextureManager *texMan = root->getTextureManager();
   //  TexturePtr tex = texMan->load("BumpMetal.jpg","");
       smgr->setShadowTechnique( SHADOWTYPE_STENCIL_MODULATIVE );
     // flr = smgr->createEntity("Floor","ground");
     // smgr->getRootSceneNode()->createChildSceneNode()->attachObject(flr);
       ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
       Prop *lev = new Prop( "Floor","testlevel.mesh",false);
    
       flr = lev->getEntity();
       flr->setMaterialName("Examples/BumpMapping/MultiLightSpecular");
       smgr->setAmbientLight( ColourValue(0.1,0.1,0.1) );
       
       SceneManager *mSceneMgr = smgr;
  
       Omni *sun = new Omni("Light 1");
       sun->setColor( 255,255,255 );
       sun->position(200,200,500);
       Omni *spot = new Omni("Light 2");
       spot->position(300,500,500);
       spot->setColor(255,128,0);
      mSceneMgr->setSkyBox( true, "Examples/SpaceSkyBox" );
      Actor *player =new Actor("Ninja","robot.mesh",1,inputDevice);
      Degree camT;
      camT=1;
      Cam *viewer = new Cam;
      viewer->registerObjs(vCam,inputDevice);
      viewer->chaseNode( player->getNode(),player->getRotationOffset());
      DWORD elapsed=0;
      DWORD ticks=0;
      float ang,rad;    
      
      Geo * levGeo = lev->getGeo();
      colm->addGeo( levGeo );
        
      printf("Entering Main Loop");
      while (1)

      {

            MSG msg;

            while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))

            {

                  TranslateMessage(&msg);

                  DispatchMessage(&msg);

            }
            
            do{
               elapsed = GetTickCount()-timeAt;
            }while( !elapsed); 
            ticks = elapsed/period;
            for(DWORD k=0;k<ticks;k++){
               timeAt=timeAt+period;
               inputDevice->capture();
               viewer->update();
               player->update();
               ang=ang+1;
               rad = Math::DegreesToRadians( ang );
               sun->position( Math::Sin( rad )*350,100,Math::Cos( rad )*350 ); 
            };


            if (!root->_fireFrameStarted())
            break;
            root->_updateAllRenderTargets();
            if (!root->_fireFrameEnded())
            break;
//End Render

         
            if (inputDevice->isKeyDown(Ogre::KC_ESCAPE))
            break;

      }

 

            return 0;

};




Metal Gear Solid 3.(Posted 2005-07-16)
Just finished it. Easily the best game I've played in a long time. Probably the best period. The ending was pure art.

It's inspired me quite a bit, and it's lead to me intergrating ode into the project. I'm looking to make physics as integral to the project as they were to Half Life 2.
Going to post a demo game build using the game's engine in a day or so, a little robot-shoot-em-up. It's modular so will be easily changed into concept's media content when it's done. Still working out a way to port 3d max media into ogre.meshes in 3dmax7.5.



Prefab Soldier.(Posted 2005-07-15)
Skyline send me the design of the male lead character. It's a great mix of anime(in terms of shading/composition) and western influenced gear. It was pretty damned hot.

The actual game engine is now much more 'along' than previously. I can now walk around, and use rmb to take direct control of the upper torse, and this still is in fact when you're not directly influencing the upper body.
The result is a very nice look and feel to the controls already. A lot less restrictive than Splinter Cell's system, although not nearly as complex yet.

Although Splinter Cell is hardly the benchmark that I wish to surpass. That'll be easy.(Grin)
I want to topple MGS3. That'll be very hard...(Nervous grin.)



Ogre It.(Posted 2005-07-09)
#include <iostream>
#include <string>
#include <windows.h>
#include "Ogre.h"
using namespace Ogre;
 
SceneManager *gsmgr;

Vector3 tFormPoint( Vector3 Vec,SceneNode *around){
    SceneNode* temp = gsngr->getRootSceneNode()->createChildSceneNode();
    Vector3 tempv;
    Quaternion tempq;
    Matrix3 tempm;
    tempq = around->getOrientation();
    temp->setOrientation( tempq );
    tempv = around->getPosition()
    temp->setPosition( tempv );
    tempm = around->getLocalAxes();
    temp->translate( tempm,Vec );
    tempv = temp->getPosition();
    delete temp;
    return tempv;        
};

class Cam{
public:
      void registerObjs( Camera *in,InputReader *inputIn){
           aCam = in;
           input = inputIn;
      };
      void freeLook(){
           state =1;
      }
      void chaseNode(SceneNode *chase){
           chaser=chase;
           state=2;
      };
      void update(){
           Degree xRot,yRot;
           Vector3 dir;
            Vector3 cPos;
           switch( state){
           case 1: //Free Look, yo.
            
                dir.x=0;
                dir.y=0;
                dir.z=0;
                xRot = input->getMouseRelY();
                yRot = input->getMouseRelX();
                aCam->pitch( -xRot );
                aCam->yaw( -yRot );
                if( input->isKeyDown(KC_W) ){
                    dir.z=-1;
                }
                if( input->isKeyDown(KC_S) ){
                    dir.z=1;
                };
                if( input->isKeyDown(KC_A) ){
                    dir.x=-1;
                };
                if( input->isKeyDown(KC_D) ){
                    dir.x=1;
                };
                aCam->moveRelative( dir);        
           break;
           case 2:
               
               cPos.x=0;
               cPos.y=20;
               cPos.z=300;
               cPos =tFormPoint( cPos,chaser );
               aCam->setPosition( cPos );
               cPos = chaser->getPosition();
               aCam->lookAt( cPos );
               /*              
                cPos = chaser->getPosition();
                aCam->setPosition(cPos);
                cPos.x =0;
                cPos.y = 20;
                cPos.z = 450;
                aCam->moveRelative( cPos );
                cPos = chaser->getPosition();
                aCam->lookAt( cPos );
                */
            break;
           };             
      };
protected:
Camera *aCam;    
int state;
SceneNode *chaser;
InputReader *input;
};


        
//Prop class. Levels are comprised entirely out of props. Sing it biyach.
class Prop{
public:
      Prop( const char *propName,const char* mesh,bool castShadows = true){
            realMesh = MeshManager::getSingleton().load( mesh,
                ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,    
                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 
				HardwareBuffer::HBU_STATIC_WRITE_ONLY, 
				true, true);          
            unsigned short src, dest;
            if (!realMesh->suggestTangentVectorBuildParams(src, dest))
            {
                realMesh->buildTangentVectors(src, dest);
            }
            ent = gsmgr->createEntity( propName,mesh );
            node=gsmgr->getRootSceneNode()->createChildSceneNode();
            node->attachObject( ent );
            ent->setCastShadows( castShadows );
    };
    Entity* getEntity(){
            return ent;
    }; 
protected:
MeshPtr realMesh;
Entity *ent;
SceneNode *node;

};


// Calling all Actors. 
class Actor{
public:
       Actor(){
       }
       ~Actor(){
       }
       Actor( const char *name,const char *mesh,short acpu=1,InputReader *cInput=NULL){
              ent = gsmgr->createEntity( name,mesh );
              ent->setCastShadows( true );
              node=gsmgr->getRootSceneNode()->createChildSceneNode();
              node->attachObject( ent );           
              input = cInput;
              state=0;
              cpu=acpu;
              cAnim = NULL;
              aState=0;
      }
      SceneNode* getNode(){
           return node;
      }
           
         
      void playAnim( const char* animName,bool loop = false,float spd=0.01){
                 if( cAnim==NULL){
                 }else{
                  cAnim->setEnabled( false );
                 };
                 cAnim = ent->getAnimationState( animName );
                 cAnim->setLoop( loop );
                 cAnim->setEnabled( true );
                 aState=state;
                 aSpeed=spd;
       }
       
       void update(){
            
                                  
            switch( state){
            case 0:
              state=1;
             break;
            case 1:
                if(cAnim==NULL){
                    playAnim("Idle1",true,0.002);
                }else{
                //    if(!aState==1){
                          playAnim("Idle1",true,0.002); 
                
                }; 
              break;
              case 2:
                   //if( (!aState==2) ){
                         playAnim("Walk",true,0.02);
                   //};
              break;
             }     
              Vector3 dir;
              Degree xRot,yRot;   
            Matrix3 lAx;
            
            switch( cpu){
            case 1:
             
                dir.x=0;
                dir.y=0;
                dir.z=0;
                xRot = input->getMouseRelY();
                yRot = input->getMouseRelX();
                node->yaw( -yRot );
                state=1;
                if(input->isKeyDown(KC_W)==true){
                   dir.z=-7;
                   state=2;
                };
                if(input->isKeyDown(KC_S)){
                  dir.z=4;
                  state=2;
                };
                lAx = node->getLocalAxes();
                node->translate( lAx,dir);
                
                break;
            };
            updateAnim();
       };
       void updateAnim(){
              if(cAnim==NULL){
                return;
              }
                  cAnim->addTime( aSpeed );
       };
       void stopAnim(){
                  cAnim->setEnabled( false );
       };
protected:
 Entity *ent;
 SceneNode *node;
 InputReader *input;
 short cpu;
 short state;
 AnimationState *cAnim;
 short aState;
 float aSpeed;
};


int main()
{

      Ogre::Root* root = new Ogre::Root();

      if (!root->showConfigDialog())

            return -1;


        ConfigFile cf;
        cf.load("resources.cfg");

        // Go through all sections & settings in the file
        ConfigFile::SectionIterator seci = cf.getSectionIterator();

        String secName, typeName, archName;
        while (seci.hasMoreElements())
        {
            secName = seci.peekNextKey();
            ConfigFile::SettingsMultiMap *settings = seci.getNext();
            ConfigFile::SettingsMultiMap::iterator i;
            for (i = settings->begin(); i != settings->end(); ++i)
            {
                typeName = i->first;
                archName = i->second;
                ResourceGroupManager::getSingleton().addResourceLocation(
                    archName, typeName, secName);
            }
        }
 

      

      Ogre::RenderWindow* window = root->initialise(true);

 

      Ogre::SceneManager* smgr = root->getSceneManager(Ogre::ST_GENERIC);
      gsmgr = smgr;
 

      Ogre::InputReader* inputDevice = Ogre::PlatformManager::getSingleton().createInputReader();

      inputDevice->initialise(window);

      Camera *vCam =smgr->createCamera("vCam");
      vCam->setNearClipDistance(5);
      Viewport *view = window->addViewport(vCam);
      view->setBackgroundColour( ColourValue(0,0,0) );
      vCam->setAspectRatio( Real( view->getActualWidth()) / Real(view->getActualHeight()) );
      //
      vCam->setPosition( Vector3(0,20,200) );
      vCam->lookAt( Vector3( 0,0,0) );
      Plane plane( Vector3::UNIT_Y, 0 );
      MeshManager::getSingleton().createPlane("ground",
           ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
           1500,1500,20,20,true,1,5,5,Vector3::UNIT_Z);
      Entity *flr;
      
 //    TextureManager *texMan = root->getTextureManager();
   //  TexturePtr tex = texMan->load("BumpMetal.jpg","");
       smgr->setShadowTechnique( SHADOWTYPE_STENCIL_ADDITIVE );
     // flr = smgr->createEntity("Floor","ground");
     // smgr->getRootSceneNode()->createChildSceneNode()->attachObject(flr);
       ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
       Prop *lev = new Prop( "Floor","ground",false );
       flr = lev->getEntity();
       flr->setMaterialName("Examples/BumpMapping/MultiLight");
       smgr->setAmbientLight( ColourValue(0.1,0.1,0.1) );
       SceneManager *mSceneMgr = smgr;
       Light *light;
       light = mSceneMgr->createLight( "Light1" );
       light->setType( Light::LT_POINT );
       light->setPosition( Vector3(0, 150, 250) );
       light->setDiffuseColour( 1.0, 1.0, 1.0 );
       light->setSpecularColour( 1.0, 0.0, 0.0 );
       light = mSceneMgr->createLight( "Light3" );
       light->setType( Light::LT_DIRECTIONAL );
       light->setDiffuseColour( ColourValue( .25, .25, 0 ) );
       light->setSpecularColour( ColourValue( .25, .25, 0 ) );
       light->setDirection( Vector3( 0, -1, 1 ) );
         light = mSceneMgr->createLight( "Light2" );
       light->setType( Light::LT_SPOTLIGHT );
       light->setDiffuseColour( 0, 0, 1.0 );
       light->setSpecularColour( 0, 0, 1.0 );
       light->setDirection( -1, -1, 0 );
       light->setPosition( Vector3( 300, 300, 0 ) );
       light->setSpotlightRange( Degree(35), Degree(50) );
       mSceneMgr->setSkyBox( true, "Examples/SpaceSkyBox" );
      Actor *player =new Actor("Ninja","ninja.mesh",1,inputDevice);
      Degree camT;
      camT=1;
      Cam *viewer = new Cam;
      viewer->registerObjs(vCam,inputDevice);
      viewer->chaseNode( player->getNode() );
      
      while (1)

      {

            MSG msg;

            while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))

            {

                  TranslateMessage(&msg);

                  DispatchMessage(&msg);

            }
            
            

//Render Scene
            if (!root->_fireFrameStarted())
            break;
            root->_updateAllRenderTargets();
            if (!root->_fireFrameEnded())
            break;
//End Render
 
//Capture Device Input 
           inputDevice->capture();
//Update Viewer
           viewer->update();
           player->update();

//Escape Clause           
            if (inputDevice->isKeyDown(Ogre::KC_ESCAPE))
            break;

      }

 

            return 0;

};





C++ You when I get there.(Posted 2005-07-08)
Well, I've decided to do the actual game engine in Orge, but the front end will be a seperate .exe wrote in bmax.

I've been spending most of the last couple of days getting to know Ogre. A powerful and complex beast yet simple to use once you know what you're actually looking for.

I've just begun work on the Cam Class, which will allow me to track entities or offer free look.

Here's the bit of code as is. (Only just figured out why my resources wern't loading (Didn't initialise the resourceGroup Manager. Blitz3D this ain't.) so it's not much.)

I guess this means the worklog will continue, as it's still partially being wrote in bmax.

#include <iostream>
#include <string>
#include <windows.h>
#include "Ogre.h"
using namespace Ogre;
 


class Cam{
public:
      void registerObjs( Camera *in,InputReader *inputIn){
           aCam = in;
           input = inputIn;
      };
      void FreeLook(){
           state =1;
      }
      void update(){
           switch( state){
           case 1: //Free Look, yo.
                
           break;
           };             
      };
protected:
Camera *aCam;    
int state;
InputReader *input;
};

int main()

{

      Ogre::Root* root = new Ogre::Root();

      if (!root->showConfigDialog())

            return -1;

 


        ConfigFile cf;
        cf.load("resources.cfg");

        // Go through all sections & settings in the file
        ConfigFile::SectionIterator seci = cf.getSectionIterator();

        String secName, typeName, archName;
        while (seci.hasMoreElements())
        {
            secName = seci.peekNextKey();
            ConfigFile::SettingsMultiMap *settings = seci.getNext();
            ConfigFile::SettingsMultiMap::iterator i;
            for (i = settings->begin(); i != settings->end(); ++i)
            {
                typeName = i->first;
                archName = i->second;
                ResourceGroupManager::getSingleton().addResourceLocation(
                    archName, typeName, secName);
            }
        }
 

      

      Ogre::RenderWindow* window = root->initialise(true);

 

      Ogre::SceneManager* smgr = root->getSceneManager(Ogre::ST_GENERIC);

 

      Ogre::InputReader* inputDevice = Ogre::PlatformManager::getSingleton().createInputReader();

      inputDevice->initialise(window);

      Camera *vCam =smgr->createCamera("vCam");
      vCam->setNearClipDistance(5);
      Viewport *view = window->addViewport(vCam);
      view->setBackgroundColour( ColourValue(0,0,0) );
      vCam->setAspectRatio( Real( view->getActualWidth()) / Real(view->getActualHeight()) );
      //
      vCam->setPosition( Vector3(0,20,200) );
      vCam->lookAt( Vector3( 0,0,0) );
      Plane plane( Vector3::UNIT_Y, 0 );
      MeshManager::getSingleton().createPlane("ground",
           ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
           1500,1500,20,20,true,1,5,5,Vector3::UNIT_Z);
      Entity *flr;
 //    TextureManager *texMan = root->getTextureManager();
   //  TexturePtr tex = texMan->load("BumpMetal.jpg","");
          
      flr = smgr->createEntity("Floor","ground");
      smgr->getRootSceneNode()->createChildSceneNode()->attachObject(flr);
      ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

      flr->setMaterialName("Examples/Rockwall");
      smgr->setAmbientLight( ColourValue(230,230,230) );
      SceneManager *mSceneMgr = smgr;
      Light *light;
       light = mSceneMgr->createLight( "Light1" );
       light->setType( Light::LT_POINT );
       light->setPosition( Vector3(0, 150, 250) );
       light->setDiffuseColour( 1.0, 1.0, 1.0 );
       light->setSpecularColour( 1.0, 0.0, 0.0 );
       light = mSceneMgr->createLight( "Light3" );
       light->setType( Light::LT_DIRECTIONAL );
       light->setDiffuseColour( ColourValue( .25, .25, 0 ) );
       light->setSpecularColour( ColourValue( .25, .25, 0 ) );
       light->setDirection( Vector3( 0, -1, 1 ) );
         light = mSceneMgr->createLight( "Light2" );
       light->setType( Light::LT_SPOTLIGHT );
       light->setDiffuseColour( 0, 0, 1.0 );
       light->setSpecularColour( 0, 0, 1.0 );
       light->setDirection( -1, -1, 0 );
       light->setPosition( Vector3( 300, 300, 0 ) );
       light->setSpotlightRange( Degree(35), Degree(50) );
       mSceneMgr->setSkyBox( true, "Examples/SpaceSkyBox" );
         
      Degree camT;
      
      camT=1;
      
      Cam *viewer = new Cam;
      viewer->registerObjs(vCam,inputDevice);
      viewer->freeLook();
      
      while (1)

      {

            MSG msg;

            while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))

            {

                  TranslateMessage(&msg);

                  DispatchMessage(&msg);

            }
            
            

//Render Scene
            if (!root->_fireFrameStarted())
            break;
            root->_updateAllRenderTargets();
            if (!root->_fireFrameEnded())
            break;
//End Render
 
//Capture Device Input 
           inputDevice->capture();
//Update Viewer
           viwer->update();

//Escape Clause           
            if (inputDevice->isKeyDown(Ogre::KC_ESCAPE))
            break;

      }

 

            return 0;

};



Oh and yes, another pretenious/pointless/Z-Movie excerpt.

Meadow:
Where are my guns?

Chaining:
You don't need guns where your going.

Meadow:
Where?

Chaining:
The supermarket. We're out of buds, bud.

Meadow:
I might need a gun...

Chaining:
The war ended like, five years ago. You can let go.

Meadow:
They might try to overcharge me.

Chaining:
And a gun will prevent this?

Meadow:
A muscle bound guy pointing a gun in your face has the effect of quick submission.

Chaining:
You've got issues....



Swansong(Posted 2005-07-05)
Well, I've got Ogre up and running/compiling using DevC++ (I have vc, but..it's too much hassle.) so I think I'm all set on carrying out the game in that engine.

But rest assured, the sequel will be wrote in Bmax with Mark's 3d Engine. Ogre has nothing on that demo mark released :)

One last pretenious and totally fabricated excerpt for old time's sake.

Meadow:
You leaving?

Chaining:
The mission's over, Johnny. A place like this hasn't
got many uses for a guy like me.

Meadow:
You've run out of dope havn't you?

Chaining:
Yes.

Meadow:
There are problably some dealers around here you know?

Chaining:
I want home grown Johnny.

Meadow:
Godspeed, spliffster.

Chaining nods and turns towards the sun.
As he walks silently into the big blue sky, the ending theme to Incredible Hulk begins to play.

(You know the one, the piano..)



Great Future Kirk.(Posted 2005-07-02)
The way things are going, Vivid2.0 is likely to be released as open source software, pretty soon.

I just want to makes games, in all honesty. If I sell Vivid, it's not just fire and forget. I have to provide updates. Support. Write intensive docs. It's a whole show baby.
And not one I care to revisit.

As it stands the engine is still fairly early on in developement, so don't expect the first os release to be anything less than a foundation.
But it is a working foundation neverthe less.

Features of initial release to come shortly are.

*Material system With multi-texturing support/blend modes(Including dot3/dota3(I.e normal mapping) - Finished.
*Vertex And Pixel Shaders support (Assignable per material) - Working, but not complete.
*Entity system - 80% complete. Needs some maths related work done.
*Loader system - 3ds loader in and working. Including textures.
*Texture system - Complete.
*RenderClass System - Early in. Has VertexArray support. The code for VBO's/Native rendering is done, but not converted over from trinity. Should be fairly trivial however.

And a few other bits and pieces that tie it all together. Surfaces/etc.


The open source release will hopefully springboard into one of the best 3d engines availiable for bmax. I'll certainly it through to complition, and with a few people already intent on helping, things are looking good.

And for the last time, SAE does NOT mean Self addressed envelope. It means ShaderACentricEngine. Stop sending me stamps.



"I Was tweaking"(Posted 2005-06-28)
Pretenious Excerpt 1342.

Meadow:
Chaining...Got any munchies?

Chaining:
Yeah. But I ate them all...

Meadow:
That's really not fair.

Chaining:
I was tweaking...

Meadow:
Selfish <bleep>tard.

Chaining:
You want to go?

Meadow:
Let's go, Sarge...

Meadow pulls a pistol, as does chaining. Their guns locked on each other. Their hands tremble with fear and the rush of being so close to a fire fight.

Chaining:
You got balls for a private.

Meadow:
You got a pun to stop this bullet?

Chaining:
You're problem is you're living off the assumption
you can shoot me be..

Meadow fires.

Chaining:
Well that's really not fair...

Meadow:
I was tweaking...

(No one even reads these anyway...right? :) )



Pretty World(Posted 2005-06-28)
Got some test media from my asian..partners in the game. Wow. It's on a par with Squares 3d artwork, yet is low-poly at the same time. Amazing original texture work is a big key, and well, splinter cell 3 chaos theory is going to be in for a run for it's money :)


Except in the script department..

Pretenious Excerpt 245.

Meadow:
What's this?

Chaining:
Wash and go. Provn to wash your hair 85% more effectively than rival brands.

Meadow:
What does this have to do with my mission?

Chaining:
It doesn't. Viddo Sasson paid the developers a lot of money
to make me say that.

Meadow:
Developers?

Chaining:
We're not real.

Meadow:
...You high?

Chaining:
Of course.

Meadow:
pass THAT shit, right over here.

Chaining:
Toke...toke...toke..

*May not be in the final game.



Phoniex from the flames(Posted 2005-06-26)
or is it phoniex risin?
oh well..never mind.

the game's back on. the twiawanese(sp?) artists I'm working with are happy to help co-develope the engine/game. so expect vivid2.0 to shine like the sun and this game to look prettier than a crimson sunset at dusk.

Pretenious except 12:

Meadow:
I killed her.

Chaining:
You had no realistic choice but to follow orders.
You're a soldier, born and breed.

Meadow:
I never signed away my free will. I could have choose
to ignore my orders. I could have let her go..

Chaining:
And the reason you didn't is not because you're a monster,
it's because the pro in you knew she'd be back to haunt
you like a ghost one day.

Meadow:
Do you have that ammo I requested?

Chaining:
10 clips and a couple of frag 'nades.
You going hunting?

Meadow:
The moment that bastard caught her in his web
her life was over. He's going to pay, and I'm the one
who's going to make sure of that.

Chaining:
You need Rats?

Meadow:
He's all mine...



It's still good.(Posted 2005-06-25)
So finally solved most of my matrix problems and now the engine is bug free for the first time. EVER.

I'm using the same concept of Visulizers and Pipelines born in trinity, only major difference design wise is a change in usage/name.

Now, pipelines have been renamed to RenderClasses.


Surface.SetRenderClass( VertexArray.Create() )

Would set a surface to use vertex array.

This renderclass does all the nasty work of spooning the data from the surface into varray compatible format..and well, is simply totally self contained.

This will be true of all render classes.

And before the render class, comes Visulizers. They have become VisualPipes because they now have the ability to daisy chain each other for improved functionality.

Of course some visualpipes may work better without such daisy chaining.(For example a dynamic surface batch visualizer may not especially like having it's data ran through an occlusion based visualpipe.

But then again, it might...

The key word here is 'flexibility.'


Batch:VisualPipe = VisualBatch.Create()
VisualOC=VisualOccluder.Create()


Now we have two options.

One is to feed the visualoc with the output of the batch renderer.

Batch.Connect( VisualOccluder.Create() )

Or, and in this case more sensibly, we can connect the batch visualizer to the occluder visualizer.

VisualOC.Connect( Batch )

VisualOC.RenderScene() 'Will run all it's assigned entities through it's occluder routines, then will quickly pass this data to the batch visualizer which'll then render the visible(Or non visible, upto you) entities.


Now just imagine if you attached a octree visualpipe before both.



One day.(Posted 2005-06-23)
I'll finish an fps.

This is on hold while I do Vivid2.0. Mainly 'cos I had no luck finding an engine/language combo I was completely happy with.

I need to use my own <bleep>. Unless Mark wishes to send me a alpha of his 3d engine. (Hint.)

(NO <BLEEP>ING WAY. HINT! - Mark Sibly )



Square Pi(Posted 2005-06-22)
So far so good, I carved a fair chunk of Trinity code up in the first night and have it all up and running,(Albiet more much user-friendly and sensible than Trinity's overly complex nature)

The Entity/Surface/Tri/Vert system is entirely new however, this time build around my custom matrix code isntead of relying 3rd party quat stuff like Trinity.
This is already a 100% working parent/child(Or sub as I've named them cos it sounds cooler) relationships with the b3d philopshy of local/global rotations/turn etc, all working internally on a local/global matrix set up.

Next stage is implementing something similar to trinity's visulizer->pipeline setup, although with less confusing names, if not radically different in other respects. The pipeline code will be entirely new at least, got a little bloated in trinity's case. Something I'd like to avoid this time around.



Square One.(Posted 2005-06-21)
Nothing exciting so far, but just thought I'd fire a warning shot across the bowls of other 3d engines in these here murky waters.

No seriously, the only decision I've made so far is to be make the engine entirely shader-centric. It will be a next generation Shader Model2.0+ engine only.



Save me(Posted 2005-06-19)
I hate coding.

I hate everything.

But mostly I hate coding.


Pretenious except 5:

Kain:
Short ride...

Meadow:
The journey is irrevelent at this point.

Kain:
It's my last breath of freedom. Allow me to..savour it.

Meadow:
Well sniff on up there Kain, it's time to wave goodbye
to the sun. And hello fedral lo..

--A Tow missile cuts past them, destroying the waiting van.---

Meadow:
Mother of <bleep>!

Kain:
My people would rather break your laws then let me rot.
Wasn't you a aware of that?

Meadow:
Sickos attract the worst kind of nut cases. You think
this..

-A Pistol enters the window, pressed firmly against meadow's neck-

Kain:
Don't kill him. We'll save that for when I need a pick me up.

Meadow:
Son of a b..

-The hand pistol whips meadow-.



"She is the beat to my heart."(Posted 2005-06-17)
Switched back to blitz3d cos irrlict keeps crashing on this <bleep>ing pc. <bleep>!

Pretenious exerpt 4:

Meadow walks up slowly behind Jane, his hand trembles
as he grabs her from behind.(Non-sexually - worried script editor)

Jane:
Back so soon?

Meadow:
I never could stay away from for too long.

Jane:
Could have fooled me. I've seen more sunrises
than I've seen you come through that door.

Meadow:
The sun rises every day in japan, nobody's that
commited...

Jane:
You're holding me a little close for someone so
set on leaving...

Meadow:
I'm afraid to tell you why i'm here.

Jane:
You may as well, you know i'll get it out of you eventually..

Meadow:
You fell in with the wrong crowd sister,
and i've been sent here to correct you mistakes.
To erase you.

Jane:
You make it sound so sweet.
Make it quick...

Meadow:
I'll.. (Mid sentence he pulls the trigger. Camera pans away)

Chaining:(Radio)
You ok?

Meadow:
I'll let you know once i've washed her blood
off my skin..



Abstract Reality(Posted 2005-06-16)
'
'Actor Type/Class
'
Strict
Import gg.IrrBMAX

Global scene:T_irrISceneManager
Global mDriver:T_irrIVideoDriver

Type ActorBase

	Method New()
		
		scale =T_irrVector3df.create()
		scale.setX( 1 )
		scale.setY( 1 )
		scale.setZ( 1 )
		position = T_irrVector3df.create()
		position.setX( 0 )
		position.setY( 0 )
		position.setZ( 0 )
		rotation = T_irrVector3df.create()
		
	End Method
	
	Method SetScale( x!,y!,z! )
	
		scale.setX( x )
		scale.setY( y )
		scale.setz( z )
			
	End Method
		
	Method SetPosition( x!,y!,z! )
	
		position.setX( x )
		position.setY( y )
		position.setZ( z )
			
	End Method
	
	Method SetRotate( pitch!,yaw!,roll! )
	
		rotation.setX( pitch )
		rotation.setY( Yaw )
		rotation.SetZ( roll )
	
	End Method
	
		
	Field name:String
	Field position:T_IrrVector3df
	Field xi!,yi!,zi!
	Field scale:T_irrVector3df
	Field rotation:T_IrrVector3df
	
End Type

Type Camera Extends ActorBase


	Method New()
	
		LookAt = T_irrVector3df.createFromVals( 0,0,0 )
	
	End Method
	
	Function Create:Camera()
	
		Local out:Camera = New Camera
		out.node=scene.addCameraSceneNode( 0,T_irrVector3df.createFromVals(0,0,0),T_irrVector3df.createFromVals(0,0,0),0)
		out.node.setFarValue( 15000 )
		out.node.setNearValue( 0.1 )
		out.node.setFov( 60 )
		Return out
								
	End Function
	
		
	Method SetPosition( x!,y!,z! )
	
		super.setPosition( x,y,z )
		node.setPosition( position )
	
	End Method
	
	Method SetRotate( pitch!,yaw!,roll! )
		
		super.SetRotate( pitch,yaw,roll )
		node.setRotation( rotation )
		
	End Method

	Method Look( x!,y!,z! )
		
		LookAt.setX( x )
		lookAt.setY( y )
		lookat.setz( z )
		node.setTarget( lookAt )
		node.setupvector( T_irrVector3df.createfromVals(0,-1,0) )
			
	End Method
	
	Field Node:T_irrICameraSceneNode
	Field LookAt:T_irrVector3df
	
End Type

Type Light Extends ActorBase

	Function Create:Light( red!,green!,blue!,range!=200)
			
		Local out:Light = New Light
		out.node=scene.addLightSceneNode(0, T_irrVector3df.createFromVals(0,0,0),T_irrSColorf.createFromRGBA(red/255,green/255,blue/255,1.0),range)
		Return out
			
	End Function
	
	
	Field Node:T_IrrILightSceneNode
	
		
	Method SetPosition( x!,y!,z! )
	
		super.setPosition( x,y,z )
		node.setPosition( position )
	
	End Method
	
	Method SetRotate( pitch!,yaw!,roll! )
		
		super.SetRotate( pitch,yaw,roll )
		node.setRotation( rotation )
		
	End Method
			
End Type

Type Bot Extends ActorBase

	Field node:T_irrIAnimatedMeshSceneNode
	Field mesh:T_irrIAnimatedMesh
	Field material:T_irrSMaterial

	Function LoadBot:Bot( File:String )
	
		Local out:Bot = New Bot
		out.load( "Actor\"+file+"\"+file+".x" )
		Local texture:String = "Actor\"+file+"\"+file+".jpg"
		out.material:T_irrSMaterial=T_irrSMaterial.create()
		out.material.setTexture1( mDriver.getTexture( texture ) )
		out.material.setLighting( True )
		out.node.setMaterial( 0,out.material )
				
		Return out
			
	End Function
	
	Method SetPosition( x!,y!,z! )
	
		super.setPosition( x,y,z )
		node.setPosition( position )
	
	End Method
	
	Method SetScale( x!,y!,z! )
	
		super.SetScale( x,y,z )
		node.setScale( scale ) 
		
	End Method
		
	Method SetRotate( pitch!,yaw!,roll! )
		
		super.SetRotate( pitch,yaw,roll )
		node.setRotation( rotation )
		
	End Method
		
	Method Load(file:String)
		
		mesh = scene.getMesh( file )
		If mesh = Null Throw "Unable to load Mesh "+File
		node = scene.addAnimatedMeshSceneNode( mesh )
		If node = Null Throw "Unable to add "+File+" Mesh to Scene"
				
	End Method
	
End Type

Function PassGlobals( sceneM:T_irrISceneManager,driveM:T_irrIVideoDriver )

	scene = sceneM
	If scene = Null Throw "Failed to establish a valid scene manager"
	mDriver =driveM
	If mDriver = Null Throw "Failed to establish a valid video driver"

End Function





So I was down in the valley shoveling some <bleep>(Posted 2005-06-15)
And I picked irrclit.(One of these days I'll get the spelling right too. Not today.)
It's not as feature-rich as I would have hoped, but it is stable and proving to be easy to use.
And most importantly of all right now I guess it let me uses bmax. Which is a big +.


Pretenious excerpt #3.
---

Meadow:
Driver, you heard the man.

Cut to outside HumVee. It steers towards a back alley, some 1 km from their
target point, and comes to a sharp halt.

Meadow:
Looks like the party is starting early. Saddle up./

The radio comes to life.

Chaining:
Hold up Meadow. We've got word there's a unit out there looking to send your sorry butt back home in a box.

Meadow:
Really? My own personal welcoming commitiy?

Chaining:
They don't look very welcoming. Something tells me
you don't want to find that out the hard way.

Meadow:
Look, as far as I can see my mission is still to whack the bad guys before they whack me. Right?

Chaining:
Correct.

Meadow:
then what does it matter what their agenda is?
Let me at 'em sarge.

Chaining:
<Insert Loose Cannon reference>



Engine Woes(Posted 2005-06-15)
Picking an engine is proving to be a real nightmare.
I've changed from DevC to VC to bloodymax in the space of a cup of tea. Which is peculiar because I do NOT drink tea.

Anyway, our online forums with obviously cool template have been set up, now we're starting the actual process of building this wonderous thing.

Pretension Excerpt #2.
-
Concept Reality

Episode 1 - Behind Enemey Minds.
----

FADE IN.

Concept Squad are stood eating chow by their humvee. The desert dusk obscures the horizon
as the camera faces the sun behind them.

The radio buzzs. (All names subject to change)

Sergent Meadow:
Go.

Major Chaining(Across a sea of static):
Incoming intel on your mission Meadow.
It appears Stanley has been taken to a urban lock up
just outside of the city mall.

Meadow(To his squad)
Lock and load boys, we're going shopping.

Major Chaning:
Try to minimize collateral damage. We may be working under
the cloak of covert ops, but we still have a ethical duty to uphold.

Meadow:
We'll be in and out before they even know what hit them.

Camera pans towards Hum Vee as Concept Squad board her.

<Player Ineraction Starts.> Role of Private Donahue.

Goal 1->Board HumVee.

If player Travels Too far.

Meadow:
Private, you're letting that uniform down.
-
Upon Compilation.

Into humVee. POV of Private Donahue.

Meadow:
Alright Squad. This is the moment we've been training for.
Stay tight and watch out for each other's backs out there.

Meadow:
This is an urban op. You have to stay alert. The enemy
can be anywhere and he will be everywhere. Remember
that if you want to stay alive long enough to start missing
long tall sally.

Wilkerson:
Shit, If I had a long tall sally you think i'd be out here risking my sorry butt?

Meadow:
I can respect that to you a relationship with a woman would nullify the need
for an actual war. Most of us however are more well adjusted human beings
who happen to get on with people better than they do a loaded gun.

Wilerson:
I resent that. It's true, But I still resent it.

Chaining:
Meadow. Private Donahue is freash blood, but he comes from a milltary
family.

Meadow:
Good stock huh?

Chaining:
In a way, yes. He's a good kid, make sure he gets back in one piece.

Meadow:
If he's half as good as you seem to think he his, he'll be the one saving my slow ass
out there.

Chaining:
Very well Sergent. God speed.

---- Machine Gun Chatter ---

The HumVee comes under attack.

Private Isack:
It's raining bullets out there. We need to find some cover.

Meadow:
Driver, you heard the man.

Cut to outside HumVee. It steers towards a back alley, some 1 km from their
target point, and comes to a sharp halt.

Meadow:
Looks like the party is starting early. Saddle up./



AAA Team for an AAA Game.(Posted 2005-06-13)
Been assembling the team for concept reality and it really is turning into a world wide affair. Several artists from places as exotic as the arab emirities to the spritual shores of taiwan. (They give the square guys a run for their money!)

The game is a tactical fps, episodic in nature. I like to think of it as a game series, like 24 is a tv series.

Episode 1 will go on sale in three months if all goes to plan. (So make that six months just to be safe :) )

And of course, this wouldn't be an antony wells worklog without a pretension except from the game's early script, now...would it? Of course not!

-Fade in.

A lone gunman sits atop the empire state building, the wind blows his hair like candy floss against the overcast sky.

DarkMan:I've got a fix on the target. I suggest we take him out before the sun comes up.

Sergent ?:Fine in theory, might not be so clean in execution. He has bodyguards flanking his every move. Most of which will be carrying bullet tracers. This won't be no clean get away.

Darkman:I've got enough bullets for everyone.

Sergent:Remember we're the good guys Jake.

DarkMan:If you say so. If you'll be so kind as to remove my lesh, I'll go get me some chow.

Sergent:You taking orders all of a sudden?

Darkman:Just thinking ahead to the court martial.

Candy:Worry about getting back to me.

Darkman:You better not get all Rose on me. I hated that game for that.

Candy:Don't worry, i'm far too sexy for that to ever be an issue.

DarkMan:...Agreed.



Phase 1(Posted 2005-06-08)
I've begun to write an abstraction layer to make Irrichilt much easier to use, and more b3d like.

it'll be freeware most likely.

here's the initial bit of code, nothing at all amazing so far, but hopefully makes it clear where it's heading.

'
'Irrlicht-Abstraction-Layer
'
'(c)Antony Wells
'--
'IAL V0.1
'
Strict

Import gg.IrrBMAX

Const I_DX =EDT_DIRECTX9,I_GL=EDT_OPENGL

Type Engine

	Method New()
		stencils=True
		vSync=False
		fullScreen=True
	End Method

	Method display(width,height,depth,driver=I_DX)
		device = T_irrIrrlichtDevice.create(driver,T_irrDimension2d_s32.create(width,height),depth,fullScreen,stencils,vsync,0)
	End Method
	Method vSyncOn()
		vsync=True
	End Method
	Method vSyncOff()
		vSync=False
	End Method
	Method StencilOn()
		stencils=True
	End Method
	Method StencilOff()
		stencils=False
	End Method
	Method fullScreenOn()
		fullScreen=True
	End Method
	Method fullScreenOff()
		fullScreen=False
	End Method
	
	Field device:T_irrIrrlichtDevice
	Field vsync,stencils,fullscreen
			
End Type





The usual suspects(Posted 2005-02-07)
Added s3tc texture compression (Works on any image source, files do NOT need to be compressed before hand.)

You can practically(i.e according to official gl specs..different cards.who knows.) obtain 6x the amount of texture space as you can with uncompressed textures.

Blitz3d uses uncompressed, if you're wondering.



Visualizer(Posted 2005-01-31)
Trinity now has the concept of visualizers.
Similar to pipelines, visualizers, instead of taking raw direct data, Visualizers take entitiies and surfaces.
The Visualizers job being that of presenting it to the pipelines in a optimized manner.

I.e atm I have a Batch visualizer.

(Type TBatch Extends Visualizer
again a templated design so any you create plug into the exiting engine.

This visualizer, again like templates have several common functions that form the universeal interface.
With the prime one being .Render(), which invokes the visualizers renderer.

But obviously, the visualizer doesn't actually render anything..the surfaces are rendered using whichever pipeline they are asscoiated with.

The result is a very simply to grasp yet very flexible overall engine pipeline.

Entity -> Visualizer -> Pipeline.

So if I decide to do a BSP visualizer for example, I can do so by filling in the middle block..with an extended visualizer class.. TBSP perhaps. No need to write a bsp reader, or to write a new renderer, just have to write the parts that manage the bsp and invoke the renderer.

You can add as many entities/surfaces as you like to a visualizer, and you can have as many active visualiers(Of varying or identical) classes in the scene at once.

Also added vertex arrays, collisions(Per poly, ray to tri etc)...



Balls to the future.(Sssh.)(Posted 2005-01-17)
Heh it's really remarkable how quick trinity has come along.
bar a few features here and there, and it has already eclipsed Vivid in my opinon.

Our game is now playable..the engine is continued to be wrote along side it atm until a certain state in very near future, then the game will be the primary focus for a while.

I'll be releasing the public alpha once this happens(Of the engine only, the game is 50/50 so not my decision to make alone. (In other words, maybe an alpha will be released..who knows ;) )...Few restrictions placed on it..but nothing too inhibiting I hope.



CacheLocale(Posted 2005-01-16)
Added per entity self-caching runs.

Basically, no matter how complex your scene is, it'll only require the cpu hit of each top tier entity.(I.e the upmost. The darth vadar to the luke skywalkers if you like)
by caching everything post tform(Including sub-pipelines which can still be unique) on the gpu.

Also added a ton of other stuff, specular mapping and what not not.automatic camera maps..

We have our game up and running now, fully 3d via the b3d format.

May post a few shots soon..or release the public alpha..i'm lazy someti



Houstan, we had a problem..but not anymore.(Posted 2005-01-13)
Probably too early to be certain of features but one of the areas trinity will include revolutionary(In precise terms, not pr bull...heap.) feedback/user assistence.


Basically, stuck on a line of code? Copy/paste into your trinity Assistant application(Not module) and it'll be filtered into an online base of problems.

Immediately, anyone else coding with trinity(And with the trinity assistant app running, which is of course optional)
will get a notifier, someone has a problem.

You may respond with assistence, if the user deems this assistance as 'useful', you'll get points.

Where the Magic comes in, is this app also has a 3d context(Trinity powered), and while you are 'demonstrating' the problem to someone helping you, you may copy/paste trinity code into the window, and watch it run.

If it requires files, it'll stream them to the person/persons assisting.

This won't be really useful for trapping blitzmax bugs, obviously, but for 3d...you better believe it'll be useful.

Next step? Natural language processing :) (But I'm afraid that may be a step too far...even for my dillusions of grandour.)



Pipe mania.(Posted 2005-01-13)
All code (c)Antony Wells 2005.

Pipelines are..wonderful.

The game ad and I are doing wasn't well suited for vbos, as a bigger market is obviosly the 'big' concern for an indie developer/game,
so after much ado about nothing(I hate the phrase, but I love saying it.) I decided to do a display list pipeline.

Here's the code, and what makes writing pipelines so easy is the lego brick nature of it. You can safely *not* overide any pipeline functions, simply overiding the ones you need to. in this case sync and render. I could have implemented additonal bind/unbind methods which would have been called when required.(Automatically. You *never* have to access a pipeline directly.)

Here's the code,

Type TStaticBuffer Extends TPipeline
		Method Delete()
		
			If glIsList( dList )
				glDeleteLists dList,1
			End If
		
		End Method
		
		Method RequestNew:TPipeline()
		
			Return TPipeline( New TStaticBuffer )
			
		End Method
		
		Method Sync()
		
			If dList=0 Or glIsList( dList )=0
				dList =glGenLists(1)
			Else
				glDeleteLists dList,1
				dList =glGenLists(1)
				
			EndIf
			?debug
			If Dlist =0 throw "Could not create static buffer"
			main_error.AssertGL("StaticBuffer Sync")
			?
			Local cMat:Tmaterial
			Local VertI:Int,TriI:Int,ColI:Int
			Local TexC:Byte,TexI:Byte
			Local CoordSet:Byte
		
			glNewList dList,GL_COMPILE_AND_EXECUTE
			
			For cMat = EachIn MatList
			
				cMat.Bind()
				glBegin(GL_TRIANGLES)
				For TriI = 0 Until Tris.Length
					VertI = Tris[ TriI]*3
					ColI = Tris[TriI]*4
					glNormal3d Norms[ VertI],Norms[ VertI+1],Norms[ VertI+2]
			'		glColor3d Colors[ ColI],Colors[ ColI+1],Colors[ ColI+2]
					TexC = TTexture.BoundTextures			
					For TexI=0 To 0
						CoordSet = TTexture.BoundSet[ TexI ]
						glMultiTexCoord3d TexI,Coords[ CoordSet].U( VertI/3),Coords[ CoordSet].V( VertI/3),Coords[ CoordSet].W( VertI/3)
					Next
					
					glVertex3d Verts[ VertI],Verts[ VertI+1],Verts[ VertI+2]
				
				Next
				glEnd()
			Next
		
			TTexture.UnbindAll()
			glEndList()
		End Method
				
		Method Render() 
			If dList
				glCallList dList
			End If
		End Method
		
		Field dList:Int
End Type


Now all I have to is,

MyEntity.UsePipeline(New TStaticBuffer)

and viola, one display list hardware accelerated entity.

For an example of how complex it can get, is some slightly older vbo pipeline code, which is roughly 95% finished.

Type TVertexBuffers Extends TPipeline


	Field VertexBuffer:Int 
	Method Delete()
'		MemFree TriMem
	'	
		'MemFree VertMem
	'	MemFree ColMem
	'	MemFree NormMem
	End Method
	
	Method RequestNew:TPipeline()
		Local Temp:TPipeline = New TVertexBuffers
		Return temp
	End Method
	
	Method CheckSupport:Byte()
	Return True
		If SupportLut=-1
			SupportLut = TEngine.GLSupports( "GL_ARB_vertex_buffer_object" )
	    End If
	    Return SupportLut
	End Method
	

	
	Method PassData(Vert:Double[], Tri:Int[] , Norm:Double[] , Color:Double[] , Coord:TCoords[],Materials:TList) 
		?debug
		Assert CheckSupport(),"Attempt to pass data to an unsupported pipeline. Call ignored."
		?
		Super.PassData(Vert,Tri,Norm,Color,Coord,Materials)
		Self.Sync()
		Self.Setup()
	End Method
	
	Field CoordMem:Byte Ptr[255]
	Field VertMem:Byte Ptr
	Field NormMem:Byte Ptr
	Field ColMem:Byte Ptr
	Field TriMem:Byte Ptr
	
	Method Sync()
	
		Local Why:String
		Try
			VertMem = DoubleToMem( Verts )
			NormMem = DoubleToMem( Norms )
			ColMem = DoubleToMem( Colors )
			For Local Set:Short =0 Until Coords.Length
				CoordMem[Set] = DoubleToMem( Coords[Set].Coords )
			Next
			TriMem = IntToMem( Tris )
		Catch Why:String
			Main_Error.Invoke "Pipeline memory stall/exception.",True
		End Try
	End Method
	
	Method BindTris()
	
		glBindBufferARB GL_ELEMENT_ARRAY_BUFFER,TriBuffer
		
	End Method
	
	Method BindVertices()
		glBindBufferARB GL_ARRAY_BUFFER_ARB,VertexBuffer
	End Method
	
	Method BindNormals()
		glBindBufferARB GL_ARRAY_BUFFER_ARB,NormalBuffer
	End Method
	
	Method BindColors()
			glBindBufferARB GL_ARRAY_BUFFER_ARB,ColorBuffer
	End Method
	
	Method BindCoords(Index:Byte)
		glBindBufferARB GL_ARRAY_BUFFER_ARB,CoordBuffer[ Index ]
	End Method
	
	Method SetUp()
		?debug
		Assert CheckSupport(),"Attempt to set up an unsupported pipeline.(Vertex buffer objects)"
		?
		glGenBuffersARB 1,Varptr VertexBuffer
		glGenBuffersARB Coords.Length,CoordBuffer
		glGenBuffersARB 1,Varptr NormalBuffer
		glGenBuffersARB 1,Varptr ColorBuffer
		glGenBuffersARB 1,Varptr TriBuffer
		?debug
		main_error.invoke "Vert:"+VertexBuffer+" Normal:"+NormalBuffer+" Tri:"+Tribuffer
		?
		Assert VertexBuffer
		Assert Coordbuffer
		Assert NormalBuffer
		Assert ColorBuffer
		Assert TriBuffer
		
		?debug
		Main_Error.AssertGL("Pipeline creation failure(VBO)")
		?
		BindTris()
		UpdateTris()
		BindVertices()
		UpdateVerts()
		BindNormals()
		UpdateNormals()
		BindColors()
		UpdateColors()
		For Local J=0 To Coords.Length-1
			BindCoords( j )
			UpdateCoords( j )
		Next
		?debug
		Main_Error.AssertGL("Vertex Buffer Pipeline setup.")
		?
		'Self.ValidateBuffers()
	'	Unbind()
	End Method
	Method ValidateBuffers()
		If glIsBufferARB( VertexBuffer) =0 Or glIsBufferARB( TriBuffer)=0 Or glIsBufferARB( NormalBuffer)=0 Or glIsBufferARB( ColorBuffer)=0  
			RuntimeError "Non valid buffers"
		EndIf
	
	End Method
	Method Bind()
		?debug
		Assert CheckSupport(),"Attempt to bind an unsupported pipeline.(Vertex Buffer objects)"
		?	
		BindVertices()
		glVertexPointer 3,GL_DOUBLE,50,Int Ptr 0
	
	End Method
	
	Method Unbind()

		glBindBufferARB GL_ELEMENT_ARRAY_BUFFER_ARB,0
		glBindBufferARB GL_ARRAY_BUFFER_ARB,0
		TTexture.UnbindAll()
		
	End Method
	
	Field LastInt:Int[255]
	Method getI( Real:Int )
			glGetIntegerv Real,LastInt
	End Method
	
	Method Render()
		Return
		main_error.invoke "Entry.",0
		If Sizeof( Tris ) <20 Return 	
		Local CMat:TMaterial
		Local MI:Byte=0
		
		For CMat = EachIn MatList
			TTexture.UnbindAll()
			CMat.Bind()
			MI:+1
			If Mi=2
				glEnable(GL_BLEND)
				glBlendFunc GL_ONE,GL_ONE
			EndIf
			?debug
			Main_Error.AssertGL("Point of no return in rendering context")
			?
			Local Why:String
			Local NullPoint:Byte Ptr
			Try
			main_error.invoke "Tris:"+Sizeof( Tris )+" Len:"+Tris.Length+" Vert len:"+Verts.Length+" Verts:"+Sizeof( Verts)+" Norms:"+Sizeof( Norms),0
			glDrawElements GL_TRIANGLES,Tris.Length,GL_UNSIGNED_INT,Null
		Catch Why:String
			Main_Error.Invoke Why,True
		End Try
			?debug
			Main_Error.AssertGL("glDrawElements")
			?
		Next
		?debug
		Main_Error.AssertGL("RenderTris in VertexBuffer Pipeline.")
		?
	End Method
	
	Method RenderStrip()
		
		glDrawElements GL_TRIANGLE_STRIP,Tris.Length,GL_UNSIGNED_INT,Byte Ptr(0)
		
	End Method
	
	Method RenderQuads()
	
		glDrawElements GL_QUADS,Tris.Length,GL_UNSIGNED_INT,Byte Ptr(0)
	
	End Method
	
	Method UpdateVerts() 
		glBufferDataARB GL_ARRAY_BUFFER_ARB,Sizeof( Verts),VertMem,GL_DYNAMIC_DRAW
		?debug
		Main_Error.AssertGL("UpdateVerts")
		?
	End Method
	
	
	Method UpdateTris() 
		glBufferDataARB GL_ELEMENT_ARRAY_BUFFER_ARB,Sizeof( Tris ),TriMem,GL_STATIC_DRAW
				
		?debug
		Main_Error.AssertGL("Update Tris (Vbo pipeline)")
		?
	End Method
	
	
	Method UpdateNormals() 
	'	glBufferDataARB GL_ELEMENT_ARRAY_BUFFER_ARB,Sizeof( Norms ),NormMem,GL_STATIC_DRAW
		?debug
		Main_Error.AssertGL("Update Normals (Vbo Pipeline)")
		?
	End Method
	
	Method UpdateCoords(Index:Byte)
		'glBufferDataARB GL_ARRAY_BUFFER_ARB,Sizeof( Coords[Index].Coords ),CoordMem[Index],GL_STATIC_DRAW
		?debug
		Main_error.AssertGL("Update Coords (Vbo Pipeline)")
		?			
	End Method
	
	Method UpdateColors() 
		'glBufferDataARB GL_ARRAY_BUFFER_ARB,Sizeof( Colors ),ColMem,GL_DYNAMIC_DRAW
		?debug
		main_error.AssertGL("Update Colors (VBO Pipeline)")	
		?
	
	End Method
	
	Field TriBuffer:Int,NormalBuffer:Int
	Field SupportLut:Byte
	Field ColorBuffer:Int
	Field CoordBuffer:Int[32],CoordSets:Byte

End Type


-

The really neat thing is you can also assign pipelines to individual surfaces. In fact, the above entity.usePipeline function did just that. it created new pipelines for each surface(hence the requestNew() abstract method)

And this is just the most basic basic advantages of the approach.



Hal you doing?(Posted 2005-01-11)
Trinity, much like vivid was intended to be before it was silenced by the men in black(Two-pronged) will be more than 'just' a 3d/2d rendering engine.
Although that is of course are the primary focus, Several aspects(Or more accurately, modules) of the trinity package have nothing at all to do with rendering.

The first tba, righ now(tada.) is AI.
Not AI as in Game ai, but AI as in a generalized abstract ANN(Artifical Neural Network) powered workers.

There are two approaches planned, one in the works,

First is a ANN class, that in very simple terms allow you to create, feed and train ann's, for use in ANY situration.
This can be self-supervised either by using template 'goals' (I.e when input A results in Output b correlating to pointer A..sounds..extreme..in reality is ANN.GoalValue( Target,Goal )) or by providing a function pointer to your own goal assertion.

What training involves is basically 'rewarding' or 'punishing' the network based on it's action. This is how a network 'learns', and this black box nature is what makes them so adaptable.
If I said you could use them to create the best compression algo in existence, I wouldn't be lying.(Google it.)

The second method of usage will be more refined, firstly you assign inputs based on the knowledge there may be multiple ANN's spawned based on this data. This is passed through a series of internal Kohonen networks(Data classifiers)
which themselfs are supervised by a training module(Which is powered by the first less refined direct approach)
this is then passed through the internal network, finally out into the outputs you define.



The pluging.(Posted 2005-01-09)
Trinity has a new concept of objectized/script assisted renderering plugins.

Basically, They are objects that share a common extended pipeline interface these take raw mesh and material links,
and also a common(Abstracted) interface for rendering.

So the engine it's self is blissfully unaware of what code will be rendering the internal data..

With this for example, I have VBO pipeline for doubles. Then I thought, "Hey, why not offer a floating point pipeline for faster rendering in small scale environments?" Then I did it in about five minutes. No need to rewrite any of my previous code. The pipelines operates in three stages. Entry(Raw data is passed, plugin can either copy direct links to this, or in the case of the vbo, create it's own version of it needed for valid usage in the pipeline), rendering and finally exit(Which cleans up any resources used by the pipeline), the surface system handles these calls. You just have to write them.
So can any of you, it's simple to write a plugin renderer without needing to alter the main code.

The point of it all is improve performance and offer massive increases in flexibility.
Why? Because unlike any other system of it's kind, instead of using a single pipeline that spawns data, the data it's self spawn pipelines.
Meaning each surface in trinity can be using or sharing a unique pipeline.

So say you a scene in your game with 'balls of fire' spewing fourth? Write a fire pipeline, and use that for anything that's on fire. Result? More flexibility, modulized rendering(No need to recode fx for new games) and hopefully a community of user-wrote renderers that will keep Trinity one step ahead of the compeition.



Roadmap to trinity.(Posted 2005-01-06)
The first public alpha will be released very shortly,

Some of it's Features are,

Full Entity system, parent/child relationships etc.

Material based automated multi-pass renderer. You can chain materials together and trinity uses multi-pass rendering to combine them seemlessly.
Each material can have upto 32 textures.

Lights/Normal generation.

3D / 2D Maths.(Including 2d/3d vectors, matrices and b3d style tformPoint/Entity commands, as well as whole new ones)

Custom collision library. Per-poly, proxy mesh based.

Support for .3DS/.Ase(Basic) and .B3d(100% support) file formats.

Integrated error management system, with automated response/safe guards. You can ignore errors, fail, set fail counts,
and you can pass a pointer to a print function to redirect
it's output to whichever output you desire. Defaults to ide output window.

GLSL Materials. Extensions of normal materials, they share all the same functionality, except they use glsl shader files to achieve their look. Multi-pass still works, to allow you to chain together multiple shader materials effortless.

Streaming meshes ala gta3.(Windows version only.)

And more. This version obviously is still a work in progress, but it's more a case of not finished, than buggy.. there are no known bugs as of this time.
-
Will be released for Windows/Linux first, mac two weeks later. (Revenge of the shinobi.)



Alpha Effect.(Posted 2005-01-01)
Trinity Alpha testing(Pre-beta) begins shortly, if you are interested in testing the spiritual successor to VividGL For BlitMax *only*, drop your details to AlphaTest@...

The engine does not rely on any 3rd party .dlls/.libs and should run on Windows/Linux/Mac Commercial/Beta or demo versions, installation is simply a matter of copying dsi.mod into your mod folder.

Includes /.3ds/.ase loaders so far, will most likely include b3d by the time you get the alpha.



Plugin baby.(Posted 2004-12-24)
Trinity is built about a plugin based design.

You can easily add your own modules, and your own plugins covering file input/output(Via ambigious loader objects(That also handle saving, for unified drivers))

Here's a small example of a 3ds loader that's currently being wrote.

The two lines of code at the bottom are all it takes to register the loader, at which points any OLD code will use it as well as new.

The 2d/3d engines take a similar approach, meaning trinity could easily offer alternative pipelines wrote by it's userbase, that are as integral and usable as any core modules. (God bless BlitzMax.)

Strict

Module DSI.Loader3DS

ModuleInfo "Version: 1.00"
ModuleInfo "Author:Antony Wells"
ModuleInfo "License:Dreamspace Developer's License"
ModuleInfo "Copyright: Dreamspace Entertainment."
ModuleInfo "Modserver: DSI" 

Import DSI.Entity
Import BRL.Stream
Import BRL.LinkedList
Import DSI.Loader
Import DSI.Constant
 


Type TLoader3DS Extends TLoader
	
	Method New()
	
		SetAuthor( "Antony Wells" )
		SetCopyright( "Antony Wells" )	
		SetVersion( "V1.0" )
		SetExt( "3ds" )
	
	End Method
	
	Method ParseStream ( ) Final
					
		If Not Self.FindChunk( ObjectBlock)
		
			Throw "Could not find 3DS Object chunk"
		
		EndIf
		
		Root:TEntity = New TEntity
		Root.Name = Self.ReadStr()
		Throw "Entity Name>"+Root.Name
				
	End Method
	
	Method ReadStr:String()
		
		If LastID =0 Or LastLen = 0
	
			Throw "No Data to read in 3DS"
	
		End If
		
		Return ReadString( Stream,LastLen ) 
				
	End Method
	
	Method Load:TEntity( File:String ) Final
			
		Stream = OpenStream( File,True,False )
		If Stream=Null Throw "Unable to read file File:"+File
		Self.ParseStream()
		
	End Method

	Method Reset()
	End Method
	
	Method Save:TEntity( File:String ) Final

	End Method
	
	Method EndStream:Int()
		
		If Stream = Null Throw "No Stream in TLoader3DS.EndStream"
		Return Eof( Stream )
	
	End Method
	
	Method FindChunk:Int( ID:Int ,WrapStream:Int = False,ZeroStream:Int=False)
		
		Local WrapPoint:Int = StreamPos( Stream )
		Local EndPoint:Int = StreamSize( Stream ) 
		
		If ZeroStream
			SeekStream Stream,0
			WrapPoint = 0
		End if
		
		repeat
	
			While Not StreamPos( Stream ) > EndPoint
			
				Self.ReadChunk()
				If LastID = ID Return True
				Self.SkipChunk()
									
			Wend
	
			If WrapStream 
				
				SeekStream Stream,0
				EndPoint = WrapPoint
				WrapStream = False 
				
			End If
			
			Return False
			
		Forever
			
	End Method
		
	Method ValidateChunk()

		Select LastID
			Case MainChunk
				
			Case EDitorChunk
			Case ObjectBlock
			Case VerticesList
			Case FacesDescription
			Case MAPPINGCOORDINATESLIST
			Case SmoothingGroupList
			Case CoordinatesSystem
			Case Light
			Case SpotLight
			Case Camera
			Case MaterialBlock
			Case MaterialName
			Case AmbientColor
			Case DiffuseColor
			Case SpecularColor
			Case TextureMap1
			Case BumpMap
			Case ReflectionMap
			Case MappingFileName
			Case MappingParameters
			Case KeyframerChunk
			Case MeshInformationBlock
			Case SpotlightInformationBlock
			Case Framepoint
			Case Objectname
			Case ObjectPivotPoint
			Case PositionTrack
			Case ScaleTrack
			Case HierarchyPosition
			Default
				Throw "Unknown Chunk Id, unable to load ID:"+LastId+" Reported Length:"+LastLen
		End Select
	
	End Method
		
	Method ParseChunk()
	
		Self.SkipChunk()
	
	End Method
	
	Method ReadChunk:Int()
		
		
		If Stream = Null Throw "No Stream in TLoader3DS.ReadChunk()"

		LastID = ReadShort( Stream )
	
		LastLen = Readint( Stream ) 
	
		Self.ValidateChunk()
	
	End Method
	
	Method SkipChunk()
		
		If LastLen=0 Throw "Cannot skip null chunk LastId:"+LastId
		If Stream = Null Throw "No Stream in TLoader3DS.SkipChunk"
		
		SeekStream ( Stream, StreamPos( Stream )+LastLen )
	
	End Method
				
	Field LastID:Int,LastLen:Int

	Field Root:TEntity
	
End Type

Global Loader_3DS:TLoader = New TLoader3DS
TFileIO.RegisterLoader( Loader_3DS )





Just the codes, mam.(Posted 2004-12-22)
Strict

Rem

	Trinity64 Engine.
	
	(c)Antony Wells 2005.
	
	Hello World! 
	
	2D Example.
	
End Rem 
Import Pub.OpenGL
Import Dsi.Error

'Create our main engine.
Local Main:TEngine = New TEngine 'Engine Entry Point.

'Create a full screen window.
Main.FindMode(640,480,32,T_fullscreen)

'Setup the gpu for 2d Drawing.
Main.Draw2D()

'Create a 2D Hardwre pen.
Local Pen:TDrawGL = New TDrawGL

Main_Error.Stamp()
Pen.Color( 255,0,0,1 )
Pen.Blend( T_None )
Main_Error.FailOn(30)

Local VCam:TCamera = New TCamera
Cam.Bind()

Local Cube:TEntity = TPrefab.Cube( 5 ) 

Plastic:TMaterial = New TMaterial

Cube.Material( Plastic ) 



Repeat
	
	Main.Cls( T_Color | T_Z )
	Main.Update()
	
	Cam.RenderEntity( Cube ) 
	
	bglDrawText Main.Fps(),1,1
	Main.Flip()

Until KeyDown( KEY_ESCAPE ) 

Release Main
Release Pen
End



There will be a public alpha.



One giant leap for pens.(Posted 2004-12-21)
Here's a little example of a 2d app.

There's no need to use Import etc, as it's structured as a unique module.

Strict

Rem

	Trinity64 Engine.
	
	(c)Antony Wells 2005.
	
	Hello World! 
	
	2D Example.
	
End Rem 

'Create our main engine.
Local Main:TEngine = New TEngine 'Engine Entry Point.

'Create a full screen window.
Main.FindMode(640,480,32,T_FullScreen)

'Setup the gpu for 2d Drawing.
Main.Draw2D()

'Create a 2D Hardwre pen.
Local Pen:TDrawGL = New TDrawGL

Local Wood:TTexture = New TTexture
Wood.LoadFile("Wood.Jpg")

Pen.Color( 255,0,0,1 )
Pen.Blend( T_None )

Local Temp:TDrawGL=Null
Repeat
	Main.Cls()
	Pen.Rect( MouseX(),MouseY(),230,230 )
      Temp=Pen.Lock() ;Create a locked pen.(TDrawGLFast)
      Wood.Bind()
      For J=1 to 100
           Pen.Rect( Rnd(640),Rnd(480),Rnd(40),Rnd(40) )
      Next
      Pen.Unlock()
      Wood.unbind()
	Main.Flip()
Until KeyDown( KEY_ESCAPE ) 

Release Main
Release Pen
End


Trinity uses it's own opengl powered 2D engine for rendering, not glMax. It uses pixelmaps as the basis for it's pixel loaders, so it'll support whatever formats your set up of bmax supports via it's native loaders.. (At least until freeimage gets ported to bmax.)



One small step for man..(Posted 2004-12-21)
Trinity (Name subject to change) is the successor to VividGL. Based off VividPro, not Vivid Lite, it is the flagship product on the Dreamspace calender.

It is a big departure from VividGL, 95% new code base.

Over the coming weeks I'll reveal more concrete info, shots and demos as the time comes. A commercial game is being made using the engine, so they should be worth the wait.

A few of the benefits of Trinity however are,

The World's first fully 64 bit engine(I think it's the first anyway!), basically, everything internally and on the driver side uses 64bit precision where possible. All internal data, including vetrex, normals and colors are stored in 64bit precision.
Textures can be 64bit(16bit per channel) also, although for performance reasons you can use faster texture formats as well.(if you wish, Trinity can handle it automatically.)

Full Error Feedback, Including End Guard system. Means not only does vivid report *any* parameters that are not legal, it also reports calling function and class type.

Full OOP/Modular design. Trinity is broken down into core modules, for example Surface.Mod,Material.Mod etc.
And each module has at least one base class (Usually many more)

A small example, here's part of the error module.

Type TError
	
	Method New()
		ErrList=CreateList()
		ErrTime=CreateList()
		ErrMem=CreateList()
	End Method
	
	Method Stamp()
	 	Self.Invoke("Stamp",False,False,0)
	End Method
	
	Method Invoke(Error:String,Fatal:Int=False,HaltDebug:Byte=False,SpecialTag:Short=0)
		LastErr=Error
		ListAddFirst ErrList,Error
		ListAddFirst ErrTime,CurrentTime()
		ListAddFirst ErrMem,(String MemUsage())
		Select SpecialTag
			Default
		End Select 
		If HaltDebug
			DebugStop
		End If
		If Fatal
			RuntimeError Error
		End If
	End Method
	
	Method Last:String()
		Return LastErr
	End Method
	
	Method GetError:String(Index:Int)
		If Index<0 Index=0
		If Index>Self.Count() Index=Self.Count()
		Return (String ErrList.ValueAtIndex( Index-1 ))
	End Method
	
	Method GetErrorTime:String(Index:Int)
		Return (String ErrTime.ValueAtIndex( Index -1 ))
	End Method
	
	Method GetErrorMemUsage:Int(Index:Int)
		Return (Int (String ErrMem.ValueAtIndex( Index-1)))
	End Method
	
	Method PrintFunction(PrintF:Int(In:String))
		Err_Print=PrintF
	End Method
	
	Method EndGuard(PrintFunc:Int(In:String),GuardFunc:Int()=Null,CallFunc:Int=False,DumpErrors:Int=True)
		If CallFunc
			OnEnd( GuardFunc )
		End If
		If DumpErrors
			Err_Print = PrintFunc
			OnEnd(TError_EndGuard)
		End If
	End Method
	
	Method Clear()
		ClearList ErrList
		ClearList ErrTime
		ClearList ErrMem
		LastErr=""
	End Method
	
	Method Count:Int()
		Return CountList( ErrList )
	End Method
	
	Field ErrList:TList
	Field ErrTime:TList
	Field ErrMem:Tlist
	Field LastErr:String
End Type


Error guard is a nice concept, in so far that you can provide a function that is called if the program exists because of an error, also a pointer to a print output function, so you can define how the error handler directs it's output. To an on-screen console for example.
--