Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [ODFAEG] (Open Source Development Framework Adapted for Every Game)  (Read 159891 times)

0 Members and 3 Guests are viewing this topic.

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #45 on: February 19, 2014, 01:31:43 pm »
You almost convinced me, but I read that :

You talek about the thor::action system but the thor::action system of thor is not sufficient, imagine that you have to click in a button you'll have to define a thor::action for each pixel of the button.

WHHAAAAT ? Stop to say crap... Some years ago I implemented a GUI with buttons and callback working with std::function and std::bind (well, it was perhaps boost at the time, but result's the same) and it worked very well. No question of pixels... I don't see any link anyhow, nor from close, nor from far.

Edit : the code of the said button should be in my Engenesis repo on my GitHub no it's not since I wiped the repo
« Last Edit: February 19, 2014, 01:34:31 pm by Lo-X »

therocode

  • Full Member
  • ***
  • Posts: 125
    • View Profile
    • Development blog
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #46 on: February 19, 2014, 01:35:50 pm »
I really need performance.

I take my bet on that you have not measured a bottleneck still.

I agree with the above poster too. A messaging system in a framework should not be the bottleneck, in that case, something is wrong.

In my framework, I use the method I described here: blog.therocode.net/2013/09/messaging-using-variadic-templates/. This approach uses neither function pointers nor std::functions but instead calls the receiving function directly which for me has proven to be more than fast enough. This is also a very clean approach and the message bus is less than 100 lines of code.

If you don't believe that it is fast enough, I wrote this to profile:

#include <featherkit/messaging.h>
#include <chrono>

FEA_DECLARE_MESSAGE(NumberMessage, int32_t);  //message carrying one int

class NumberKeeper : public NumberMessageReceiver
{
    public:
        NumberKeeper() : total(0)
        {
        }
        void handleMessage(const NumberMessage& message) override
        {
            total += std::get<0>(message.mData);;
        }
       
        int32_t total;
};

int main()
{  
    using namespace std::chrono;

    fea::MessageBus bus;
    NumberKeeper keeper;

    bus.addSubscriber<NumberMessage>(keeper);


    std::cout << "total number is now " << keeper.total << " and will start sending messages!\n";

    high_resolution_clock::time_point before = high_resolution_clock::now();

    for(uint32_t i = 0; i < 300000; i++)     //send 300000 messages
        bus.send(NumberMessage(5));

    high_resolution_clock::time_point after = high_resolution_clock::now();

    std::cout << "now done, total number is " << keeper.total << ". The time it took was " << duration_cast<milliseconds>(after - before).count() << " milliseconds. Cya mate!\n";
}
 

Output:
tobbe@archosaurus ~/projects/messagingtest % ./bin/messagingprof
total number is now 0 and will start sending messages!
now done, total number is 1500000. The time it took was 13 milliseconds. Cya mate!
 

In other words, it sends 300000 messages to one receiver just fine in less than one game frame (one frame is typically ~16ms). I think the cases when you need more performance from the messagebus than this is really rare and will probably be slow due to other factors, and wouldn't be feasible for a real time application such as a game anyway.

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #47 on: February 19, 2014, 02:51:09 pm »
Usually when someone claims to need performance without being directly looking for solutions to a very specific bottleneck, that means they aren't even using that tech anywhere..

People have been asking _why_ is all this performance needed, and that wasn't really answered. Chances are you're saving a little bit of CPU on these little quirks, only to waste most of its potential on bad code later in the project.. It's what usually happens, slowness coming from inappropriate use of containers, bad allocation patterns etc..

I'd advice to focus on giving actual usable functionality with some value. If your library is providing less or even the same as its competitors, chances are no one will use it.. The best of luck for it, but I'd really focus on providing something worth people's times in it. SFML with the currently existing community extensions is more than enough for most indie projects you can think of.

As far as signals go, I've been happily married with libsigc++ for years now. It rocks so much! The c++11 alternatives seem more than promising as well. In sum, I don't think you can do better than either one, as most developers couldn't either..

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #48 on: February 19, 2014, 05:35:22 pm »
It's not a question of optimisation but also a question of needing functionnalities.

I need  it to use a signal and a slot system. (the user create  two functions pointers, (the first is a signal, the second is the slot), and I store them in a structure and map them with a connexion name)

I have a class which stores all signals, slots and actions. (I can't use std::bind because the type is undefined so I can't store them)
I want also to change the parameters of the slot and the signals (hey have always the sames parametes like in QT) when I want. (At their creation or at they execution)
So I need to pass parameters like we do this with std::bind. (The better solution that I've found is to create two tuples and to concat them, but I don't know if it's possible to change the elements types into a tuple to replace the ones wich are placeholders)
So I've created a class witch contruct function pointers, pass parameters to the functions and call them with the operator().
All class that store and call function pointers inherit from a single class and I do a cast when I need to change parameters. (The operator() call the pointer to the fonction with the parameters given in the tuple)

Ok, it works fines excepts with the return type, I can't have a generic calling function because the return type is always different :

 virtual void* getReturn() const = 0;
 

 template <typename R> R invoke() {
        (*delegate)();
        if (delegate->hasReturn()) {
            return reinterpret_cast<R>(delegate->getReturn());
        }
        return 0;
    }
 

It gives me an error because it can't cast bool to void* (I can't make a template function virtual too. :/)

I can't also store the type of the template and retrieve it at the execution time. :/
If everyone as an idea ...

PS : I have a base class (Delegate) and severals child delegates classes wich store different pointers to functions. (And each derived classes redefines the void operator() to clall the function pointer.) (With the given parameters that I stored into the tuples)




« Last Edit: February 19, 2014, 05:38:37 pm by Lolilolight »

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #49 on: February 19, 2014, 05:56:54 pm »
So :

There's plenty of sigslot libs that uses std::function. One was given in another post above.

Using std::function or your function system doesn't allow a compile-time definition of messages. It's executed in live (well, don't think that's an issue, but since you want to optimize everything, you must know it). Therocode has a framework that allow compile time messages with any parameter you need, not matter their type.

Usually, you don't need  return type for sigslots. The principal is that some part of the program wants to notify that a event happened, without knowing what other part of the program will catch that. It can be one part that do the catch, none, or a lot. So a return means nothing... In what order will they return things ? It's unhandlable.
If you know what part of the program will return back something and what type it will be, so why do you call it directly... ?
« Last Edit: February 19, 2014, 05:58:59 pm by Lo-X »

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #50 on: February 19, 2014, 07:28:34 pm »
If you don't want to lose time you could pass an argument by reference and use it as return value

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #51 on: February 19, 2014, 07:34:57 pm »
Yes you're right, I've made two generic class so, once with a FastDelegate for return type functions, and one with a delegate for void functions and it works. ;)

