This short video (no music) shows the perspective 2D camera mode in the G2D (open GL) graphics library for PlayBasic. The mock up scene consists of a mix of elements mostly from Xenon 2000. In view is 2000 rotating sprites and the various map layers with filler backdrop.
The capture of the demo is rather awful (very framey), but it actually runs 200fps plus on the 10 year old althon 64 test system with 6600 gpu.
This tiny video was taken of a Xenon 2000 scene remake, which a top down shoot'em game for windows written by the Bitmap Brothers way back into 2000 as tuturoials series. This version of the remake is written in PlayBasic using our OpenGL library called G2D for the display. Normally PB uses DirectX and software rendering.
This remake isn't necessarily to show a working game, just how easy it is to port existing PlayBasic programs to use G2D display library. The video capture is sadly very framey even at a low resolution, which is annoying as the actual demo runs at 500+ fps even on the legacy test system, which is 9->10 years old,
The demo is running in PlayBasic V1.64P3 which is the current retail edition at the time of writing. The PlayBasic G2D library supports rendering PlayBasic images / sprites / maps / fonts / Particles and various 2D primitives though OpenGL interface .
You can find the source code for this demo and 1000's and others on our forums.
G2D - 2D OpenGL library for PlayBasic V1.64P PROTOTYPE #8
Release Date:22nd, Nov, 2014
PlayBasic version: For use with PlayBasic V1.64P (Retail or higher).
What is this?:
G2D is an alternative / replacement rendering library the uses the OpenGL API rather than the DirectX / Software interface that PlayBasic normally uses. The command set is evolving constantly and already supports a range of core 2d primitive drawing functions (Dots, Lines, Boxes,Polygons) through to Image, Sprites, Maps, Fonts / Text, and many the most recent addition is the programmable particle library. These functions try to be functionality identical to the internal PlayBasic equivalent command (where one exists), while only drawing to the OpenGL screen.
This library was written in PlayBasic V1.64P2 and converted to a DLL with PlayBasic2DLL
Latest Blog Posts:
The following is a selection of development blog posts, note the posts may mention pictures / source codes / video that may not be shown in this overview.
G2d Blog - Particles and all the small things (October 24, 2014)
Been thinking about adding particle / entity layers to the G2D library. Personally I tend to find particle libraries can be a hit hit and miss, some things are easy to do and others fall outside the scope of the solution. Although the same can be said about any library really.
Particle effects are useful in many situations, but there's a handful that come to mind such as smoke / fire / thrusters / explosions, so they're worth spending a bit more time thinking about, rather than jamming in the same old same old solution in.
Control wise different effects need different controls per particle, stuff like controlling speed / gravity / scale / rotation / image / Randomization etc could all be useful in various situations. So supporting a cross section of controls seems like the way to go, but this does make initializing them potentially harder for the user. Not a huge fan of functions that require 20 parameters though, obviously such things could be wrapped down, but still you soon end up with a lot more set up, than solution.
In recent years my favorite solution for such problems is a type of generalized solver. Where the user can define a set of operations which it runs it's internal logic over the data set. In particle terms the user builds a type of particle script (for want of better word) and the solver would apply this logic to each particle in the set. So the user isn't really hands on in the process, but they have control over how they move / rotate / animate and when they die.
Even with such customizable control there would still be situations where the user need to roll their own.. But ya get that !
The awfully static picture bellow doesn't really give you much of sense of the demo but anyway, the execution engine is taking shape. You can think of as a special purpose virtual machine for running basically vector operations, a bit like the vector stack stuff from a few years back. The code are thus far 3d vector only, but the idea is to support 1D,2D,3D vectors and possibly some bare bones integer controls. Don't wanna have too many opcodes and too much logic getting in the way of the particle execution engine though.
In this demo the controller runs the Particles.NEW() function upon creation which is then updated by the Particles.UPDATE() function. The FREE() code isn't used/defined in this demo, not too sure how the language will control the particles state. Currently the execution engine returns an ALIVE/DEAD (true/false) state on this object, if it's false it's died and needs to be reclaimed.
In terms of instructions so far we have SET,MOVE,ADD,SUB,DIV,MULT, RANDOMIZE and CMP. Which gives us just enough controls to create and explosion with gravity. It's not exactly BASIC, but with a little thought/reshuffling it seems like reasonable start. You won't be able to 'loop' in script though, so the logic will have to generally solve in order. Should be able to add some type of conditional branching (IF/ENDIF) styled statement, but it'd be nothing like BASIC..
Anyway.. here's an approximation of the controller code in our mock up script that creates the explosion attached (Running in just PlayBasic for now) .
PlayBasic Code:
; start of script block and name of this class. So scripts can get called by actual NAME
ParticleScript "Explosion"; declarations would be expect here (explicit and case sensitive)dim Speed as Vector3
dim SpeedScale as Vector3
dim SpeedCenter as Vector3
dim Gravity as Vector3
dim GravityAccel as Vector3
dim FloorPosition as Vector3
; function is called after object allocatedfunctionNew(); set starting position of this particle
Set(Pos,400,300,0); Set this vector to speed.x = 20, speed.y=20, speed.z=0
Set(Speed,20,20,0); Randomly scale speed vector. So it's speed.x *= rnd#(1),; speed.y*=rnd#(1), speed.z*=rnd#(1) Randomize(Speed); Set SpeedCenter. So it's this SpeedCenter.x = -10, SpeedCenter.y=-10, speedCenter.z=0
Set(SpeedCenter,-10,-10,0); Add SpeedCenter to Speed. So it's this; Speed.x += SpeedCenter.x,; Speed.y += SpeedCenter.y; Speed.z += SpeedCenter.z
Add(Speed,SpeedCenter)
Set(SpeedScale,0.99,0.99,0); force applied to the particle
Set(Gravity,0,0,0)
Set(GravityAccel,0,0.20,0); clipping vector
Set(FloorPosition,0,600,-1)EndFunction; Function called when objects motion is 'updated'Function Update(); Add current speed to the position
Add(Pos,Speed); Add gravity speed to the position
Add(Pos,Gravity); increase the force of gravity over time
Add(Gravity,GravityAccel); Scale speed over time
Add(Speed,SpeedScale); Compare position vector with Floor vector, this set the ; particles condition code which the execution engine returns.; when a particles position is inside the floor vector, it; returns an ok state, otherwise it's dead and needs to be ; deleted by the controller
Cmp(POs >=Floor)EndFunction[
EndParticleScript
G2d Blog - Particles Script Compiler - Local Rotations/Scaling/Animations (November 09, 2014)
Even though today was my birthday, still found time to add a branch (IF/ENDIF) block into the script. This means the script can make comparisons and make simple decisions upon on the result. Unlike the previous versions of the library the particle will only return a 'dead' state when the script hits the DIE() operator. Which is basically and END statement. So script is exited and the status set to dead.
So while still rather crude, we've basically arrived at a frame work that can do most common place particle effects. What we're missing is some way of spawning them relative to a parent. The current idea for that, is the user set the current parent (passes a structure to the library) and then the new() operator can pull useful stuff from, such as it's position, direction / rotation, speed. So if you had a ship that rotating, all you'd do is set the parent structure with that info, then any and all particles generated at that point will use that as they're origin. Allowing you to attach a thruster, spawn related sparks/explosions that sort of thing.
The current Particle VM is a bit naff, I think what i'll do is wrote a post processing converter, which will convert the instruction calling to a more optimal method within the final DLL version (PB2DLL), which would easily be using some type of ON VARIABLE GOTO/GOSUB structure. Which yields a fixed cost per instruction. Moreover I can use the same registering caching method that PB+PB2DLL use when writing opcodes, would allow the compiler to sub faster operations, or use packed methods. So the scripts should perform very well.
Anyway here's today's little picture.. It's show the particles using different frames, rotations, scales, speeds etc etc... Check the source code to
PlayBasic Code:
; ---------------------------------------------------------------------------------------; ---------------------------------------------------------------------------------------; ---------------------------------------------------------------------------------------; ---------------------------------------------------------------------------------------; PARTICLE SCRIPT EXAMPLE; ---------------------------------------------------------------------------------------; ---------------------------------------------------------------------------------------; ---------------------------------------------------------------------------------------; ---------------------------------------------------------------------------------------; Start if script called "Gravity EXPLOSION"
ParticleScript "Gravity Explosion"; declarations should be outside of functions and before first usagedim Speed as Vector3
dim SpeedScale as Vector3
dim SpeedCenter as Vector3
dim Gravity as Vector3
dim GravityAccel as Vector3
dim FloorPosition as Vector3
dim RotationSpeed as Vector3
; function is called after object allocated.functionNew(); set starting position of this particle
Set(Pos,400,300,0); Set this vector to speed.x = 20, speed.y=20, speed.z=0
Set(Speed,20,20,0); Randomly scale speed vector. So it's this speed.x *= rnd#(1);, speed.y*=rnd#(1), speed.z*=rnd#(1) Randomize(Speed); Set SpeedCenter. So it's this SpeedCenter.x = -10, SpeedCenter.y=-10, speedCenter.z=0
Set(SpeedCenter,-10,-10,0); Add SpeedCenter to Speed. So it's this]; Speed.x += SpeedCenter.x,; Speed.y += SpeedCenter.y; Speed.z += SpeedCenter.z
Add(Speed,SpeedCenter)
Set(SpeedScale,0.999,0.999,0); Gravity force we'll apply to the particle
Set(Gravity,0,0,0)
Set(GravityAccel,0,0.20,0); clipping vector
Set(FloorPosition,-20000,650,-1); set the frame to the max possible frames
Set(Frame,15,15,15); mult the frame by a random facor to pick a frameRandomize(Frame); set the rotation angle vector X,y,Z, only Z is used in a 2d scene
Set(Rotation,360,360,360)Randomize(Rotation)
Set(RotationSpeed,2,2,2)Randomize(RotationSpeed); set the Scale of this particle
Set(Scale,3,3,0)Randomize(Scale)EndFunction; Function called when objects motion is 'updated'Function Update(); Add current speed to the position
Add(Pos,Speed); Add gravity speed to the position
Add(Pos,Gravity); increase the force of gravity over time, so it accels down
Add(Gravity,GravityAccel); Scale speed over time
Mult(Speed,SpeedScale); Shrink the scale over time
Mult(Scale,SpeedScale); Add speed scale to rotation angle to turn the particle
Add(Rotation,RotationSpeed); Compare position vector with Floor vector, each field in is compared and MASKED together; into a 3 bit condition code
Cmp(Pos >= FloorPosition); branch on the previous condition code that was set by a previous CMP() operator.if; Set this particle to DEAD, so controller can reclaim it
die()endifEndFunction; End of this particle block
EndParticleScript
Wrote the emitter commands yesterday, the functions turned out pretty much like what's outlined above, with a few subtle changes. The emitter is the controller or owner of any group of particles. All particles within the group share common attributes, such as the spawning origin, logic scripts and the texture they use, but each emitter is unique. The user controls the spawning frequency (particle emission) updating and rendering. So you have complete control over if/when something is updated, and if it's rendered. There's no particle level access at all really, but a function to return a pointer to a particles locals could be useful, or perhaps a function to alter the locals of the set. Which is useful for adding/changing some global force, like wind for example.
The scene bellow is running in a new hacked together testbed. In the original demo, the code was man handling each particle through a list, now we've just managing the emitters. Basically telling them to emitter new particles, when to refresh and when to draw. Since they're all on screen we're updating all of them all the time. If and emitter was to do out of view, then of course you'd suspend updating/rendering it.
Here's an animation created from frame work running in standard PlayBasic, with any luck the damn thing will play... as it doesn't here !
G2d Blog - Programmable Particles DLL version (November 20, 2014)
Up until today, the particle library only existed as a set of PlayBasic functions and Psubs. After tonight though, the library has made it's way into the G2D library and now being compiled to machine code DLL using PlayBasic2DLL. There was few gremlins with the translation initially and a few spots where I'd been lazy and not manually allocated my types. Which would make it crash during the script compile, but those seem to be all sorted now.
For me, the most interesting thing about this isn't actually the rendering at point, it's how fast the Particle VM will execute the byte code, as if there's too much overhead in the particle VM, then there's no much use in them being programmable. But any fears I may have bad were soon squashed. With the particle scene controller being able to run 10,000 scripts at over 60fps on my 9 year old Athlon system. Which can be seen in the rather boring screen shot bellow.
The library can't render the particles to the OpenGL screen as yet, but even drawing the same FX screen yields a 10+ times performance boost in 4K particle heavy scene, rendering the particles as FX images with alpha addition. I'd say that with batching them as quads in GL, rendering should make mince meat of it really. While in reality it might be able to process 10K particle scripts, I'll be more than happy with rendering 1/2 of that at a reasonable rate. But that's Fridays little challenge
G2d Blog - Programmable Particles - 17000 particle test scene.(November 21, 2014)
Well that was much ado about nothing, as any fears that running particles through our custom particle VM would be too slow, should now be completely and utterly smashed with the library returning better than expected performance. The test scene bellow is shown in two states, the scene is made up of a number of elements again all cut and pasted together form the basic 2d demo that comes with the library. So in this scene we have some sprites an mock up map and depending on how fast you can press the ENTER KEY anywhere between 5K->17K live particles... Obviously the demonstration is over the top, but it does prove how efficient the PB Compiler -> PB2DLL process actually is. Which is VERY !
Test Machine: AMD64 3000, GF6600 ( 9 years old)
Download:
The current build of the G2D library is available through PlayBasic maintenance area on our forums.
G2D - 2D OpenGL library for PlayBasic V1.64P PROTOTYPE
Release Date:24th, June, 2014
PlayBasic version: For use with PlayBasic V1.64P (Beta Edition 42 or higher).
What is this?:
G2D is an alternative rendering library that uses the OpenGL API rather than the DirectX / Software interface that PlayBasic normally uses. The command set is very minimal at this point, in fact only about a dozen primate operations are supported at all. Those that are, try to be functionality identical to the internal PlayBasic equivalent commands, while only drawing to the OpenGL screen.
G2D currently only works with PlayBasic windowed modes, the library attaches the GL viewport to the PlayBasic window. When we do this, both the DX and GL screens are being drawn to the same window. You can get rid of the DX screen using the ScreenLayout command. The command gives you a rect (X1,y1,x2,y2) of where the DX screen should be drawn within the window. To get rid of it, just position it outside of the window.
This library was written in PlayBasic V1.64P and converted to a DLL with PB2DLL
You can download the first alphas through the forums.