Would you like to react to this message? Create an account in a few clicks or log in to continue.



 
HomeHome  Latest imagesLatest images  SearchSearch  RegisterRegister  Log inLog in  

 

 WIP: Controller system

Go down 
AuthorMessage
Darktib
Committer
Darktib


Messages : 389
Date d'inscription : 2009-07-20
Localisation : A coté de Paris

WIP: Controller system Empty
PostSubject: WIP: Controller system   WIP: Controller system Icon_minitimeThu Feb 16, 2012 1:44 pm

The last week I have started working on a controller system (which is not related to SPK::System) for SPARK.

What is a controller ?
Actually, when you create an effect, all parameters are fixed, and if you want to change it dynamically, you must do it yourself. For example, to change the direction of a StraightEmitter at run-time you must add some code in your main loop. A Controller is a class designed to change object parameters at run-time, without needing user code in the loop: a Controller possess special attributes that are called 'controls', that can be connected to other object attributes. When the controller sets the value of a control, every attribute connected to the control is set to the value of the control. And the cool point is that Controllers are also SPKObjects : you can chain controllers!

A simple example: let's say we have a StraightEmitter emitting particles from a point, and we want to "rotate" the direction (ie, direction = (sin(t),0,cos(t)) )
Currently, to do this, the code is:
Code:

// Init
// ...
SPK::Ref<SPK::StraightEmitter> emitter = ...;
// ...

while(gameIsRunning)
{
  emitter.setDirection(SPK::Vector3D(sin(t),0,cos(t)));
  render();
}

With controllers, it becomes:
Code:

// Init
// ...
SPK::Ref<SPK::StraightEmitter> emitter = ...;
SPK::Ref<SinController> sc = ...; // has an unique control, "value" (float)
SPK::Ref<CosController> cc = ...; // has an unique control, "value" (float)
SPK::Ref<VectorMultiplexer> vm = ...; // has an unique control, "value" (Vector3D)
vm.setY(0.0f);
sc.connect("value",vm,"x");
cc.connect("value",vm,"z");
vm.connect("value",emitter,"direction");
// ...

while(gameIsRunning)
{
  render();
}

The main advantage here is that controls and connection are serializables, an artist can put some dynamics in the effect without having the programmer to code extra functions.

The system is not finished yet, I am still working on it (because of the implications, for example 100% automatic deserialization, etc...). I will post further improvements of this feature in this thread. For the moment, here is a test demo:
Link : http://www.mediafire.com/?7njyil0y7ag65m4
Code :
Code:
// external libs
#include <irrlicht.h>

// SPARK lib
#include <SPARK.h>
#include <SPARK_IRR.h>

// windows only
#ifdef _WIN32
#include <windows.h>
#endif

float dirX = 0.0f,dirY = 0.0f,dirZ = 0.0f;

using namespace irr;
IrrlichtDevice* device = NULL;

// Input Receiver
class MyEventReceiver : public IEventReceiver
{
    public:
        virtual bool OnEvent(const SEvent& event)
        {
            if(event.EventType==EET_KEY_INPUT_EVENT)
            if(event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown==false)
               device->closeDevice();
            return false;
        }
};

class SinController : public SPK::Controller
{
   SPK_START_DESCRIPTION(SinController)
      SPK_CONTROL("value",SPK::SPK_TYPE_FLOAT)
   SPK_END_DESCRIPTION

   public:
      SinController(float p_=0):time(0),p(p_){}

   protected:
      virtual void innerUpdateControls(float deltaTime)
      {
         float period = 2.0f;
         time = fmod(time + deltaTime,period);
         float tTime = time / period;
         float phase = p * 2 * irr::core::PI;
         float output = sinf(phase + tTime * 2 * irr::core::PI);
         if(!setControl(0,output))
            printf("Failed to set sin control\n");
      }
      float time,p;
};