Anyway the signal returns always a bool and the slot returns always a void :


Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #52 on: February 20, 2014, 05:40:53 pm »
Ok now I've fixed the last bugs and I must say that's it's very faster!!!

Before I had to have a speed of 10 to move the caracter, and the framerate of the animations wasn't very high too.
The clock returns also seconds to move the view in realtime.

Now, I had to define a speed of 50 000 otherwise the caracter don't move fast enougth so unlike as you said before there's a real difference of performance!

I'll update the gith-hub this evening. ;) (Or this night :D) (In other word, befor tommorrow.)

I'm happy, this'll really upgrate the performances comparing as before when i used the networking..., it was too slow!

That's why I've decided to build a framework, to optimise source code and have some goods advices. :)





« Last Edit: February 20, 2014, 05:44:10 pm by Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #53 on: February 20, 2014, 10:04:03 pm »
I've updated the git-hub repository.

Now, the signals and slots must be objects of type FastDelegate, a FastDelegate object encapsulate a pointer to a function of any type (excepts anonymous function I haven't finish all code implementation yet), and functions arguments.

The fast delegates are the benefits to be faster and to allow you to pass derived objects properly by casting a derivate object pointer to a base object before calling the virtual member function of a base class.

It avoids to have to call directly the virtual member function of the base class on an object of a derived class whith the operator ->, the code may be unportable and the behaviour can be undefined when the base class inherits from several classes with a virtual inheritance. (and also if thoses classes have abstract virtual functions)

The delegate'll be even introduced in next C# version it seems. :)

To create a FastDelegate object you have just to past the return type of the function pointer as a tempalte argument and the adress of the function to call. :)

Like this :

FastDelegate<bool> delegate(&MyCall::MyFunction);
 

Don't forget to pass the arguments to the functions before calling it if the function takes argument, and, the object if it's a member function : (Otherwise it result to a crash, it's the inconvenient of the using of tuples but the advantages are powerfull because the code is generate at the compilation time and the function call result to only 2 ASM instructions.)
delegate.setParams(object, argument1, ...);
 

And you have just to class the operator() to execute the function :
delegate();
 

Later you'll be able to pass default arguments when you'll create the delegate the defautl arguments well be set in a tuple, and be concataned with another tuple that contains arguments passed before calling the delegate. (And a placeholder system maybe'll be avalaible in a next version if I can do this technique with tuples (and not with std::bind any more))

The actions can know have a signal function, I can't use the emit key word here because this feature is only avalaible in Qt, so, the alternative is to pass a FastDelegate object which a pointer to a function whiwh return true or false if the signal is triggered. (This function is called a trigger function)

With the new system we can call a slot if one or more sf::event and a trigger function are triggered.

A system like the java listener'll be implemented later with the guis components in the next version. (I'll certainly take example on the source code of sf::GUI. :) )

