[SoC 2009 - Accepted] Unified Samples Framework & Browser

Threads related to Google Summer of Code
Post Reply
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

Oh, alright. I see that it might be a hassle for samples to specify requried resource groups. It was part of the proposal since quite early on though, so I thought it was okay. I suppose my original motivation is no longer relevant, since the overhead from parsing all the samples' resources would only happen once on the browser startup. In the old framework, this overhead was there every single time a sample was run. So I think the best choice now would be method A. Samples load resources without forward declaration, and unreferenced resources are unloaded after sample termination. This however means that all samples must be fully responsible for cleaning up after themselves. Or should the SampleContext somehow ensure that samples never interfere with one another?
User avatar
Kencho
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4011
Joined: Fri Sep 19, 2003 6:28 pm
Location: Burgos, Spain
x 2
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Kencho »

Well, I see both 1 and 3 can coexist in a practical way. When a sample is announced to the framework, it might optionally provide a list of required resources. The framework would then load them if they aren't already, and release them if they're no longer needed (as in #3). Those not included in the list just would fall in the manage-them-yourself (reload-friendly) approach of #1.
Image
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

I gave this a bit of thought, and I decided to go with method #1 after all, and to remove tabbing from the feature list. I really liked Kencho's idea of a hybrid system, but a couple of things tipped the balance in the end:
  • We want to make this framework extensible, not all-inclusive. It should have just the features necessary for the OgreSDK and no more, while being easy to take apart and add new functionality to. The samples in the SDK are not particularly resource-heavy, and the overheads I wanted to avoid were minimal in the worst cases. If needed though, it shouldn't be too much work to extend the framework to have the features I mentioned before through inheritance and virtual methods. Maybe I'll even write an article in the Wiki for it when this is done.
  • Multiple tabs are cool and all, but they'd probably bring more trouble (addition of a SampleInstance class, more complicated interface, difficult resource management, etc.) than they eliminate. Having a browser already makes it much faster/easier to switch between samples than before anyway, so the speed gain of having multiple loaded samples would be minimal.
  • The division of the framework into separate components already makes the new framework more complicated than the old one. Adding all these features would simply overcomplicate the system and make it even harder for people to jump right in - which is sort of the point.
Last edited by omniter on Wed Apr 29, 2009 5:44 pm, edited 1 time in total.
User avatar
Kencho
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4011
Joined: Fri Sep 19, 2003 6:28 pm
Location: Burgos, Spain
x 2
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Kencho »

Good points :) *thumbs up*
Image
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by sinbad »

I agree. I didn't want to necessarily push you in a direction here, but more to think really carefully about the trade-offs, because in the end, every design decision is a trade-off, there are no universally good designs! I think given the context and the primary goals of this system, this is the right decision. It's the kind of thing to keep in mind for later maybe, because as a secondary goal it's still valid in concept to reduce unneccessary parsing of scripts particularly, but it's an open question whether that can be effectively done without introducing the kind of complexity that will undermine the primary goal of making it easy to add new samples.
Hirni
Gnoblar
Posts: 2
Joined: Mon Nov 06, 2006 11:30 am
Location: Vienna, Austria

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Hirni »

I think this project is an excellent idea. I teach real-time graphics and I am using OGRE wherever I can to show different effects such as showing the difference between shadow algorithms
or screenspace effects. A browser would facilitate the usage of OGRE in teaching, especially if one could attach additional images or descriptions. Just wanted to note that this would also be an application of such a framework.
User avatar
xadhoom
Minaton
Posts: 973
Joined: Fri Dec 28, 2007 4:35 pm
Location: Germany
x 1

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by xadhoom »

Hirni wrote:A browser would facilitate the usage of OGRE in teaching, especially if one could attach additional images or descriptions. Just wanted to note that this would also be an application of such a framework.
I´m not sure if this GSoC project can satisfy all your needs but just for information there is currently an Ogre editor in development which may soon be able to do most of the things you mentioned.

http://www.ogre3d.org/wiki/index.php/Ogitor

xad
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

If Hirni wanted to do something like what he mentioned (demonstrate the differences between shadow algorithms or screenspace effects), then the only part the scene editor would play in it is to setup the shadow casting objects in the scene graph. There's still the actual shadow technique switching code and the GUI controls. Ogitor might allow changing things like shadow technique from within the editor, but in this case we want it to be an inherent feature of the sample, not of the tool that's displaying it.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by jacmoe »

Would be cool to have a kiosk mode, though! :)
For things like demoing or showing off..
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