class VectorMultiplexer : public SPK::Controller
{
   SPK_START_DESCRIPTION(VectorMultiplexer)
      SPK_ATTRIBUTE("x",SPK::SPK_TYPE_FLOAT,setX)
      SPK_ATTRIBUTE("y",SPK::SPK_TYPE_FLOAT,setY)
      SPK_ATTRIBUTE("z",SPK::SPK_TYPE_FLOAT,setZ)
      SPK_CONTROL("value",SPK::SPK_TYPE_VECTOR)
      SPK_CONTROL("test1",SPK::SPK_TYPE_FLOAT_PAIR)
      SPK_CONTROL("test2",SPK::SPK_TYPE_INT32_ARRAY)
   SPK_END_DESCRIPTION

   public:
      VectorMultiplexer():x(0),y(0),z(1) {}

      void setX(float v) { x = v; dirX = x; }
      void setY(float v) { y = v; dirY = y; }
      void setZ(float v) { z = v; dirZ = z; }

   protected:
      float x,y,z;
      virtual void innerUpdateControls(float deltaTime)
      {
         SPK::Vector3D output(x,y,z);
         if(!setControl(0,output))
            printf("Vector: failed to set control\n");
         if(!setControl(1,12.3f,45.6f))
            printf("float-pair: failed to set control\n");
         if(!setControl(2,std::vector<int>(3,42)))
            printf("int-array: failed to set control\n");
      }
};