It should rox. (And I'll finally have a framework which guis, opengl and sfml are compatible. (This is not the case with the actuals games framework so it's also why I've decided to create ODFAEG.)
I've also tried with java and JOGL, but JOGL and java classes weren't very compatible, it was resulting to thread concurrent exception most of the time.

This is not the case with ODFAEG. :)
I'm happy to have finally found a solution to my problems. (But know I'have to reimplementing all)
« Last Edit: February 20, 2014, 10:11:02 pm by Lolilolight »

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #54 on: February 21, 2014, 01:22:42 am »
The delegate'll be even introduced in next C# version it seems. :)

I have no clue what you mean by this... considering you can already write the following code (in C# or any CLI language for that matter).

var callback = new Func<bool>(MyFunction); // Create callback/delegate
var result = callback(); // Invoke callback/delegate

// Or for that matter lets have fun using lambda expressions

var firstCallback = new Action(() => { Console.WriteLine("First callback"); });
var secondCallback = new Action(() => { Console.WriteLine("Second callback"); });
var combinedCallbacks = firstCallback + secondCallback; // Combine callbacks
combinedCallbacks(); // Invoke both callbacks

// Output
/* First callback
   Second callback */
« Last Edit: February 21, 2014, 02:26:43 am by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #55 on: February 21, 2014, 09:18:59 am »
Ha it's already implemented in C#.

Sorry then.

C# seems to be a nice language too. ^^


Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #56 on: February 21, 2014, 07:49:31 pm »
The place holder system is not for now, because, I tried to retrieve the type of the specific delegate like this instead of using a static cast on the template parameters of the functions because the size of the values passed and the size of the arguments function types are not the same when I use palceholders so I need to store the type of the delegate somewhere and retrieve it to do the cast when I change the params of the delegate, so I tried something like this :

template <class T> class DelegatePrototype {
    public :
    virtual bool operator== (T& other) const = 0;
};
typedef void DefaultVoid;

class Delegate : public DelegatePrototype<Delegate> {
    public :
    virtual void operator()() = 0;
    virtual bool hasReturn() const = 0;
    virtual void* getReturn() const = 0;
    std::type_info& getType() {
        return typeid(this);
    }
};
 
And int the fast delegate class :
template<typename... V> void setParams(V... vals) {
        if (static_cast<delctype(delegate->getType())>(delegate)) {
            static_cast<delctype(delegate->getType())>(delegate)->setParams(vals...);
        }
    }
 

It work well with fast delegates with unvoid functions but it doesn't work with delegates which void functions and I have this error message :

Code: [Select]
C:\ODFAEG\include\ODFAEG\Core\signal.h|256|error: 'class odfaeg::Delegate' has no member named 'setParams'|

The most strange thing is that I can retrieve the fast delegate like this :

FastDelegate<void*> fd = static_cast<decltype(delegate)>(delegate);
fd->setParams(args...)
 
Works with static function delegates but not with member function delegates.

But I can't call member function on the delegate :
static_cast<decltype(delegate)>(delegate)->setParams(vals...)
 

Works with unvoid functions but not with void functions.

Is it a c++ bug ?







« Last Edit: February 21, 2014, 07:51:38 pm by Lolilolight »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #57 on: February 21, 2014, 08:15:12 pm »
Is it a c++ bug ?
Yeah, sure.

Lolilolight, before always blaming libraries, compilers and programming languages for having bugs, have a deeper look at your code, make sure you really understand it, and then find out what you did wrong. If you just invested 20 seconds to actually read the code you wrote, you would see that you're casting something to the type of itself, which is clearly not how conversions work.

Concerning the whole delegate mess, we've already had an endless discussion in the French forum where I wanted to show why you should use std::function instead of reinventing it in a worse way, apparently you didn't learn from it.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #58 on: February 21, 2014, 10:08:30 pm »
You are wrong, I don't cast an object of type Delegate to itself but an object of type Delegate to objects of type FastDelegate1<FunctionTYPE>, FastDelegate2<FunctionTYPE>, etc...

I don't kno if you're looking at my code yet but.

template <typename R> class FastDelegate {
    public :
    FastDelegate () {
        delegate = nullptr;
    }
    bool operator!() {
        return delegate == nullptr;
    }


    template <typename O, typename ...A> FastDelegate(R(O::*f)(A...) const) {
        delegate = new FastDelegate3<R, O, A...>(f);
    }
    template <typename O, typename ...A> FastDelegate(R(O::*f)(A...)) {
        delegate = new FastDelegate3<R, O, A...>(f);
    }
    template <typename ...A> FastDelegate(R(*f)(A...)) {
        delegate = new FastDelegate1<R , A...>(f);
    }


    R operator()() {
        (*delegate)();
        return reinterpret_cast<R> (delegate->getReturn());
    }
    template<typename ...A> void setParams(A... args) {
        if (static_cast<FastDelegate1<R, A...>*>(delegate)) {
            static_cast<FastDelegate1<R, A...>*>(delegate)->setParams(args...);
        }
    }
    template<typename O, typename D, typename ...A> void setParams(D* derived, A... args) {
        if (static_cast<O*>(derived)) {
            static_cast<FastDelegate3<R, O, A...>*>(delegate)->setParams(static_cast<O*>(derived), args...);
        }
    }
    template<typename O, typename ...A> void setParams(O* object, A... args) {
        if (static_cast<FastDelegate3<R, O, A...>*>(delegate)) {
            static_cast<FastDelegate3<R, O, A...>*>(delegate)->setParams(object, args...);
        }
    }
    bool operator==(FastDelegate &other) {
        return delegate == other.delegate;
    }

private :
    Delegate* delegate;
};
 

It's not dramatic if it don't work I can do it without placeholders it work also well. (The only thing it that i'll have to do is to pass all parameters at the delegate creation.)

I just do that for learning purpose. (And to see what can I do which this language and what can I not do.

type_info wirks only when I cast an object of type delegate into objects of type FastDelegate3<FuncTYPE> and FastDelegate1<FUNCTYPE> objects.

« Last Edit: February 21, 2014, 10:11:20 pm by Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: [ODFAEG] (Open Source Development Framework Adapted for Every Game)
« Reply #59 on: February 22, 2014, 12:12:45 pm »
I've found why it's simply because I didn't used a fast delegate with return something in the code so..., I forgot that I've wiped some code.

Anyway  T type and typeid(type) aren't of the same types, T is replace by a type and typeid(type) is of type typeinfo.

I don't think that exists a safe way to store the type of a template and to retrieve if at compilation time to do a static_cast in c++ like this.

template <class T> class DelegatePrototype {
    public :
    virtual bool operator== (T& other) const = 0;
};
typedef void DefaultVoid;

class Delegate : public DelegatePrototype<Delegate> {
    public :
    virtual void operator()() = 0;
    virtual bool hasReturn() const = 0;
    virtual void* getReturn() const = 0;
    const std::type_info& getType() {
        return typeid(*this);
    }
};
template <typename R, typename O, typename ...A> class FastDelegate3 : public Delegate {
        public :
        FastDelegate3 (R(O::*func)(A...)) {
            typedef R(*CB)(MemberFunction<R(O*, A...)>, O*, A...);
            CB cb = &callback;
            funct = new Functor<R(MemberFunction<R(O*, A...)>, O*, A...)> (cb, MemberFunction<R(O*, A...)>(func));

        }
        FastDelegate3 (R(O::*func)(A...) const) {
            typedef R(*CB)(MemberFunction<R(O*, A...)>, O*, A...);
            CB cb = &callback;
            funct = new Functor<R(MemberFunction<R(O*, A...)>, O*, A...)> (cb, MemberFunction<R(O*, A...)>(func));

        }

        void setParams (O* object, A... args) {

            params = std::make_tuple (object, args...);
        }
        void operator()() {
             ret = reinterpret_cast<void*>((*funct)(params));
        }

        bool operator== (Delegate& other) const {

            if (&dynamic_cast<FastDelegate3<R, O, A...>&>(other) == nullptr) {
                return false;
            }
            FastDelegate3<R, O, A...>& delegate3 = dynamic_cast<FastDelegate3<R, O, A...>&>(other);
            return *funct == *(delegate3.funct);
        }
        bool hasReturn() const {
            return true;
        }
        void* getReturn() const {
            return ret;
        }
        std::tuple<O*, A...> params;
        Functor<R(MemberFunction<R(O*, A...)>, O*,  A...)> *funct;
        void* ret;
};
template <typename R> class FastDelegate {
    public :
    FastDelegate () {
        delegate = nullptr;
    }
    bool operator!() {
        return delegate == nullptr;
    }


    template <typename O, typename ...A> FastDelegate(R(O::*f)(A...) const) {
        delegate = new FastDelegate3<R, O, A...>(f);
    }
    template<typename O, typename ...A> void setParams(O* object, A... args) {
        if (static_cast<decltype(delegate->getType())>(delegate)) {
            static_cast<decltype(delegate->getType())>(delegate)->setParams(object, args...);
        }
    }
    ...
};
 

I'm forced to do that so :
template<typename O, typename ...A> void setParams(O* object, A... args) {
        if (static_cast<FastDelegate3<R, O, A...>*>(delegate)) {
            static_cast<FastDelegate3<R, O, A...>*>(delegate)->setParams(object, args...);
        }
    }
 

But is everyone has an idea he's welcome. :)

« Last Edit: February 22, 2014, 12:16:08 pm by Lolilolight »