jacmoe wrote:Would be cool to have a kiosk mode, though! :)
For things like demoing or showing off..
Sounds interesting, but I'm not sure I understand. :) Are you talking about the browser, or Ogitor?
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by jacmoe »

It was just a wild thought. I meant the browser, of course. (Wouldn't dream of hi-jacking) :)
Kiosk mode would require pre-recorded demos, though..
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

The first week's tasks are now done. :) And as expected, I made some new design changes/decisions.

In the past, when creating a new sample, you needed to make an ExampleApplication subclass and an ExampleFrameListener subclass, and override the createFrameListener method of ExampleApplication to add an instance of your ExampleFrameListener subclass. In the new framework, I've decided to make the Sample class a subclass of FrameListener and WindowEventListener. There's one main reason for this decision (aside from being more convenient): The typical response to any event is a modification to the sample. Thus it would make sense that the callback methods have direct access to the objects they are trying to modify. In the current SDK samples, such objects are either passed from the ExampleApplication to the ExampleFrameListener through an overloaded constructor, or declared as a global variable accessible by both classes. This is confusing, difficult to make changes to, and just doesn't make much sense design-wise.

With this new design, a problem arose when I thought about the browser's in-game menu again... How on Earth do you add a common element to all samples? The solution was to make SampleContext a subclass of FrameListener and WindowEventListener, just like Sample. At first this idea seemed strange, but slowly it made more sense. With this solution, the SampleContext is essentially able to act as an overarching "supersample" of sorts. I expanded on this idea, and made the SampleContext methods virtual. Now, SampleContext is intended to be subclassed to provide common elements / event-handlers for samples. For example, you can extend the class to display a logo splash-screen before every sample, give every sample a time-limit, or even add a developer console, or in the case of the browser, an in-game menu. This also means that you can write a Sample class once, and make it either stand-alone or pluggable into the browser (or any other context) without making any changes to the code (as long as keyboard shortcuts don't conflict, or something trivial like that). :)

SampleContext and Sample will both have their own methods for locating and loading resources. This provides a very flexible system. You could have the SampleContext parse all resource groups from a config file, or have each Sample load its own resource groups, or a combination of the two.

As a result of these decisions, things like the browser menu and resource config file are specific to a certain sample context, and not part of the framework itself. This makes the framework more light-weight and flexible.

Currently, using the framework to create a stand-alone sample looks something like this:

Code: Select all

class MySample : public Sample
{
    ...
};

SampleContext sc;
MySample s;
sc.go(s);
As you can see, it's quite similar to the old framework. You can also run a blank window if you don't pass anything to SampleContext::go. You can change samples with SampleContext::switchSample from a callback.

I placed all the classes under a new namespace "OgreBites" (which is also the nickname for the browser). The class names seemed a bit too short and/or generic to not have a namespace, and I didn't want to put something non-core under the "Ogre" namespace. Of course this is just an idea. If you guys think it's a bad one, let me know.
Last edited by omniter on Mon Jun 01, 2009 1:49 am, edited 1 time in total.
User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
x 3
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Praetor »

All of this sounds reasonable. Design changes are expected as you continue on with it. I'll be checking out and looking a what you committed this week. I'll probably have more to say once I've actually seen what you committed.
Game Development, Engine Development, Porting
http://www.darkwindmedia.com
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

Finished writing the Sample class and integrating it with SampleContext. Some changes/notes:

Sample class now has an unloadResources method in addition to locateResources and loadResources, for unloadig resources on a per-sample basis. It currently iterates through all resource managers and calls unloadUnreferencedResources on them. SampleContext does not have this, because unloading of context-wide resources is done on context shutdown anyway.

The Sample class has the methods start, reset, and stop. Reset basically clears the scene and calls setupScene again. This can be overridden, of course, to reset custom variables. The roles of start and stop are outlined in the summary at the bottom.

Platform-specific methods for changing the window's title (for example to each sample's name) are planned.

The Sample class must be given a pointer to a RenderWindow through its start() method. This is done automatically by SampleContext's switchSample method. This was the only way to give the Sample class access to the RenderWindow (for handling window events, manipulating the viewport, or updating the window manually for loading bars) without assuming that the RenderWindow was automatically created (in which case we could use Root::getAutoCreatedWindow), or passing the context itself to the sample (which requires Sample and SampleContext to use each other, which in turn would spoil the hierarchical design).