// Main function
int main(int argc, char *argv[])
{
   //!IRRLICHT
    video::E_DRIVER_TYPE chosenDriver = video::EDT_OPENGL;
#ifdef _WIN32
   if(MessageBoxA(0,"Do you want to use DirectX 9 ? (else OpenGL)","SPARK Irrlicht test",MB_YESNO | MB_ICONQUESTION) == IDYES)
      chosenDriver = video::EDT_DIRECT3D9;
#endif

    //!IRRLICHT
   device = createDevice(chosenDriver,
      core::dimension2d<u32>(800,600),
      32,
      false,
      false,
      false,
      new MyEventReceiver);

    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
    gui::IGUIEnvironment* guienv = device->getGUIEnvironment();

    device->setWindowCaption(L"SPARK Irrlicht test - Mouse to aim, arrows to move");
   device->getCursorControl()->setVisible(false);
    irr::scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(smgr->getRootSceneNode(),100.0f,0.0005f);
    cam->setPosition(irr::core::vector3df(0.0f,0.0f,1.5f));
    cam->setTarget(irr::core::vector3df(0.0f,-0.2f,0.0f));
    cam->setNearValue(0.05f);

   // Inits Particle Engine
   // Sets the update step
   SPK::System::setClampStep(true,0.1f);         // clamp the step to 100 ms
   SPK::System::useAdaptiveStep(0.001f,0.01f);      // use an adaptive step from 1ms to 10ms (1000fps to 100fps)
   
   irr::scene::CSPKParticleSystemNode* system = new irr::scene::CSPKParticleSystemNode(smgr->getRootSceneNode(),smgr);
   system->drop(); // We let the scene manager take care of the system life time

   {
   SPK::Ref<SPK::IRR::IRRQuadRenderer> quadRenderer = SPK::IRR::IRRQuadRenderer::create(device);
   quadRenderer->setBlendMode(SPK::BLEND_MODE_ADD);
   quadRenderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
   quadRenderer->setTexture(driver->getTexture("res\\flare.bmp"));
   quadRenderer->setTexturingMode(SPK::TEXTURE_MODE_2D);

   SPK::Ref<SPK::Point> emitpt = SPK::Point::create();
   SPK::Ref<SPK::StraightEmitter> emitter = SPK::StraightEmitter::create(SPK::Vector3D(1,0,1),emitpt);
   emitter->setForce(0.4f,0.6f);
   emitter->setFlow(200);

   SPK::Ref<SPK::ColorGraphInterpolator> graphInterpolator = SPK::ColorGraphInterpolator::create();
   graphInterpolator->addEntry(0.0f,0xFF000088);
   graphInterpolator->addEntry(0.5f,0x00FF0088);
   graphInterpolator->addEntry(1.0f,0x0000FF88);

   SPK::Ref<SPK::Group> group = system->createSPKGroup(400);
   group->setRadius(0.15f);
   group->setLifeTime(1.0f,2.0f);
   group->setColorInterpolator(graphInterpolator);
   group->setParamInterpolator(SPK::PARAM_SCALE,SPK::FloatRandomInterpolator::create(0.8f,1.2f,0.0f,0.0f));
   group->setParamInterpolator(SPK::PARAM_ANGLE,SPK::FloatRandomInitializer::create(0.0f,2 * 3.14159f));
   group->addEmitter(emitter);
   group->addModifier(SPK::Gravity::create(SPK::Vector3D(0.0f,-0.5f,0.0f)));
   group->addModifier(SPK::Friction::create(0.2f));
   group->setRenderer(quadRenderer);

   SPK::Ref<SinController> scontroller1 = SPK_NEW(SinController);
   SPK::Ref<SinController> scontroller2 = SPK_NEW(SinController,0.25);
   SPK::Ref<VectorMultiplexer> vmcontroller1 = SPK_NEW(VectorMultiplexer);
   SPK::Ref<VectorMultiplexer> vmcontroller2 = SPK_NEW(VectorMultiplexer);
   scontroller1->connect("value",vmcontroller1,"x");
   scontroller1->connect("value",vmcontroller2,"z");
   scontroller2->connect("value",vmcontroller1,"z");
   scontroller2->connect("value",vmcontroller2,"x");
   vmcontroller1->connect("value",emitter,"direction");
   vmcontroller2->connect("value",emitpt,"position");
   system->addSPKController(scontroller1);
   system->addSPKController(scontroller2);
   system->addSPKController(vmcontroller1);
   system->addSPKController(vmcontroller2);


   int startX = 80, startY = 80;
   float lineLength = 40.0f;

   while(device->run())
   {
      //system->setPosition(irr::core::vector3df(-dirX,dirY,-dirZ));

      driver->beginScene(true, true, irr::video::SColor(0,0,0,0));

      // Renders scene
      smgr->drawAll();

      irr::core::stringw infos; infos+="FPS: "; infos+=driver->getFPS(); infos+=" - Nb Particles: "; infos+=system->getNbParticles();
      guienv->getBuiltInFont()->draw(infos.c_str(),irr::core::rect<irr::s32>(0,0,170,20),irr::video::SColor(255,255,255,255));

      irr::video::SMaterial mat;
      mat.Lighting = false;
      driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
      driver->setMaterial(mat);
      driver->draw2DLine(irr::core::vector2di(startX,startY),irr::core::vector2di((int)(startX + lineLength * dirX),(int)(startY + lineLength * dirZ)));

      driver->endScene();
   }

   SPK_DUMP_MEMORY
   }
   device->drop();
   SPK_DUMP_MEMORY

   return 0;
}
Note 1: the code is just to show how to get this to work. Obviously, you cannot compile it because the controller system is not on the SVN repository yet Wink
Note 2: the point of emission is describing a circle, and the direction of emission too, but in the opposite way, leading to this strange effect.

Feel free to comment!
Back to top Go down
Darktib
Committer
Darktib


Messages : 389
Date d'inscription : 2009-07-20
Localisation : A coté de Paris

WIP: Controller system Empty
PostSubject: Re: WIP: Controller system   WIP: Controller system Icon_minitimeThu Feb 23, 2012 3:42 pm

Some random piece of news about the controller system...

About types: this system will introduce SPK::SPKType, which is a (big) enum containing all types of variable that can be controlled in SPARK. A type is a combination of a base type (bool, char, float, int, Ref<SPKObject>, Ref<Emitter>, etc...) and a store method (single, pair, triplet, quadruplet, array). It allows you to precisely define an attribute, and permits the controller system to use your already existing code for setting attributes.
For example, I've written a controller which changes the zone of an emitter each x seconds (x is real):
Code:
class ZoneChanger : public SPK::Controller
{
   SPK_START_DESCRIPTION(ZoneChanger)
      SPK_CONTROL("value",SPK::SPK_TYPE_ZONE_REF)
   SPK_END_DESCRIPTION

