Worklog for AntMan - Banned in the line of duty.
Worklog 1
Return to Worklogs
| ||
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. :) |
| ||
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. |
| ||
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* |
| ||
The engine has been released. I've sold approximately 3 million copies so far. |
| ||
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. |
| ||
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 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. |
| ||
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. |
| ||
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 |
| ||
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 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'. :) |
| ||
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. |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
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 :) |
| ||
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! |
| ||
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.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 |
| ||
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. |
| ||
/\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... |
| ||
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; } |
| ||
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; }; |
| ||
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! |
| ||
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; }; |
| ||
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. |
| ||
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.) |
| ||
#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; }; |
| ||
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.... |
| ||
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..) |
| ||
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. |
| ||
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? :) ) |
| ||
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. |
| ||
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... |
| ||
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. |
| ||
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 ) |
| ||
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. |
| ||
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. |
| ||
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-. |
| ||
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.. |
| ||
' '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 |
| ||
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> |
| ||
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./ |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
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)... |
| ||
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. |
| ||
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 |
| ||
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.) |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
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.) |
| ||
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. |
| ||
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 ) |
| ||
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. |
| ||
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.) |
| ||
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. -- |