There will be no methods like processUnbufferedKeyboardInput or createCamera. Methods like these, in my opinion, were big limitations of the original framework. Yes, the sample framework does by nature impose certain limitations on the design of the application, but other limitations should be avoided for the sake of flexibility. What if the user wanted a different camera setup with, for example, multiple cameras? What if the user wanted to check for a keypress + mouseclick combo? Wouldn't it make more sense in that case for keyboard and mouse input to be handled by the same method? For these reasons, I decided to leave the "update loop" of each sample in its raw form as FrameListener events (frameRenderingQueued, frameEnded, etc.). The SDK samples can themselves use a specific setup for processing input / updating the scene, but the framework doesn't need to. The framework also makes no assumption that a sample uses a default camera, or a camera at all, or even a viewport, for that matter. It only assumes the use of a RenderWindow. This means that samples can have any kind of viewport / camera setup. Basically, when it comes to the scene, the framework will give you a blank slate (and a default viewport, so you don't have to make one). Of course, as one of the framework's goals is to be convenient, I'm planning to make a SampleCamera class or something similar which will simplify the process of setting up and controlling a camera. Current ideas include preset camera movement modes, customisable keys, speed and acceleration.

Here's a quick summary of how the framework currently operates:
  • User instantiates a SampleContext or a subclass.
  • User extends Sample, which usually involves overriding the setupScene method, the FrameListener events and, in special cases: testCapabilities, locate/loadResources, and chooseSceneManager. This is done for every sample.
  • User instantiates each Sample (or subclass).
  • User calls SampleContext::go, passing in an initial sample.
  • SampleContext configures settings, creates window, sets up OIS, loads context-wide resources, and adds itself as a FrameListener and WindowEventListener. Any error in this part results in program termination.
  • SampleContext switches to initial sample, or a blank if none is provided, via switchSample. This method does the following:
    • Call current sample's quit method, which does the following:
      • Set finished flag to true in case of termination by third-party.
      • Remove self as FrameListener and WindowEventListener.
      • Destroy scene manager.
      • Unload sample-specific resources.
    • Reset RenderWindow's viewport layout to a single default.
    • If the new sample is null, set it to be the blank sample.
    • Call the new sample's start method (passing in the RenderWindow), which does the following:
      • Perform a capabilities test.
      • Locate and load sample-specific resources.
      • Create a scene manager.
      • Setup scene.
      • Add self as FrameListener and WindowEventListener.
      • Set finished flag to false.
    • Set the new sample to be the current sample.
    Any error encountered in this part may be caught and handled by an extended SampleContext (for example, fall back to main browser menu).
  • SampleContext starts render loop.
  • SampleContext performs following checks on a per-frame basis:
    • If the window was closed, terminate the loop.
    • If a sample has ended, switch to a blank sample.
  • SampleContext shuts down everything.
A Sample's start and quit methods should not be used manually. To change sample, use SampleContext's switchSample method instead. For a Sample to mark itself as finished, simply set the mDone flag to true. Alternatively, you may exit the render loop altogether by returning true from a Sample's frame event handler.

Lastly, just to emphasise a couple of things:
  • The Sample class contains only the sample-specific aspects of the framework, and it is thus named. It is a very lightweight class.
  • The framework itself contains no content of any sort. It does not have any kind of default GUI, font, textures, logo, FPS display, etc. These things, however, will be distributed with the SDK, and used heavily by the browser, and may be used easily with the user's own samples. The point is that these things are not necessary for creating a bare-bones sample. The framework handles setup and sample management, but that is all.
That's it for now. Please feel free to give me some feedback, guys. :)
Last edited by omniter on Mon Jun 08, 2009 7:43 am, edited 1 time in total.
User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
x 3
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Praetor »

Looks on track. The SampleContext and the Sample seem like a solid state machine system. It's good to keep in mind both flexibility and ease of use. Your strategy for this is probably best: keep the core framework 100% flexible, and then provide defaults and standard implementations that can be used for convenience. From what I can see here I think the project is right on track. Great work.
Game Development, Engine Development, Porting
http://www.darkwindmedia.com
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

Week 3 is finished. OIS support was added, and pluggability testing was done. And of course, as you probably guessed, there are a couple of design changes. Don't worry, it's nothing too drastic this time.

First of all, let's talk OIS. By default, the new framework only creates an unbuffered keyboard and mouse. These are what I consider the bare minimum. The SDK samples don't even use joystick control, so why create a joystick device by default? Also, the old framework had an ExampleFrameListener whose constructor had a whole bunch of different arguments which, among other things, allowed you to choose between buffered and unbuffered input. For the new framework to provide this option would require the SampleContext to basically relay a whole bunch of args from go() to setup() to setupInput(). It just seems kind of silly. Instead, I created a new method, createInputDevices(), which only creates the devices (a mere line of code for each device). This way, the user can easily extend this method for new devices / modes. The idea is that a fixed characteristic of the context should come from inside the context, not an external parameter. Besides, input mode is specific to your context class, not to each instance of it, so why put the option in the constructor? Just extend the class and hardcode it.

From this same idea, I realised that the Sample class constructor doesn't need to take a name either. I mean, one sample is never going to have two instances with different names, nor are samples going to ever change their names. So now, the getName method can simply be extended to return the sample's name. This change also comes with the benefit of not having to store a string for each sample.

I added a sample queue to SampleContext. The basic effect is that you can now give the SampleContext some "next steps" ahead of time. An obvious use for this is to make a sort of sample playlist. You no longer have to provide an initial sample to the go() method. Simply queue up a sample (or two), and call go(). As before, you can still switch to another sample without altering the queue. The method you use to do this is now called runSample instead of switchSample. There is also runNextSample, skipNextSample, queueSample, clearSampleQueue, getNumQueuedSamples, and getNextSample. If a sample ends by itself, the context will shutdown instead of switching to a blank sample. Similarly, if the sample queue is empty when go() is called, then the render loop won't even start. The context will shutdown right after it starts up (you'll see a black render window pop up and then disappear). This isn't to say you can't manually create a blank sample, of course.