   public:
      ZoneChanger(float p=1.0f):time(0.0f),period(p){}
      void addZone(const SPK::Ref<SPK::Zone>& z)
      {
         zones.push_back(z);
         timePerIndex = period / zones.size();
      }

   protected:
      virtual void innerUpdateControls(float deltaTime)
      {
         time = fmod(time + deltaTime,period);
         SPK::Ref<SPK::Zone> output = zones[(unsigned int)(time / timePerIndex)];
         if(!setControl(0,output))
            printf("Failed to set zone control\n");
      }
      float time,period,timePerIndex;
      std::vector<SPK::Ref<SPK::Zone> > zones;
};
Note: this is a test controller, the final one will use attributes and will be a lot more powerful.


Now, let's focus on the description declaration. It is a lot concise now : you no longer have to call SPK_PARENT_ATTRIBUTES or SPK_IMPLEMENT_OBJECT, as it is done automatically. And attributes have a third parameter, the setter of the attribute. It is needed to control the attribute but also to deserialize it.


I am on holiday next week, so there won't be any advances on the controller system for a week. For you, time to see the code!
You can download a copy of the repository with the controller system here. This is still far from being finished (lacks automatic deserialization, serialization is intentionnally broken, and the code should be cleaner I think).
There is a demo : 'demos/ControllerTest'. Be aware you will need Irrlicht 1.8 (svn) for it to compile (there was a typo in Irrlicht 1.7 code that was fixed on Irrlicht SVN)

Have fun, and don't forget to post any idea/request/patch/bug here!
Back to top Go down
Darktib
Committer
Darktib


Messages : 389
Date d'inscription : 2009-07-20
Localisation : A coté de Paris

WIP: Controller system Empty
PostSubject: Re: WIP: Controller system   WIP: Controller system Icon_minitimeSat Mar 17, 2012 2:22 pm

Lately, I've introduced some meta-programming facilities in SPARK.

First, back to the types.

Types in SPARK are defined as values in the enumeration 'SPK::SPKType'. There are 19 base types:
Base typeCorresponding C++ type
SPK_TYPE_BOOLbool
SPK_TYPE_CHARchar
SPK_TYPE_INT32int
SPK_TYPE_UINT32unsigned int
SPK_TYPE_FLOATfloat
SPK_TYPE_VECTORVector3D
SPK_TYPE_COLORColor
SPK_TYPE_STRINGstd::string
SPK_TYPE_OBJECT_REFRef<SPKObject>
SPK_TYPE_ACTION_REFRef<Action>
SPK_TYPE_CONTROLLER_REFRef<Controller>
SPK_TYPE_EMITTER_REFRef<Emitter>
SPK_TYPE_GROUP_REFRef<Group>
SPK_TYPE_FLOAT_INTERPOLATOR_REFRef<FloatInterpolator>
SPK_TYPE_COLOR_INTERPOLATOR_REFRef<ColorInterpolator>
SPK_TYPE_MODIFIER_REFRef<Modifier>
SPK_TYPE_RENDERER_REFRef<Renderer>
SPK_TYPE_ZONE_REFRef<Zone>
SPK_TYPE_ZONED_MODIFIER_REFRef<ZonedModifier>

Then, you have 5 store method:

  • single : 1 value of the base type
  • pair : 2 values of the base type
  • triplet : 3 values of the base type
  • quadruplet : 4 values of the base type
  • array : n values of the base type in a variable length array (std::vector)


The SPKType value all respect the same (quite intuitive) pattern. Let's take an example:
SPK_TYPE_FLOAT_TRIPLET
The blue part is the prefix that all SPARK types share.
The red part is the name of the base type. Here it is FLOAT, but it could have been ACTION_REF for example.
The green part is the suffix linked to the store method (the 'single' store method does not have a suffix). Here it is triplet, that means a value of type SPK_TYPE_FLOAT_TRIPLET contains 3 floats.

Now, why that much types ?

