Jump to content
  • Advertisement

Polymorphic OOP

Member
  • Content Count

    835
  • Joined

  • Last visited

Community Reputation

954 Good

About Polymorphic OOP

  • Rank
    GDNet+
  1. Polymorphic OOP

    Do not lean on your pregnant wife

    Don't you see? If he kills his young, then he won't be spreading his stupid-gene to further generations!
  2. Polymorphic OOP

    Hooray for Evil Spilly

    you don't have a book
  3. Polymorphic OOP

    Sound Manager Coming Together

    Huge update concerning the inner workings of the sound managers I mentioned in my last update here, particularly for those interested in making their own personal implementations. Overview for those unbriefed: The purpose of the sound manager types, as explained in my previous post, is to provide a free and portable encapsulation of the concept of the play and management of 3d sounds and listeners in a C++ environment. The end result is a system for quickly and safely setting up 3d sound on a target platform without having to directly work with non-portable code. The idea is obviously nothing new to the world of programming. This particular application of abstraction is the basis for the 3d portion the FSOUND API of fmod, as well as OpenAL, only I'm taking it to an even higher level of abstraction. More low-level concepts are abstracted away, and, as well, initialization and destruction of objects such as sound generators are handled automatically through C++ objects, leaving little room for programmer error (since it's a C++ API, not a C portable API such as those I just mentioned). Since the abstraction is a layer above that of most other sound APIs, the implementation of a conforming sound manager can internally use DirectMusic and DirectSound, or OpenAL, or fmod, without impacting the standard external interface of the type. The most notable high-level feature in my proposed standard that is not a part of OpenAL or fmod include automatic management of sound generators based on user-defined priority types and comparison predicates. Anyway, for the passed couple of weeks, up until a few hours ago, I have been working with this idea directly as stated, towards an end result where I would have a group of types and templates that would be implementation specific, yet all share a common interface, such that you download an OpenAL implementation if you are working on linux or possibly the DirectSound and DirectMusic implementation if you were running windows. Each implementation just goes into the same namespace with the same type and template names. The problem, as I've realized for some time yet just accepted for some reason, is that this limits you to having one implementation installed on your system at any given time (unless you just change your include directory settings depending on the implementation you wish to use). The more I thought about it, the more I realized that this is totally unacceptable. It is very conceivable that one might want to have different implementations installed, and going further, one might even want to use multiple implementations in the same application, similar to having an engine which can optionally render with Direct3D or OpenGL. So, I decided to change the concept from a set of absolute types and templates in a common namespace with a standardized interface, to a pure abstraction concept, where not even the location of the object is standardized; they just must conform to the interface. The types and templates can exist anywhere and have any name. This way, multiple implementations can exist on the same computer. No revolutionary idea there, just a change in my approach. However, I also realized that the addition of a priority concept as well as the standard way I provide of handling the insertion of new generators in a saturated manager, could be completely and portably implemented on top of a much more simple pure abstraction than what I described earlier. Since all of the high-level functionality can be implemented via the interface of the provided abstraction, default implementations of the high-level priority and basic sound manager concepts can exist for any system by just being templated with one parameter representing the type which conforms to the abstraction to be used for implementation! This has some very powerful results. Now, implementing different versions of the sound managers is even more simple than I had planned. All the implementor must do is provide a very basic low-level abstraction and now those types can be directly used by the high-level templates without any changes. Further, if the internal API already allows things such as priorities, like fmod, there is nothing stopping someone from partially specializing the encapsulator template to take advantage of it (though in the case of fmod only integral priorities in ascending order are supported whereas in my implementation both the priority type as well as the comparison predicate are template parameters, so it would only be a partial specialization for integral types where the Predicate defines an ascending priority organization). Not only this, but that also brings back the fact that the overall types used are in the same exact namespace regardless of implementation, though now without conflict since you use the encapsulator types instead of the implementation-specific types. So now you have a common set of templates which exist in a standard namespace, have a standard interface, and even have a portable default implementation based off of a given pure abstraction that you can use portably with a provided underlying implementation (of which I personally will be providing a DirectMusic and DirectSound implementation as well as an OpenAL implementation)! So, as an example: namespace some_namespace { class openal_implementation { // Implementation whose interface // conforms to the standardized // simple, low-level pure abstraction. }; } namespace audio_library // I haven't decided on a namespace name yet { template< typename PureAbstraction > class basic_sound_manager_3d { // Default implementation uses // the provided pure abstraction. // This version doesn't use priorities. }; template< typename PureAbstraction , typename PriorityType = unsigned int , typename PriorityPredicate = ::std::less< PriorityType > > class sound_manager_3d { // Default implementation uses // the provided pure abstraction. // This version uses priorities. }; } int main() { audio_library::sound_manager_3d< some_namespace::openal_implementation > sound_manager; } Aside from this, I have also developed what I feel is the best way to handle extensions for the managers. This is, again, nothing revolutionary, though I feel it is important that I standardize the concept for the project. Since different audio APIs provide different ways of dealing with certain concepts which can't necessarily be universally translated between, such as environmental effects and lower-level audio effects, it becomes necessary to expose those interfaces in the high-level encapsolator. The problem is, since I made the high-level encapsulator have a default implementation that I want people to be able to use even if their implementation has extensions, how do I create a way of exposing all of those extensions through the encapsolator types? Here is the solution I came up with: For the case of functions which have a high-level implementation that internally must call the lower-level version as a part of the process (IE initialization), there is an extra type at the end of the function parameter list which is declared in the low-level implementation type (I described this in my previous post). The argument must have a default value to conform to the standard. If someone needs to pass implementation-specific initialization information (such as a window handle), then they just explicitly pass the parameter. Again, this is simple and nothing special, but succeeds at providing a way to expose internal initialization without changing the implementation of the high-level encapsulator template. In cases where there is no high-level function that corresponds to low-level extensions, such as specific effects applied to sounds, an "extension" member function template is used. This function is an instantiation of a template whose sole template parameter is a tag type which specifies the extension being used. If the extension is supported then the function is defined, otherwise, the user will get a compiler error (which is good). Right now, I am leaning towards using SFINAE to allow the functions to actually take the amount of arguments required for the extension, however, since lots of compilers do not fully support the proper use of SFINAE, I may end up having the function always take one parameter and rely on explicit specialization instead. So, for example, to use an I3DL2 extension for environmental effects on a sound generator with a compiler that has fully compliant SFINAE support, you'd simply do something like: your_sound_generator.extension< I3DL2_extension >( all , of , your , parameters , go , here ); The corresponding code for a non-SFINAE compliant compiler would just pass a structure with all of the parameters. What's good about this design is that since it uses a compile-time tagging system and since the varying implementations are known at compile-time, you will get an error at compile time if the extension you are attempting to use is not supported rather than finding out at runtime. That's it for now. Any ideas are welcome and feedback is appreciated.
  4. Polymorphic OOP

    Hey look!

    I LOVE IT! WHERE DO YOU COME UP WITH THIS STUFFF!!?!!!111
  5. Polymorphic OOP

    Holy crap

    do you have stairs in your house?
  6. Polymorphic OOP

    ATL? COM on!

    Thanks. Also, going back to the audio -- I have decided to allow multithreading, however, not via a template parameter. Instead, in order to get a multi-threading safe version of the sound manager, you use a metafunction. The reasoning for this is it makes it possible to create a metafunction that is capabable of making literally any implementation multithreading-safe via encapsulation using a portable multithreading library (IE boosts multithreading sublibrary). This way, if someone needs to get a multithreaded sound manager up and running but wants to use some sound api other than ones used in implementations I provide, they can just make a single-threaded one and use the default metafunction implementation to produce a multithreaded version automatically. As well, if you need to make further optimizations that the default metafunction can't provide, this also allows people to make implementation specific multithreading-safe types via partial or explicit specialization as well, so you get the best of both worlds. The only problem with this is that the new type would be unable to forward implementation specific parameters to member functions. Possible ways around that would be either standardizing the way of making implementation specific parameters of sound manager functions via packet types on the ends of functions specific to implementation (so all extra parameters of a single type would be in an implementation-defined type for that function with default initialization) or by making any implementation-specific functions required to be implemented as separate nonmember functions. Right now I'm leaning towards the latter solution, though that could cause innefficiency if a compiler doesn't take advantage of the named return value optimization in the case of constructors which require implementation specific parameters. Anyway, so making a manager multithreading-safe without individual sound manager implementations having to manually make multithreaded implementations could be as easy as: make_multithreaded< sound_manager_3d< some_priority_type > >::type your_multithreaded_sound_manager_3d; //Where sound_manager_3d is declared as // template< typename PriorityType, typename Predicate = ::std::less< PriorityType > > // class sound_manager_3d;
  7. more like mushu rice am i lite
  8. Polymorphic OOP

    General Info About Me

    Hi Stoffel, your guts are okay with me!
  9. Polymorphic OOP

    ATL? COM on!

    Thanks. I have almost all of the interface of the sound manager layed out already such that it could very easily be ported to use other audio APIs -- portability and standard compliance are my biggest concerns when putting together a library. Currently the only thing not portable is initialization, since internally you should be passing a window handle when initializing a DirectMusic performance (though even that defaults to 0, which is valid though not recommended). As well, another feature I am currently supporting, but haven't decided if it should be standard to the library across implementations or not, is an option for multithreading (since it's very conceivable that one might want to use the same sound manager across multiple threads). If I decide to make it standard, I will probably implement multithreading as a partial specialization via a bool template parameter for whether or not the functionality is desired. Either that or I may make the multithreaded version a standardized extension that is optionally supported by an implementation. If that were the case, I'd just set up the multithreading switch as the last template parameter which defaults to false (false meaning singlethreaded) and is optionally not defined for when the value is true. Checking whether or not multithreading is supported would be available via a standardized compile-time metafunction. The only other potentially non-portable part which I haven't yet implemented, though have definately though about doing it if I get around to it, is to allow people to provide a custom DirectMusic loader so that they can load up user-defined audio formats if the need exists (a functionality of DirectMusic which I personally haven't even used). The only problem with that is it would be pretty difficult to abstract away to the point of being portable, so I probably wouldn't even make it a standard extension - just something unique to the DirectMusic implementation. Anyway, whenever I get a fully working, partially tested version of the DirectMusic/DirectSound based manager, I'll upload it along with documentation as to what I'd prefer to be standard to all implementations. Since I plan on working on other projects as well, I'll probably just only implement one version myself (and maybe an OpenAL version, though I've never done any programming with OpenAL before). Other than that, I'll leave it up to the community to make and upload conforming implementations (if people actually use it, of course). So, if you want to implement it with libraries other than DirectMusic and DirectSound, you'll be happy to know that I'll try to make it as smooth a process as possible. Thanks for your interest!
  10. Polymorphic OOP

    ATL? COM on!

    Yes, I have thought about this before and I definately agree with your assessment but have decided to continue. A total switch to managed code is still quite a ways off, with longhorn still a couple of years until expected release, and as well, a lot of the concepts carry over in a more general sense than things such as COM object lifetime management. At this point in time, and predictably at least for the next two years, there are many misconceptions that people have with COM, particularly those who are jumping into C++ with DirectX having potentially no previous COM experience. Initially, many concepts can seem confusing and prone to error while other aspects can be unnecessarily tedious concerning the provided level of abstraction. It all can seem needlessly intimidating to the point where newcomers can be so turned off that they'll leave their current project or look for a different solution. I've seen several programmers give up with Direct3D in favor of OpenGL because of it. Anyway, glad you're showing interest, and thanks for the feedback!
  11. Polymorphic OOP

    ATL? COM on!

    Don't stop reading yet -- while the first paragraph of this post is my obligatory praise of Gamedev.net, I am also foreshadowing a future article I plan on writing which will probably be of use to many of you out there -- particularly those who work with COM (IE DirectX) in C++, and some bonus information about a library I'm working on to make 3D audio simple to work with and manage in a complex simulation. So keep reading! Ahh, my first developer journal post. Fun stuff, eh? I love the way Gamedev is headed with their GDNet+ membership and everything it provides. I will be using this journal for talking about any projects I am currently working on, and will also be using it to get feedback on where people wish me to direct my attention in future projects. I am very open to suggestions and am willing to develop just about any library that would be useful for many types of projects that plenty of developers can benefit from (within reason -- IE I'm not going to program the next Unreal engine... and if I did, I wouldn't upload it here ;). Anyway, my first order of duty here is to provide the community with an article that I personally feel is almost a necessity to anyone planning on or currently working with DirectX, or any COM library for that matter, in C++. The planned title is something along the lines of "Why ATL's CComPtr is helpful and why you should never use it," which may give you a general idea of the direction I'll be taking. With the article, I will be talking about why smart pointers are extremely useful when working with COM and why Microsoft's ATL COM smart pointer templates get it wrong in some areas from a C++ programmer's perspective. In addition, I will provide a suggested coded solution for what ATL attempts to provide, along with C++ wrapper functions and objects for Microsoft's procedural COM library featuring exception throwing instead of HRESULT returns and an easier method for dealing with factories. As well, I will also provide exception safe copyable objects for dealing with COM construction and destruction which allow you to easily determine if the COM settings in your current thread are acceptible for your application (which normally can be quite a hassle). So, hopefully I'll be able to bring you some info that you may not have known about COM, or perhaps knew yet didn't give much thought as to how it should impact your development. For those who are interested, be warned that I use a lot of advanced C++ template features, particularly a reliance on the SFINAE principle in conjunction with partial specialization. While everything I do is 100% standard C++, some compilers may have trouble with them. My current target for these libraries is Microsoft Visual C++ .NET 2003 as most people who work with COM are working on a Microsoft compiler to begin with, coupled with the fact that their template support is very compliant (for instance, I know that if I port the code to be used with GCC I will have to make some work-arounds for G++'s partially broken SFINAE implementation). So, anyone who is interested in this project, please let me know. I'm happy to answer any questions you may have and would be willing to take suggestions both for the planned article as well as ideas for the project and even future projects. My next project (which is already pretty far along in development) is a complete 3D sound manager built around DirectMusic providing facilities for loading sounds and creating generators positioned and oriented in 3D. Supported features include everything that DirectMusic can provide through DirectSound, particularly environmental effects, doppler effects, manual pitch and volume adjustments on both a persound or pergenerator basis, etc. The more abstract feature, and potentially the most useful, is the ability to set the maximum amount of active generators available as well as the ability to create any amount of generators you wish coupled with user-defined priorities (the type of which you can specify through a template parameter making customizability to your application a snap). The manager will automatically move your extra generators into and out of the active generator container based on what priority they have, so you can have lots of objects in a level and have a very simple way of ensuring that the most important sounds (usually the closest sounds or explosions, etc) always get heard without having to manually deal with the intricacies of managing activation and deactivation of generators. The order of an operation which switches the priorities of an already created generator is proportional to log(n), where n is the amount of different priority values that are currently being used. For speed purposes, there will also be a form without priorities that is slightly more optimized than having a manager with priorities where all the priorities are the same. Of course, the latter's uses are much less general than the former. Due to the nature of this project, I'll probably upload it along with documentation, but not make an article about it (unless, of course, I get enough positive feedback to warrant one). Also, just so I can see if people (and which people) actually read this, please leave a comment of some sort -- even if it's just to say hi. Thanks.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!