Finally, let's talk pluggability. I made a utility SamplePlugin class, which is basically an OGRE Plugin extended to have a list of samples, an addSample method, and a getSamples method. One should extend this class to create and add samples to the list in its install() method, and to destroy the samples in its uninstall() method. Then, you put it in a dll like any other OGRE plugin, installing it from dllPluginStart, etc. After that, you can get access to the plugin through the Root object, cast it, and then call getSamples() to retrieve its list of samples. This is by no means the only way or even the best way to plug samples into your application with this framework. You might even not use an OGRE Plugin at all and choose to load the samples from a dll directly. In any case, the SamplePlugin class is just a utility to be used by the SDK to demonstrate the framework's pluggability. Ultimately, the SampleContext just expects a Sample pointer - it doesn't care where it was made or how you got it. There is one limitation of this class though - like all OGRE plugins, it can only be installed by a valid Root object. This means you cannot extract samples from a plugin and queue them up before calling go(). You can however extend the context to scan and load sample plugins after setup, and that is exactly what the browser will do.

That should be it for this week. Please feel free to check out the source from branches/soc09-samples and try it out yourself. Next up is dynamic graphics configuration and custom sample data. Look out for sample code and screenshots next week, because I'm gonna write test apps!

Cheers. :)
Last edited by omniter on Sat Jun 20, 2009 8:39 am, edited 1 time in total.
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

Update time!

Dynamic configuration was a real pain, but I think I've reached a solution I'm comfortable with. Basically, the SampleContext will provide the means to reset the root / window with a specific render system and a set of startup options. This basically replaces the initial restoreConfig or displayConfigDialog. This already effectively allows for "dynamic configuration". It's just the back-end, though. It's up to you to display the options to the user, collect his input, and provide it to the reconfigure method. This is easy - just use Root::getAvailableRenderers to get a list of renderer systems, and use RenderSystem::getConfigOptions to get a render system's list of options, and use ConfigOption::possibleValues to yada yada yada... It really doesn't make sense to put this part in the framework, because it requires some kind of user interface, and as previously mentioned, user interfaces will only be provided through the browser and samples. Also, the options people choose to expose may vary greatly. Now for some implementation details:

What used to be just the setup method is now split into three methods (in order): createRoot, oneTimeConfig, setup. createRoot only handles the creation of the root. oneTimeConfig only happens the first time you setup the context, and you would usually use Root::restoreConfig or Root::showConfigDialog for this. setup covers the actual setup of the context, with the given configuration. There is a new reconfigure method, which takes the name of a render system, and a NameValuePairList of render system startup options. First, the current sample state is saved (I will discuss this shortly), and the sample is quit. Then, shutdown is called, the root is recreated, and this time, instead of calling oneTimeConfig, manual configuration takes place using the values passed in. Then setup proceeds as before. Finally, the sample is restarted and its state is restored.

Sample state saving is optional, and provides a means to save off your camera position, slider values, and other objects of interest. Basically each sample has a saveState and a restoreState method, both of which take a NameValuePairList.