With the controllers system, Attributes have an extra field, their setter. The setter prototype is computed using the type of the attribute.
For example, SPK::Zone has only one attribute, their position, which type is SPK_TYPE_VECTOR. SPARK expects a setter of the form void (Zone::*)(const SPK::Vector3D&) (the used function is obviously 'setPosition').
It enable attributes to be strongly typed (and you cannot pass an innappropriate setter). Note that numeric types are passed by value and not by reference.
Also, the setter for the type SPK_TYPE_*_PAIR (for example) is void (MyClass::*)(U,U) where U is the c++ type corresponding to the SPARK base type

Meta-programming
The meta programming facilities allows user to find, given a SPKType, the C++ corresponding type, the number of parameters for the setter, i parameter type (ie, 'real' type + const ref if not numeric), the base type, etc... All is done by using the helper SPKTypeInfo.
Finally you can find the SPKType associated with a C++ type.

This feature is necessary to generate Attributes, Controls, etc... with code repetition
Back to top Go down
Darktib
Committer
Darktib


Messages : 389
Date d'inscription : 2009-07-20
Localisation : A coté de Paris

WIP: Controller system Empty
PostSubject: Re: WIP: Controller system   WIP: Controller system Icon_minitimeThu Apr 26, 2012 9:20 am

About (de)serialization...

I've introduced a little change in the previous work: instead of specifying only the setter(s) for an attribute, getter(s) are now also needed. Therefore, serialization and deserialization are entirely automatic, no code from user is needed. And you can remove the two function innerImport and innerExport.

This kind of feature is really nice because:
1/ SPARK is ensuring the validity of data, users can't add wrong data (bug, etc...)
2/ The (de)serialization processus is now totally handled by SPARK so some optimizations can safely be done. I do not expect a boost in speed, but I expect the process to consume less memory than before.

For the Loader/Saver part, the class IO::Attribute will disappear, as it is no longer needed now.

Note: multi-threaded (de)serialization is not possible.
Back to top Go down
Darktib
Committer
Darktib


Messages : 389
Date d'inscription : 2009-07-20
Localisation : A coté de Paris

WIP: Controller system Empty
PostSubject: Re: WIP: Controller system   WIP: Controller system Icon_minitimeTue Jul 03, 2012 6:46 am

Despite the absence of messages recently, the project has advanced; a new kind of attributes was created: structured attributes, which consists of an array of structure. Each field of each item in the array can be independently controlled, thus allowing cool effects Wink. It is the only attribute that have this ability.

For example, given the structure
Code:

struct S
{
 float x;
 Color y;
};
the old method was to create 2 array attributes, one for the x values and one for the y:
Code:

 attribute 1 = array<float> // for x
 attribute 2 = array<Color> // for y
Now, you just need one attribute.
Code:

 attribute = array<S>
There is also a good side-effect: serialization / deserialization now ensure correctness of data: with the old method, 2 arrays are serialized, and the user can change one of the array, so for example one have 10 items and the other have 6 items: full deserialization is impossible.

Here is a demo, with the source used to create it (not the cleanest code I've ever wrote...) (this does not include the code of the controller system): http://www.mediafire.com/?kmiq3a059785kq9
Back to top Go down
Darktib
Committer
Darktib


Messages : 389
Date d'inscription : 2009-07-20
Localisation : A coté de Paris

WIP: Controller system Empty
PostSubject: Re: WIP: Controller system   WIP: Controller system Icon_minitimeSun Aug 19, 2012 8:39 am

You can now test controllers by yourself : https://spark.canadian-forum.com/t121-spark-2-dev-diary#1420
Back to top Go down
Sponsored content





WIP: Controller system Empty
PostSubject: Re: WIP: Controller system   WIP: Controller system Icon_minitime

Back to top Go down
 
WIP: Controller system
Back to top 
Page 1 of 1
 Similar topics
-
» New feature: controller system
» Rotating a system in irrlicht
» SPARK Move a System?
» [Article] Optimizing the rendering of a particle system
» disable/enable/hide particle system

Permissions in this forum:You cannot reply to topics in this forum
 :: English Forum :: Showcase (en)-
Jump to: