OgreDotNet Beginner Tutorial 4: Event Handling
Original version by Clay Culver
C# changes by DigitalCyborg
Note: This was written for Ogre 1.2 and is known to compile against it. Any problems you encounter while working with this tutorial should be posted to the Help Forum.
Table of contents
- Prerequisites
- Introduction
- Getting Started
- EventHandling
- Setting up the Scene
- Event Handling Part II, adding code to our callbacks
- End
- Credits
- 1. Definitions
- 2. Fair Use Rights
- 3. License Grant
- 4. Restrictions
- 5. Representations, Warranties and Disclaimer
- 6. Limitation on Liability.
- 7. Termination
- 8. Miscellaneous
Prerequisites
This tutorial assumes you have basic knowledge of C# programming and are able to setup and compile an OgreDotNet application in C# (if you have trouble setting up your application, see this guide for specific compiler setups). This tutorial builds on the previous C# beginner tutorials, and it assumes you have already worked through them.
Introduction
In this tutorial we will be introducing one of the most useful OgreDotNet constructs: the Eventhandler. By the end of this tutorial you will understand EventHandler and Event Delegates, how to use them to do things that require updates every frame, and how to use them.
As you go work tutorial you should be slowly adding code to your own project and watching the results as we build it.
Getting Started
As with the previous tutorials, we will be using a pre-constructed code base as our starting point. Create a project in the compiler of your choice (VS200X assumed) for this project, and add a source file which contains this code:
using System; using System.Drawing; using OgreDotNet; using Math3D; namespace TutorialApplication4 { class TutorialApplication4 : ExampleApplication { protected bool MouseDown; // Whether or not the left mouse button was down last frame protected float mToggle; // The time left until next toggle protected float mRotate; // The rotate constant protected float mMove; // The movement constant protected SceneNode mCamNode = null; // The SceneNode the camera is currently attached to protected override void CreateEventHandler() { } protected override bool FrameEnded(FrameEvent e) { } protected override bool FrameStarted(FrameEvent e) { } protected override void MouseMotion(MouseMotionEvent e) { } protected override void MouseDragged(MouseMotionEvent e) { } protected override void MouseClick(MouseEvent e) { } protected override void KeyClicked(KeyEvent e) { } protected override void KeyPressed(KeyEvent e) { } protected override void KeyReleased(KeyEvent e) { } protected override void MousePressed(MouseEvent e) { } protected override void MouseReleased(MouseEvent e) { } protected override void CreateCamera() { } protected override void CreateScene() { } //[STAThread] static void Main(string[] args) { using(TutorialApplication4 app = new TutorialApplication4()) { app.Start(); } } } }
We will be defining the program controls during this tutorial.
EventHandling
Introduction
In the previous tutorials we only looked at what we could do when we add code to the createScene method. In OgreDotNet, we use Event Delegates to receive notification when an input event happens. The EventHandler interface uses Event Delegates to handle Mouse and Keyboard events. In C#, We define Event Delegates to handle the events which occure When a mouse or keyboard event occurs. If you are familar with "callbacks", these are the same thing: Functions(Methods) which get called when something happens.
Since the ExampleApplication already defines them. we'll need to use the override keyword.
protected override bool FrameEnded(FrameEvent e) { return true; } protected override bool FrameStarted(FrameEvent e) { return true; } protected override void MouseMotion(MouseMotionEvent e) {} protected override void MouseDragged(MouseMotionEvent e) {} protected override void MouseClick(MouseEvent e) {} protected override void KeyClicked(KeyEvent e) {} protected override void KeyPressed(KeyEvent e) {} protected override void KeyReleased(KeyEvent e) {} protected override void MousePressed(MouseEvent e) {} protected override void MouseReleased(MouseEvent e) {}
Ogre's (and OgreDotNet's) main loop (Root::startRendering) looks like this:
- The Root object calls the frameStarted method on all registered FrameListeners.
- The Root object renders one frame.
- The Root object calls the frameEnded method on all registered FrameListeners.
In the ExampleApplication in C#, this loops until mDone is set to true or (I think) until FrameStarted() or FrameEnded returns false. If you set mDone to true or return false from either Frame* function, the program will exit.
Registering an EventHandler
The FrameEvent object contains two variables, but only the timeSinceLastFrame is useful to us right now. This variable keeps track of how long it's been since the FrameStarted or FrameEnded last fired. Note that in the FrameStarted method, TimeSinceLastFrame will contain how long it has been since the last FrameStarted event was last fired (not the last time a FrameEnded method was fired). This tutorial uses the mDeltaTime variable inherited from the ExampleApplication.
mDeltaTime = e.TimeSinceLastFrame;
One important concept to realize about OgreDotNet's Event Handlers is that they are called asynchronously when each event happens. Each one actually runs as its own thread. For the all the dirty details read this http://msdn.microsoft.com/msdnmag/issues/02/12/BasicInstincts/
This is why we define event delegates for each event. The ExampleApplication already sets up a nice, neat clean framework in the OgreDotNet.EventHandler class, so we'll use it in our version of CreateEventHandler():
protected override void CreateEventHandler() { mEventHandler = new OgreDotNet.EventHandler(mRoot, mRenderWindow); mEventHandler.SubscribeEvents(); mEventHandler.FrameStarted += new FrameEventDelegate(FrameStarted); mEventHandler.FrameEnded += new FrameEventDelegate(FrameEnded); }
See how easy it is to use? We just call the SubscribeEvents function to register the EventHandler with the framework and then tell the EventHandler instance which functions to use when events happen.
You might also notice that the main loop really only does three things, and since nothing happens in between the frameEnded and FrameStarted methods being called, you can use them almost interchangably. Where you decide to put all of your code is entirely up to you. You can put it all in one big FrameStarted or FrameEnded method, or you could divide it up between the two.
Currently the above code will compile, but since we have overridden the CreateEventHandler method of ExampleApplication and CreateCamera, if you run the application you will not be able to kill it. We'll fix this problem soon. But first, lets create the camera.
Find the TutorialApplication4::createCamera method and add the following code to it:
// create camera, but leave at default position mCamera = mSceneManager.CreateCamera("PlayerCam"); mCamera.SetNearClipDistance(5);
We have not done anything out of the ordinary with this. The only reason we need to overide ExampleApplication's createCamera method is because the createCamera method moves the camera and changes its orientation, which we do not want for this tutorial.
Since the Root class is what renders frames, it also is in charge of keeping track the EventHandler. The first thing we need to do is create an instance of our EventHandler. Find the TutorialApplication::createEventHandler method, and notice this code:
mEventHandler = new OgreDotNet.EventHandler(mRoot, mRenderWindow); mEventHandler.SubscribeEvents();
The mRoot and mRenderWindow variables are defined in the ExampleApplication class. We call the SubscribeEvents() function to tell the framework what to do when an event happens. As I already mentioned, this is not the whole story though, we'll define and setup callbacks for each event later in the tutorial.
Be sure you can compile the application before continuing. It's not useful to run it though. we haven't told the event handler how to handle any mouse or key events, and hence, there is really no way to exit cleanly.
Setting up the Scene
Introduction
Before we dive directly into the code, I would like to briefly outline what we will be doing so that you understand where I am going when we create and add things to the scene.
We will be placing one object (a ninja) in the scene, and one point light in the scene. If you left click the mouse, the light will toggle on and off. Holding down the right mouse button turns on "mouse look" mode (that is, you look around with the Camera). We will also be placing SceneNodes around the scene which we will be attaching the Camera to for different viewports. Pressing the 1 and 2 buttons chooses which Camera viewpoint to view the scene from. We also add some functionality to move the camera around with the keyboard.
The Code
Find the TutorialApplication::createScene method. The first thing we will be doing is setting the ambient light of the scene very low. We want scene objects to still be visible when the light is off, but we also want the light going on/off to be noticable. I also prefer a black background: (maybe you like Orange or something? .. change it if you want)
mSceneManager.SetAmbientLight(Color.FromArgb(63,63,63)); mRenderWindow.GetViewport(0).SetBackgroundColour(Color.Black);
Note that the arguments to FromArgb are in the range 0,255, so 63 is the same as .25 in the non DotNet version of SetAmbientLight
Now, add a Ninja entity to the scene at the origin:
Entity ent = mSceneManager.CreateEntity("Ninja","ninja.mesh"); SceneNode node = mSceneManager.GetRootSceneNode().CreateChildSceneNode("NinjaNode"); node.AttachObject(ent);
Now we will create a white point light and place it in the Scene, a small distance (relatively) away from the Ninja:
Light light = mSceneManager.CreateLight("Light1"); light.SetLightType(Light.LightTypes.Point); light.SetPosition(new Vector3(250,150,250)); light.SetDiffuseColour(Color.White); light.SetSpecularColour(Color.White);
Now we need to create the SceneNodes which the Camera will be attached to. It is important to note that when using this system for Cameras we need to have a seperate SceneNode to handle the pitch (up and down rotation) of the Camera. I will go into full detail why we need that when we actually move the Camera later on. For now, lets create the first SceneNode and have it face the ninja:
// Create the scene node node = mSceneManager.GetRootSceneNode().CreateChildSceneNode("CamNode1",new Vector3(-400,200,400)); // Make it look towards the ninja node.Yaw(-45.0f);
Now, we need to create a child SceneNode that will control the pitch of the camera (and it will have the Camera itself attached to it). At this point, we'll also save which node the camera is attached to.:
// Create the pitch nod node.CreateChildSceneNode("PitchNode1"); node.AttachObject(mCamera); mCamNode = node;
Now, we have a heirarchy of nodes. The Camera is attached to "PitchNode1", which is attached to "CamNode1", which is attached to the SceneManager's root SceneNode. When we want to move the camera or yaw/roll it, we do that to "CamNode1". If we want to change the pitch of the Camera, we do that to "PitchNode1".
Now, add a second CamNode and PitchNode. We will use these later as a second viewing position for our Camera:
// create the second camera node/pitch node node = mSceneManager.GetRootSceneNode().CreateChildSceneNode("CamNode2",new Vector3(0,200,400)); node = node.CreateChildSceneNode("PitchNode2");
Now we are done with the CreateScene(). Onto the Event Handling!
Event Handling Part II, adding code to our callbacks
Variables which we'll use:
We have defined a few variables in the TutorialFrameListener class which I'd like to go over before we get any further:
bool mMouseDown; // Whether or not the left mouse button was down last frame float mToggle; // The time left until next toggle float mRotate; // The rotate constant float mMove; // The movement constant SceneNode *mCamNode; // The SceneNode the camera is currently attached to
The mCamNode holds the current SceneNode that the Camera is attached to (that would be the "CamNodeX", not the "PitchNodeX"). The mRotate and mMove are our constants of rotation and movement. If you want the movement or rotation to be faster or slower, tweak those variables to be higher or lower.
The other two variables (mToggle and mMouseDown) control our input.
We will be using callbacks for mouse and key input in this tutorial. This means that we will be setting up methods that are called methods by our EventHandlerr to use the input provided by the keyboard and mouse. We run into an interesting problem when we try to use the keyboard to change the state of some object on the screen. If we see that a key is down, we can act on this information, but what happens the next frame? Do we see that the same key is down and do the same thing again? In some cases (like movement with the arrow keys) this is what we want to do. However, lets say we want the "T" key to toggle between a light being on or off. The first frame the T key is down, the light gets toggled, the next frame the T key is still down, so it's toggled again...and again and again until the key is released. We have to keep track of the key's state between frames to avoid this problem.
The mMouseDown keeps track of whether or not the mouse was also down the previous frame (so if mMouse down is true, we do not perform the same action again until the mouse is released). The mToggle button specifies the time until we are allowed to perform an action again. That is, when a button is pressed, mToggle is set to some length of time where no other actions can occur.
Construction
The first thing to notice about the class variables is that we initialize them to values which are useful (at least to us) ExampleFrameListener's constructor:
We will set default values for all variables:
protected bool MouseDown = false; // Whether or not the left mouse button was down last frame protected float mToggle = 0.0f; // The time left until next toggle protected float mRotate = 0.13f; // The rotate constant protected float mMove = 250.0f; // The movement constant protected SceneManager SceneMgr = null; // The current SceneManager protected SceneNode mCamNode = null; // The SceneNode the camera is currently attached to
The FrameStarted Method
Now we are going to get into the real meat of the tutorial: performing actions every event. Currently our FrameStarted method has the following code in it:
if (mRenderWindow.Closed || mDone) return false; mDeltaTime = e.TimeSinceLastFrame; UpdateDebugOverlay();
This is almost enough to get us running in windowed mode (since closing the window will set mRenderWindow.Closed. Once we add some code to CreateEventHandler we can run our application in windowed mode:
mEventHandler.FrameStarted += new FrameEventDelegate(FrameStarted); mEventHandler.FrameEnded += new FrameEventDelegate(FrameEnded);
The KeyClicked Method
The next callback that we'll setup is the KeyClicked function. In This function, we are passed a KeyEvent to handle. In this part of the tutorial, we'll handle 3 keys. First, the Escape key. The code for this is fairly straightforward. Since the ExampleApplication already contains a member variable mDone, which tells it when to exit, all we have to do is set it.
protected override void KeyClicked(KeyEvent e) { switch (e.KeyCode) { case KeyCode.Escape: mDone = true; break; } }
Ok,now that we've handled that (ESC), lets add some functionality to switch the camera between our two cam nodes. We'll do this by adding code for handling a user pressing '1' and a user pressing '2'.
Now that we have a way to kill the application in FullScreen mode (pressing ESC) we need to tell our Event Handler (mEventHandler) which function to use when a key is pressed. Update CreateEventHandler() with this:
mEventHandler.KeyClicked += new KeyEventDelegate(KeyClicked);
Next, we'll be adding functionality to change which node the camera is attached to:
When a user presses 1, we'll detach the camera from its current node and attach it camnode1.
case KeyCode.One: if (mToggle < 0.0f) { mToggle = 1.0f; mCamera.GetParentSceneNode().DetachObject(mCamera); mSceneManager.GetSceneNode("PitchNode1").AttachObject(mCamera); mCamNode = mSceneManager.GetSceneNode("CamNode1"); } break;
In order to disallow rapid clicking between '1' & '2' we use the mToggle variable. We check it here to make sure that its less than zero and reset it to 1.0 after we toggle. We'll decrement it in FrameStarted:
if (mToggle >= 0.0f) mToggle -= mDeltaTime;
Similarly, When a user presses '2' we'll detach it and add it to CamNode2
case KeyCode.Two: if (mToggle < 0.0f) { mToggle = 1.0f; mCamera.GetParentSceneNode().DetachObject(mCamera); mSceneManager.GetSceneNode("PitchNode2").AttachObject(mCamera); mCamNode = mSceneManager.GetSceneNode("CamNode2"); } break;
At this point, the KeyClicked function is completed and looks like this:
protected override void KeyClicked(KeyEvent e) { switch (e.KeyCode) { case KeyCode.Escape: mDone = true; break; case KeyCode.One: if (mToggle < 0.0f) { mToggle = 1.0f; mCamera.GetParentSceneNode().DetachObject(mCamera); mSceneManager.GetSceneNode("PitchNode1").AttachObject(mCamera); mCamNode = mSceneManager.GetSceneNode("CamNode1"); } break; case KeyCode.Two: if (mToggle < 0.0f) { mToggle = 1.0f; mCamera.GetParentSceneNode().DetachObject(mCamera); mSceneManager.GetSceneNode("PitchNode2").AttachObject(mCamera); mCamNode = mSceneManager.GetSceneNode("CamNode2"); } break; } }
The MousePressed Method
The next tidbit of functionality we'll add handles what happens when a mouse key is pressed. In this tutorial, we want to toggle the light when the left mouse button is pressed. We'll do this by updating the code in the MousePressed fxn.
The mouse button event handler uses a bitvector (e.ButtonID) to specify which button is pressed. The binary value 5'b 10000 (16) is the left button. The code to toggle the light is also pretty simple. All we need to do is check the value returned by the light's IsVisible() method and use the light's SetVisible() method to set it to the opposite value:
switch(e.ButtonID) { case 16: Light light = mSceneManager.GetLight("Light1"); light.SetVisible(!light.IsVisible()); break; }
So, at this point MousePressed looks like this:
protected override void MousePressed(MouseEvent e) { switch(e.ButtonID) { case 16: Light light = mSceneManager.GetLight("Light1"); light.SetVisible(!light.IsVisible()); break; } }
Now we can update CreateEventHandler to tell the framework to use our MousePressed function.
mEventHandler.MousePressed += new MouseEventDelegate(MousePressed);
The KeyPressed method
Now that we can toggle the light and switch the camera viewpoints, let's add some functionality to move the camera around using the A S D W Q E and Up, Down, Left, Right, PageUp, & PageDown keys.
The ExampleApplication already contains a variable which we can use to determine how we should move the camera (mMoveCam) so we'll use it. In this function all we need to do is use mMoveCam as a bitvector to determine which way to move. We'll use each of the bits in mMoveCam to determine which way to move: bit 0 (decimal #1) to move forward, bit 1 (decimal #2) to move backwards, bit 2 (decimal #4) to move left, bit 3 (decimal #8) to move right, bit 4 (decimal #16) to move up, and bit 5 (decimal #32) to move right.
We'll use the information in this bitvector (mMoveCam) in FrameStarted (which we'll update a little later in the tutorial)
The KeyPressed function is basically a big switch which is called whenever a key is pressed. If you don't like my keybindings (or maybe are doing something wierd, like using a Dvorak keyboard), change them to something that suits your style better.
protected override void KeyPressed(KeyEvent e) { switch(e.KeyCode) { case KeyCode.W: case KeyCode.Up: mMoveCam |= 1; break; case KeyCode.S: case KeyCode.Down: mMoveCam |= 2; break; case KeyCode.A: case KeyCode.Left: mMoveCam |= 4; break; case KeyCode.D: case KeyCode.Right: mMoveCam |= 8; break; case KeyCode.PageUp: case KeyCode.Q: mMoveCam |= 16; break; case KeyCode.PageDown: case KeyCode.E: mMoveCam |= 32; break; default: break; } }
And, yep.. you probably guessed it. Update CreateEventHandler to use our KeyPressed function
mEventHandler.KeyPressed += new KeyEventDelegate(KeyPressed);
The KeyReleased method
Similarly, the KeyReleased method will be called whenever a key is released. In this tutorial, all we need to do is unset the bit of mMoveCam that we set in KeyPressed:
protected override void KeyReleased(KeyEvent e) { switch (e.KeyCode) { case KeyCode.W: case KeyCode.Up: mMoveCam &= ~1; break; case KeyCode.S: case KeyCode.Down: mMoveCam &= ~2; break; case KeyCode.A: case KeyCode.Left: mMoveCam &= ~4; break; case KeyCode.D: case KeyCode.Right: mMoveCam &= ~8; break; case KeyCode.PageUp: case KeyCode.Q: mMoveCam &= ~16; break; case KeyCode.PageDown: case KeyCode.E: mMoveCam &= ~32; break; default: break; } }
Don't forget to update CreateEventHandler() so that it uses our KeyReleased method
mEventHandler.KeyReleased += new KeyEventDelegate(KeyReleased);
Using the variables set by KeyPressed in FrameStarted
Now that we have a bitvector (mMoveCam) set when a user presses a key, we need to update FrameStarted to actually use it.
The method we use here is also fairly straightforward. All we need to do is check which bit is set and use it. In order to do that we'll use a Vector3 which contains the direction to move. We'll also use the mMoveScale variable in the ExampleApplication (override it if you want) and the time since the last frame to determine how far to move:
if (mMoveCam > 0) {//mMoveCam bits: 1=forward, 2=backward, 4=left, 8=right, 16=up, 32=down Vector3 vCamMove = Vector3.Zero; float mvscale = mMoveScale * e.TimeSinceLastFrame; if ((mMoveCam & 1) > 0) vCamMove += Vector3.NegativeUnitZ; if ((mMoveCam & 2) > 0) vCamMove += Vector3.UnitZ; if ((mMoveCam & 4) > 0) vCamMove += Vector3.NegativeUnitX; if ((mMoveCam & 8) > 0) vCamMove += Vector3.UnitX; if ((mMoveCam & 16) > 0) vCamMove += Vector3.UnitY; if ((mMoveCam & 32) > 0) vCamMove += Vector3.NegativeUnitY; if((mMoveCam & 64) > 0) vCamMove *= mvscale; mCamera.MoveRelative(vCamMove); }
At this point we are done with FrameStarted.. Here it is:
protected override bool FrameStarted(FrameEvent e) { if (mRenderWindow.Closed || mDone) return false; mDeltaTime = e.TimeSinceLastFrame; UpdateDebugOverlay(); if (mToggle >= 0.0f) mToggle -= mDeltaTime; if (mMoveCam > 0) {//mMoveCam bits: 1=forward, 2=backward, 4=left, 8=right, 16=up, 32=down Vector3 vCamMove = Vector3.Zero; float mvscale = mMoveScale * e.TimeSinceLastFrame; if ((mMoveCam & 1) > 0) vCamMove += Vector3.NegativeUnitZ; if ((mMoveCam & 2) > 0) vCamMove += Vector3.UnitZ; if ((mMoveCam & 4) > 0) vCamMove += Vector3.NegativeUnitX; if ((mMoveCam & 8) > 0) vCamMove += Vector3.UnitX; if ((mMoveCam & 16) > 0) vCamMove += Vector3.UnitY; if ((mMoveCam & 32) > 0) vCamMove += Vector3.NegativeUnitY; if((mMoveCam & 64) > 0) vCamMove *= mvscale; mCamera.MoveRelative(vCamMove); } return true; }
Looking Around with the camera
At this point in the tutorial, we can toggle the light using the Left mouse button, we can change camera position using the '1' and '2' keys and we can move the the camera around using WASDQE or Left,Right,Up,Down,PgUp,PdDown keys.
Let's add some 'mousen ook' functionality next. In this tutorial, we only want mouse look when the RIGHT mouse button is pressed. This slightly complicates things. In order to do this we'll use the mMoveCam bitvector similar to how we used it earlier. The next available, unused bit in our mMoveCam bit vector is 64.
We already setup an event delegate for the mouse pressed function to toggle the light, so we'll use it to update the mMoveCam bitvector when the RIGHT mouse button is pressed. Update the switch statement in MousePressed and it should look like this after you are done.
protected override void MousePressed(MouseEvent e) { switch(e.ButtonID) { case 16: Light light = mSceneManager.GetLight("Light1"); light.SetVisible(!light.IsVisible()); break; case 32: mMoveCam |= 64; break; } }
Since we only want to use mouselook when the the right button is pressed we need to define another event delegate for the mouse button released event. All we want to do here is clear the button we set in MousePressed.
protected override void MouseReleased(MouseEvent e) { switch (e.ButtonID) { case 32: mMoveCam &= ~64; break; } }
Now, what happens when the mouse is moved?... The answer is nothing until you tell the code how to handle the MouseMotion & MouseDragged events. The mouseDragged event is called when a button is held while the mouse is moved and the MouseMotion event is called when the mouse is moved. since we already have a variable (well, actually a bit in a bitvector) to determine if we should mouselook, we dont need to do anything in MouseDragged except call MouseMotion
protected override void MouseDragged(MouseMotionEvent e) { this.MouseMotion(e); }
In the MouseMotion method, we'll check for the mouselook bit and use the Pitch and Yaw functions provided by the Ogre Framework:
protected override void MouseMotion(MouseMotionEvent e) { if ((mMoveCam & 64) > 0) { mCamera.Pitch(new Radian(-e.DeltaY * mDeltaTime * 500.0f)); mCamera.Yaw(new Radian(-e.DeltaX * mDeltaTime * 500.0f)); } }
Well, the only thing that is left is to setup our event handler to call our event delegates for mouse. Update CreateEventListener with:
mEventHandler.MouseMoved += new MouseMotionEventDelegate(MouseMotion); mEventHandler.MouseClicked += new MouseEventDelegate(MouseClick); mEventHandler.MousePressed += new MouseEventDelegate(MousePressed); mEventHandler.MouseReleased += new MouseEventDelegate(MouseReleased); mEventHandler.MouseDragged += new MouseMotionEventDelegate(MouseDragged);
End
If you didn't understand this, ask questions in the OrgeDotNet Forum.
Credits
Original tutorial by Clay Culver.
C# Update by DigitalCyborg
<HR>
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
- "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
- "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
- "Licensor" means the individual or entity that offers the Work under the terms of this License.
- "Original Author" means the individual or entity who created the Work.
- "Work" means the copyrightable work of authorship offered under the terms of this License.
- "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
- "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.
2. Fair Use Rights
Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.
3. License Grant
Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
- to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
- to create and reproduce Derivative Works;
- to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
- to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
- For the avoidance of doubt, where the work is a musical composition:
- Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
- Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
- Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.
4. Restrictions
The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
- You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
- You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
- If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability.
EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
- This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
- Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
8. Miscellaneous
- Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
- Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
- If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
- No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
- This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.