This all seems rather complex right now, but in practice, it's actually quite simple to use. For example, if you wanted to turn on VSync and turn off FSAA, and use OpenGL, just make a NameValuePairList called rsOptions, add a pair <"VSync", "True"> and another pair <"FSAA", "None">, then call reconfigure("GL Rendering Subsystem", rsOptions). That's it, done. If you provided saving and restoring methods for your Sample, you will basically see your window disappear and reappear with the new settings you requested, and your sample will be as you left it. Call Root::saveConfig if you want these changes to persist.

Some config options like dimensions and full screen do not need a context reset. You can simply use RenderWindow::resize or RenderWindow::setFullscreen. However, if you do this, you're only changing the window's properties, and not your render system's startup settings. You'll have to set them manually according to what you've set for the window. This is when it becomes quite a pain, since each render system uses a slightly different notation. To remain flexible and minimal, the framework itself will not help you with this task. However, in the browser, I will provide a full in-game configuration screen with all the code you need.

Sample::start now takes an Ogre::RenderWindow*, an OIS::Keyboard*, and an OIS::Mouse*. These are the three main objects provided by the context to the sample, and they are saved for future use. I kind of just forgot to add the keyboard and mouse the first time, whoops. :oops:

Sample::testCapabilities is no longer protected, but public, and is no longer called by Sample::start. The reason for this is that I want the Sample to just worry about running its content, and not performing tests that the user may or may not want to run. Same goes for two new methods: Sample::getRequiredRenderSystem, and Sample::getRequiredPlugins. None of these things are checked by the Sample itself. If you run a Sample without the necessary plugins, render system, or capabilities, you will just get an exception. It's up to you to run these tests when you deem necessary. It's your job to make sure a Sample can run when it is run. Another reason for this decision is because I want the browser to be able to mark certain samples as "out of order" and give the reason before the sample is even run. This means the browser has to perform the test beforehand, so it doesn't make sense for the sample to perform a test that has already been performed by the browser beforehand. Yet another reason for this decision is that you can now decide what to do with the test results. For example, you can choose to automatically switch to the required render system, or ask the user if it's okay. You can also give the user helpful hints on how to make the sample functional.

Seeing as how this part of the week's work is done, and I start making the actual browser next week (Yay! :D), I see no point of making a bunch of test apps which will basically test what the browser will be used to test anyway. Thus, I will start the browser early, and save the tests and screenies 'til then.

And finally, I leave you with another idea for possible applications of this framework. OGRE Add-on developers can make their own samples viewable in the OGRE sample browser. For example, to make a physics sample, you just have to extend Sample::start to setup physics-related objects, and Sample::quit to clean up. Then it's just a matter of adding collision callbacks, and setting up the scene with bodies, etc. You don't even have to touch the SampleContext - it's just another sample. Of course, it would also be cool if an Add-on made its own separate browser. That way, you can have one browser for regular OGRE samples, one for physics, one for 3D sound, etc. Anyway, just a thought.
Last edited by omniter on Sat Jun 20, 2009 8:37 am, edited 1 time in total.
User avatar
Noman
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 714
Joined: Mon Jan 31, 2005 7:21 pm
Location: Israel
x 2
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Noman »

Nice work!
Of course, it would also be cool if an Add-on made its own separate browser. That way, you can have one browser for regular OGRE samples, one for physics, one for 3D sound, etc. Anyway, just a thought.
This one got me thinking a bit. In terms of ease of use, wouldn't it be nicer to take a different approach - a hierarchial sample browser? If each sample would classify itself in a category (this can even be done with '/' separation in the name of the sample), it would be possible to logically separate between different sample sets, while still being able to access them from the same menu.

I think it might be a good idea even for ogre's core - there are many samples today, and its easy to get lost looking for something. Subcategorizing them (into, for example, Animation / Procedural Content / Environment / etc) would be pretty nifty...
Do you have anything similar to that planned? Couldn't find it in the wiki...
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

Thanks Noman! It's always good to have input like this. I never thought of making it easier to find samples, but now that you mention it, it would be quite a nifty thing to have. Here's another idea: Instead of categories, how about letting each sample specify some tags like YouTube videos? You could then see which tags each sample has, and click on a tag to list all samples with that tag. In my opinion, it would be difficult placing each sample in one single category. You'd need to make very good categories that don't overlap, and aren't too general or too specific. There's also no way to change which category a sample belongs to without recompiling. If you wanted to change the name of one category, you'd have to recompile all the samples within that category. With tags, you can search for samples, just as you search through E-mail or online videos. What do you think?
User avatar
Noman
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 714
Joined: Mon Jan 31, 2005 7:21 pm
Location: Israel
x 2
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Noman »

Its up to you, really.

I think a 'tagging' system is a bit overkill for this, but its a matter of opinion. I like how the Havok SDK subcategorizes the demos. When I was searching for inverse kinematics examples, it was easy to find the demos because they were all under Animation/API/Inverse Kinematics.

Tagging makes it easier to find something if you know what you're looking for. But if you're browsing, i think categorization makes it easier to understand what is available in the engine, for example.

But, its your project. Tagging is legit too...
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by CABAListic »

I would also prefer a category-based browsing mode. But there's no rule against having a sample listed in several categories, if more than one apply :)
User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
x 3
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by Praetor »

Sounds like you figured out the config issues. That's good. I can see, and definitely understand, the pain of being able to change some config options while running. Settings on options like vsync and fsaa are properties on the rendertargets themselves. This may be why sinbad originally suggested using custom windows instead of the auto-created one. With a custom, external window, you could simply detach the render target and then create a new one with the new options. It would mean not having to shut down the entire system. I'm not necessarily suggesting you rip out the system you built up, but now I definitely understand the issues a lot better than the last time we spoke. Good post and keep up the great work.
Game Development, Engine Development, Porting
http://www.darkwindmedia.com
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browse

Post by omniter »

Tons of changes this week! Where do I begin...

Changes to Sample

There's no more getTitle or getDescription. These are two pieces of information used by a specific type of context (the browser). A sample that runs on its own would never need a description, for example. These pieces of information are now placed in the sample's custom info structure, and may be retrieved via Sample::getInfo. Using custom info means that samples don't have to inherit from some special "browser-compatible" sample class in order to provide this information. There's now a setupView method for setting up the viewport(s) and camera(s). There's also optional preSceneSetup and postSceneSetup methods for setting up things before and after the scene is set up, respectively. This may come in useful for loading special configuration files or setting up custom GUIs without having to completely extend the _start method. Similarly, there's a finalCleanup method for any non-scene and non-resource cleanup. Sample is no longer inherited from FrameListener or WindowEventListener. Instead, it just provides the same virtual methods as these two classes. The reason for this is that when both the SampleContext and the Sample register themselves as listeners, the order in which their callbacks are fired is indeterminate. This turned out to be quite dangerous, and caused some funky bugs that took forever to track down. Now, only the SampleContext is registered as a listener, and its callbacks in turn call the Sample's corresponding callbacks. This guarantees stable and predictable behaviour. Sample also now has the virtual methods of OIS::KeyListener and OIS::MouseListener - see changes to SampleContext.

Changes to SampleContext

Callbacks now call their corresponding Sample callbacks to guarantee correct order of execution. Input is now buffered by default. SampleContext is registered as a KeyListener and a MouseListener, and its callbacks call their corresponding keyboard and mouse callbacks in Sample. Buffered input allows processing of key presses and releases as opposed to just querying of key state. This means no more mTimeUntilNextToggle. Hallelujah.

Changes to SamplePlugin

SamplePlugin no longer needs to be extended. You just instantiate it by passing in a unique name, and then add samples to it. It doesn't need to do anything on install, initialisation, uninstall or shutdown. The samples are not created by the SamplePlugin, but by the dll itself, and then added to the SamplePlugin.

Addition of SDKSample

Sure the Sample class is minimal and flexible, but it makes it a pain to create regular SDK samples, even with utility camera classes and what not (you'd still have to create the camera controller, pass it key events, save off camera position, and what not). There'd be a lot of common code being rewritten for every SDK sample. That's not good. So, I created the SDKSample class, which inherits from Sample, and will be subclassed for all SDK samples. It currently creates a default viewport and camera. In time, it will have different camera modes, camera controls, a debug overlay, a loading screen, etc.

Work on Browser

The browser reads Samples.cfg, which has the same format as Plugins.cfg. It then loads all the sample plugins and extracts all the samples from them. An error is thrown if a loaded plugin is not a SamplePlugin. A sample's title, description, category and thumbnail are all provided through the sample's custom info structure. There is currently no categorisation taking place, and no menu created, so the current behaviour (for testing purposes) is to queue up every sample loaded. Instead of a Bootstrap resource group and a General resource group, there is now a Browser resource group and a Common resource group. The Browser resource group specifies all the resources required by the browser to run. This includes OgreCore.zip, OgreBites.zip, and a sample thumbnail directory. The Common resource group will contain the most commonly used resources. Currently, this is the same as the original General resource group. As more samples are added to the browser (especially ones with numerous resources specific to them), it would not make sense to initialise all of these resources during browser startup. Instead of calling initialiseAllResourceGroups, the browser now initialises only Browser and Common, and any samples that would make a significant contribution to startup time can initialise their own resource groups in Sample::loadResources.

Sample Code and Screenshots

... huh? How about a video instead?


Next week's job is the browser menu (and some other stuff that goes on behind the scenes). :)

P.S. Random Idea: Another thing you could create with the new framework would be an 3D screensaver application. Instead of a photo slideshow, it could be a slideshow of different samples. You could add/remove samples, choose the order, shuffle, speed, etc. You could even use RTT to create transitions. This way, people could easily make and distribute cool OGRE screensavers (or screensaver packs, since one dll can hold more than one) as sample plugins to this OGRE screensaver program.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by sinbad »

Sorry for the slow response, travelling this week!

Code is really starting to shape up, looking great. The video was a nice touch too!
User avatar
omniter
OGRE Contributor
OGRE Contributor
Posts: 424
Joined: Thu Mar 19, 2009 8:08 am
Location: Canada
x 44

Re: [SoC 2009 - Accepted] Unified Samples Framework & Browser

Post by omniter »

The project timeline is going to need a complete rewrite. No, we're not behind schedule... some things just need to be switched around. More on this later. First let's get some small changes out of the way.

SampleContext now checks required plugins, renderer, and runs a capabilities test before running a sample. If a required plugin is not found, an exception is thrown. Sample::testCapabilities can throw whatever exceptions it wants, if at all. If the sample requires a specific render system to run, and that render system is not currently in use, it will also throw an exception. The original plan was for the browser to do preliminary testing of all samples and mark the failed ones. This could get quite slow if done for every sample, and I'm not so sure anymore that marking samples as "out of order" will be so useful. The new plan is that the browser will do exactly what the SampleContext class does, but it catches the first exception thrown, displays it, and goes back to the menu without crashing. Sample::testCapabilities now takes a RenderSystemCapabilities pointer. This is retrieved from the RenderSystem by the SampleContext and passed to the sample at testing time. The reasoning was that a capabilities test almost always needs this object, so it would be convenient to have it already provided.

Everything that used a SampleQueue now uses a SampleSet. SampleSet is an std::set that ensures every sample is unique, and sorted by name using a utility Sample::Comparer structure. The sample browser now keeps a master set of samples, as well as a set of sample categories. This ensures that both categories and samples are unique and sorted alphabetically. Samples get a default title ("Untitled") and category ("Unsorted") if none are found. Of course, this means that the SampleContext no longer has sample queueing capabilities which, in retrospect, were quite useful for testing, but not so much for the user. So as before, you'd provide an optional initial sample to SampleContext::go.

The browser now creates a dummy scene and camera whenever a sample is not being run. This ensures that the browser can render its own GUI even when no sample is running. Of course, this could also be used to create some "menu scenery" like in Half-Life 2, but that'd add to startup time, so... no.

And now, the big news: the arrival of a new sample GUI system.

I think we can all agree that OGRE's overlay system does not make for much of a "GUI" on its own (at least not a very advanced one, and definitely not interactive). If you're making your own game, chances are you'll end up using a separate GUI solution like CEGUI, QuickGUI, MyGUI, just to name a few. But when you're making samples or 3D demos and you want to quickly add some buttons or slider bars, the overlay system is just not enough, and the other GUI solutions are a bit overkill. Most GUI solutions require some kind of "renderer" in order to interface with OGRE. They also have static libraries you need to link to and one or more dynamic ones. The current SDK has 4 dlls in the runtime folder just for CEGUI, and 23 files in the gui media directory. There's .xsd files, .layout files, .config files, .scheme files, .imageset files, .looknfeel files, .xml files, .font files, and .tga files. On the code side of things, setting up and using CEGUI is not a task I'd want to do for just a sample. Does it really make sense for Gui.cpp (the SDK GUI sample) to be 569 lines of code? I mean even DeferredShadingDemo.cpp only has 547. What the sample framework needs is a middle ground between these two extremes...

This new system was designed to be minimalistic wherever possible, and it does so not by looking at what a GUI needs, but instead at what a GUI has that most samples probably won't use. Are you really going to reskin your sample GUI and apply different themes? Are your buttons really going to have different heights? Do you really need to provide callback delegates separately to individual widgets? Does your sample really need tons of windows and tabs? Are your sample GUIs really going to be so complex that you need an external editor to export a layout file of some sort? Let's say you want to setup a simple quit button for your sample... what if all you had to do was this? And I mean all you have to do...

Code: Select all

mQuitButton = mGui->createButton("QuitButton", "Click Me!");
To respond to your button's events, your sample just has to extend GuiListener and make the following callback:

Code: Select all

virtual void buttonClicked(Button* b)
{
    if (b == mQuitButton) mDone = true;
}
Where should you put your button? Well, in most samples, widgets are off in the corners or to the sides, and rarely, a text box could be turned on in the center to display instructions. Also, since text flows sideways, buttons are wider than they are tall, and are usually stacked on top of each other, instead of side to side. This also goes for slider bars and drop-down menus. Taking into account these observations, the new system provides a quick and intuitive way to organize your widgets while being flexible enough to handle all kinds of layouts. Observe.

Code: Select all

mGui->moveWidgetToTray(mQuitButton, TL_BOTTOMRIGHT);
The GUI provides 9 convenient "anchor points" - 1 in each corner, 1 on each edge, and 1 in the center. At each of these anchor points, there is a widget "tray" that holds your widgets. A tray only shows up when you have at least one widget in it, and it forms a bubble that wraps neatly around all the widgets you put in it. Here's a screenshot to demonstrate the power of these widget trays:

Image

I placed 2 buttons in the top left tray, 2 in the left tray, 3 in the center tray, and 2 in the bottom right. Notice how they make a transparent wrap around each group of widgets. Here's two more screenshots showing how the shapes of the trays change as I insert more widgets. They also show how the trays look on different background colours.

Image

The trays wrap around all of your widgets perfectly, regardless of their horizontal alignment. You can customise the tray padding (distance of the trays from the edges of the screen), widget padding (distance of widgets from edges of the trays), and widget spacing (distance between widgets in a tray). Trays along the top of the screen grow downward. Trays along the bottom grow upward, and trays in the middle grow both ways vertically. At any time, you can insert or remove a widget anywhere in a tray, and the tray will automatically update its shape or hide itself, depending on the new contents. Use of the trays is optional. You can have your widgets free floating.

You can make as many GUIs as needed. Each GUI comes with 3 layers - the backdrop, the widgets, and the cursor. You can toggle the visibility of all layers. When showing the backdrop, you can specify a material to fill the backdrop, or if you don't, the last material will be used. If either the cursor or the widgets are hidden, GUI events do not fire (there's either nothing to press, or nothing to press with). So far, the following widgets are planned: Button, StatsPanel, CheckBox, TextBox, Dropdown, Slider, SectionHeading. You can easily extend your own widget. Also, you can still access all the underlying overlay elements of the GUI system to make any tweaks you want.

This GUI requires no libaries to link to (static or dynamic), no resources you have to create, and no scripts you have to write. If you're using SdkSample, you're already good to go. If you're using Sample directly, just include "BasicGui.h". All the resources used by the GUI system are in OgreBites.zip, which is loaded by the browser on startup. Its contents consist solely of an overlay script, a material script, textures, and fonts - all familiar OGRE file types. The GUI system has no external dependencies as it is completely based on OGRE's overlay system.

OgreCore.zip is now (or will soon become) obsolete. The debug panel will be replaced by the StatsPanel widget, which will be in the bottom left tray by default in every SdkSample. The rest of OgreCore.zip's contents will be replaced by procedural content in the near future. For now, it will be kept for backwards compatibility, but it is no longer required by the framework at all.

Just as the samples will use the new GUI system, the browser will use it as well for its menu and configuration screens. The "Browser" and "Common" resource groups have been renamed to "Essential" and "Popular", respectively. The "Essential" group contains OgreBites.zip and the thumbnails directory. These are necessary to run the browser, and most of the samples. The "Popular" group will contain the most commonly used sample resources. I think these group names are much clearer and more descriptive.

Another implication of this new GUI system is that many of the keyboard toggles and value up/down keyboard shortcuts in the current SDK samples will be removed and replaced with GUI controls. Input device control can be easily toggled between the GUI and the scene. In addition to using the BasicGui system by default, SdkSample will also include a default camera controller, called CameraMan. This is basically the camera utility class mentioned in previous weeks.

Keep in mind that although SdkSample, SamplePlugin, SampleBrowser, BasicGui, CameraMan, and OgreBites.zip are used extensively by the SDK, they are not part of the core samples framework which consists only of Sample and SampleContext. In fact, BasicGui, CameraMan and the contents of OgreBites.zip may be used by any of your OGRE applications without using the samples framework at all.

So, now you can see why the project timeline has to be rewritten. In order to develop many of the browser's features, it would make sense to have a GUI system in place to test it first. So for the next couple of weeks, I will develop the essential GUI widgets and some of the more important browser features. Hope you guys are in favour of this new system I've introduced. Feel free to make suggestions or ask questions! Cheers! :D
Post Reply