Introduction

This tutorial builds on the previous Humble Beginnings tutorial so you should continue with the same files from that.

Change the way the ship moves

We want to change the way the ship moves for now so that we can rotate it. This will mean that when we are working on the lights on the wings we can get a better look at them.

Open Ship.h and change the frameStarted method to be:

bool frameStarted(const FrameEvent& evt)
     {
         // Move upto 80 units/second
         Real MoveFactor = 80.0 * evt.timeSinceLastFrame;
 
         // Copy the current state of the input devices
         mInputDevice->capture();
 
         // Move the ship node!
         if(mInputDevice->isKeyDown(Ogre::KC_UP))
           mShipNode->translate(0.0, MoveFactor, 0.0);
 
         if(mInputDevice->isKeyDown(Ogre::KC_DOWN))
           mShipNode->translate(0.0, -MoveFactor, 0.0);
 
         // Instead of moving the ship left and right, rotate it using yaw()
         if(mInputDevice->isKeyDown(Ogre::KC_LEFT))
           mShipNode->yaw(MoveFactor);
 
         if(mInputDevice->isKeyDown(Ogre::KC_RIGHT))
           mShipNode->yaw(-MoveFactor);
 
         return true;
     }

If you compile now and get 'Ogre::SceneNode::yaw' : cannot convert parameter 1 from 'Ogre::Real' to 'const Ogre::Radian &' it is because OGRE_FORCE_ANGLE_TYPES is not defined. You can either define OGRE_FORCE_ANGLE_TYPES or use the following instead:

if(mInputDevice->isKeyDown(Ogre::KC_LEFT))  mShipNode->yaw(Angle(MoveFactor));
     if(mInputDevice->isKeyDown(Ogre::KC_RIGHT)) mShipNode->yaw(Angle(-MoveFactor));

Avionic Flying Lights


Some new classes to play with

We are now going to give the ship some lights on it's wings and tail so that pilots of other ships can see it againt the blackness of space. By using different colours and patterns on each of the wings and tail, another pilot will also be able to determine which direction the ship is facing.

To do this we will be using three object classes: Light, BillboardSet, and {LEX()}Billboard{LEX}.

Billboards and Materials

A {LEX()}billboard{LEX} simply displays a 2D image in the 3D world that we create. Whenever a billboard is rendered it faces the viewer. This is perfect for the lights we are about to make, they can appear as small balls of light. The image displayed on the billboard is a material just like any other so it needs to be defined in our material script file.

Open ogrenew\Samples\Media\materials\scripts\example.material and add the following to the script:

// Light effects
 material Examples/FlyingLightMaterial
 {
   technique
   {
     pass
     {
       lighting off
       scene_blend add
       depth_write off
       texture_unit
       {
         texture flare.png
       }
     }
   }
 }

It may look familiar to some of you. It is in fact the material used for the flare effects earlier in the script, but its name has been changed to suit our purposes.

BillboardSets and Billboards

A BillboardSet is a grouping of Billboards in 3D space. The relationship between BillboardSet and Billboard is well documented in the Ogre API so there is really no need to describe it here.

Member Variables

Time to add member variables for the lights and billboards. Add this to the protected section of our SpaceApplication class

// The set of all the billboards used for the avionic lights
 BillboardSet* mLights;
 
 // Billboards
 Billboard* mRedLightBoard;
 Billboard* mBlueLightBoard;
 Billboard* mWhiteLightBoard;
 
 // Lights
 Light* mRedLight;
 Light* mBlueLight;
 Light* mWhiteLight;

Lighting Instances



The general flow of this is:

  1. Create BillboardSet
  2. Set its material and attach it to the scene
  3. Using the new BillboardSet create as many billboards as you require, position each of them
  4. Create the lights and attach them to the scene


So let's begin by creating the BillboardSet. Type this in at the bottom of the createScene method

// First create the BillboardSet. This will define the materials for the billboards
 // in its set to use
 mLights = mSceneMgr->createBillboardSet("FlyingLights");
 mLights->setMaterialName("Examples/FlyingLightMaterial");
 mShipNode->attachObject(mLights);

There should not be too much there that needs explaining. Like other objects in Ogre, BillboardSets all have unique names. This one is called "FlyingLights" and the material that we want it to be using for its Billboards is "Examples/FlyingLightMaterial", which is of course the material we put into the material script earlier.

Each of the three coloured lights has two properties of any interest. Position and colour.

// Red light billboard, in "off" state
 Vector3 redLightPosition(74, -8, -70);
 mRedLightBoard = mLights->createBillboard(redLightPosition);
 mRedLightBoard->setColour(ColourValue::Black);
 
 // Blue light billboard, in "off" state
 Vector3 blueLightPosition(-87, -8, -70);
 mBlueLightBoard = mLights->createBillboard(blueLightPosition);
 mBlueLightBoard->setColour(ColourValue::Black);
 
 // White light billboard, in "off" state
 Vector3 whiteLightPosition(-5.5, 30, -80);
 mWhiteLightBoard = mLights->createBillboard(whiteLightPosition);
 mWhiteLightBoard->setColour(ColourValue::Black);

You might notice that the positions chosen here are not symmetrical. I originally used symmetrical values but then discovered that the lights just would not line up on the ship. Instead of modifying the model and distributing that I decided to just change these positions. If you find that the lights still do not line up on your model you may want to adjust these values yourself later on.

The light objects are next on the list. Each of them has a distinct name, a type, a colour, and a position.

// Red light, in "off" state
 mRedLight = mSceneMgr->createLight("RedFlyingLight");
 mRedLight->setType(Light::LT_POINT);
 mRedLight->setPosition(redLightPosition);
 mRedLight->setDiffuseColour(ColourValue::Black);
 mShipNode->attachObject(mRedLight);
 
 // Blue light, in "off" state
 mBlueLight = mSceneMgr->createLight("BlueFlyingLight");
 mBlueLight->setType(Light::LT_POINT);
 mBlueLight->setPosition(blueLightPosition);
 mBlueLight->setDiffuseColour(ColourValue::Black);
 mShipNode->attachObject(mBlueLight);
 
 // White light in "off" state
 mWhiteLight = mSceneMgr->createLight("WhiteFlyingLight");
 mWhiteLight->setType(Light::LT_POINT);
 mWhiteLight->setPosition(whiteLightPosition);
 mWhiteLight->setDiffuseColour(ColourValue::Black);
 mShipNode->attachObject(mWhiteLight);

If you run the program as it stands right now you wont notice anything different. Why is that? well that is because we told the lights and billboards to be black. Just to see where the lights and billboards are try changing the colour of all of the billboards to their "on" colour. For instance, set the colour of mRedLightBoard to ColourValue::Red. When you run it you will then see three coloured balls, one on the left wingtip, one on the right wingtip, and one on the tail wingtip. Change them all back to black and save.

Using Waveform Controllers

Controllers, ControllerFunctions, and ControllerValues

When I initially wrote the source for the tutorial I used two variables of type Real, and two booleans for each light to control its flashing. The code was a couple pages long and it would have been very hard to extend the functionality of it. I thought to myself that it would be nice if I could just set up the logic of controlling the colour value of a Light and -Billboard pair just once and let different time based functions control the intensity. Just when I was about to make my own I discovered that Ogre has these built into it. And now they are my new best friends.

The way it hangs together in Ogre is that you create a class descending from ControllerValue which overrides the methods getValue and setValue. The names should make their function obvious enough but one thing to note is that they only deal with values between 0.0 and 1.0.

A ControllerFunction is given a value to operate on and outputs a result between 0.0 and 1.0, which gets fed to a ControllerValue. These functions can be based on anything, but for this tutorial we will only focus on using it to control values based on time.

A Controller connects a ControllerFunction with an input ControllerValue and an output ControllerValue. The most useful input ControllerValue to us comes from a method on the ControllerManager called getFrameTimeSource which will give the value of time between frames.

Controllers, ControllerFunctions, and ControllerValues

With our new found knowledge of controllers lets make a ControllerValue and ControllerFunction to control these lights. Go to the top of the Space.h file just after #include "ExampleApplication.h and enter this

class LightFlasher : public ControllerValue<Real>
 {
 protected:
     Light* mLight;
     Billboard* mBillboard;
     ColourValue mMaxColour;
     Real intensity;
 public:
     LightFlasher(Light* light, Billboard* billboard, ColourValue maxColour)
     {
         mLight = light;
         mBillboard = billboard;
         mMaxColour = maxColour;
     }
 
     virtual Real  getValue (void) const
     {
         return intensity;
     }
 
     virtual void  setValue (Real value)
     {
         intensity = value; 
 
         ColourValue newColour;
 
         // Attenuate the brightness of the light
         newColour.r = mMaxColour.r * intensity;
         newColour.g = mMaxColour.g * intensity;
         newColour.b = mMaxColour.b * intensity; 
 
         mLight->setDiffuseColour(newColour);
         mBillboard->setColour(newColour);
     }
 };

When the controller calls setValue, the value is used to attentuate the Red, Green, and Blue values of the Light and Billboard. The effect of this will be that when the value is set to 0.0 the light will be black which is the same as being off, and when set to 1.0 the light will be at its brightest.

The ControllerFunction that we will use will be based on WaveformControllerFunction. We do not need to modify the class very much, in fact all we will do is override the constructor and default some of the arguments to make using it a little easier.

class LightFlasherControllerFunction : public WaveformControllerFunction
 {
 public:
     LightFlasherControllerFunction(WaveformType wavetype, Real frequency, Real phase) 
          : WaveformControllerFunction(wavetype, 0, frequency, phase, 1, true)
     {
 
     }
 };

The constructor for a WaveformControllerFunction is

WaveformControllerFunction::WaveformControllerFunction(WaveformType wType, Real base,  Real frequency, 
   Real phase, Real amplitude, bool delta)

The first argument, WaveformType is the type of wave to be generated, which can be a sine, traingle, square, sawtooth, or inverse sawtooth. We will use most of these wave forms in the tutorial. Base is added to the value generated, it effectively sets the bottom value of the wave and we will only use 0.0 in this tutorial so it has been hardcoded in the constructor. Frequency is how often the whole wave form is produced within one second. Phase is how far through the wave to start in. Amplitude is multiplied to the wave value to increase the size of the wave, we will only use 1.0 for this. Delta is used internally to specify wether or not the values are supplied as delta or absolute values, defaulting here to true.

Switching the lights on

In the previous tutorial we had to turn the ambient lighting on so that we could see the ship but now we want to turn it back down again so that we can see the effects of our new light sources. So in the createScene method change the line setting the ambient lighting to

// Set a very low level of ambient lighting
 mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));

We need some member variables to hold the Controllers and their Values and Functions. Add these to the protected section of the class. Note that the 'Ptr' classes are 'shared pointer' which mean the contents are automatically deleted when nothing is using them anymore.

// Light flashers
 ControllerValueRealPtr mRedLightFlasher;
 ControllerValueRealPtr mBlueLightFlasher;
 ControllerValueRealPtr mWhiteLightFlasher;
 
 // Light controller functions
 ControllerFunctionRealPtr mRedLightControllerFunc;
 ControllerFunctionRealPtr mBlueLightControllerFunc;
 ControllerFunctionRealPtr mWhiteLightControllerFunc;
 
 // Light controllers
 Controller<Real>* mRedLightController;
 Controller<Real>* mBlueLightController;
 Controller<Real>* mWhiteLightController;

And now, finally, we create our controllers. Type this into the bottom of the createScene method.

// Light flashers
 mRedLightFlasher = ControllerValueRealPtr(
   new LightFlasher(mRedLight, mRedLightBoard, ColourValue::Red));
 mBlueLightFlasher = ControllerValueRealPtr(
   new LightFlasher(mBlueLight, mBlueLightBoard, ColourValue::Blue));
 mWhiteLightFlasher = ControllerValueRealPtr(
   new LightFlasher(mWhiteLight, mWhiteLightBoard, ColourValue::White));

 // Light controller functions
 mRedLightControllerFunc = ControllerFunctionRealPtr(
   new LightFlasherControllerFunction(Ogre::WFT_SINE, 0.5, 0.0));
 mBlueLightControllerFunc = ControllerFunctionRealPtr(
   new LightFlasherControllerFunction(Ogre::WFT_SQUARE, 0.5, 0.5));
 mWhiteLightControllerFunc = ControllerFunctionRealPtr(
   new LightFlasherControllerFunction(Ogre::WFT_TRIANGLE, 4, 0.0));

 // Light controllers
 ControllerManager* mControllerManager = &ControllerManager::getSingleton();
 mRedLightController = mControllerManager->createController(                                             
   mControllerManager->getFrameTimeSource(), ControllerValueRealPtr(mRedLightFlasher),
   ControllerFunctionRealPtr(mRedLightControllerFunc));
 mBlueLightController = mControllerManager->createController(
   mControllerManager->getFrameTimeSource(), ControllerValueRealPtr(mBlueLightFlasher),  
   ControllerFunctionRealPtr(mBlueLightControllerFunc));
 mWhiteLightController = mControllerManager->createController(
   mControllerManager->getFrameTimeSource(), ControllerValueRealPtr(mWhiteLightFlasher),  
   ControllerFunctionRealPtr(mWhiteLightControllerFunc));

There is one LightFlasher for each of Red, Blue, and White connected to their respective Light and Billboard. Then we create one ControllerFunction to pulse the red light in a sine wave fashion, one to flash the blue light on and off, and one to pulse the white light 4 times a second in a triangle wave fashion. We then use the ControllerManager to create three Controllers, one for each light and hook them up to their ControllerFunctions and ControllerValues. The first argument to their constructors is a call to getFrameTimeSource, which will give us an object that provides the Controller with time information.

Compile and run the program. The lights should be flashing or pulsing as described above.

Blinking Lights

I said earlier that is is easier to extend the functionality of this than my first attempt. Lets do it now by changing the way that the white light works. Lets make it blink on for one tenth of a second once every 4 seconds. To do this we will create a new class called LightBlinker inheriting from the LightFlasher. It will be designed to accept input from the sawtooth wave and when the wave hits a certain value we will turn the light on, otherwise the light will remain off.

Put this class definition just after the definition of LightFlasher.

class LightBlinker : public LightFlasher
 {
 protected:
     ColourValue mMinColour;
     Real mActivationLevel;
 public:
     LightBlinker(Light* light, Billboard* billboard, ColourValue maxColour, ColourValue minColour, Real activationLevel) 
          : LightFlasher(light, billboard, maxColour)
     {
         mMinColour = minColour;
         mActivationLevel = activationLevel;
     }
 
     virtual Real  getValue (void) const
     {
         return intensity;
     }
 
     virtual void setValue(Real value)
     {
         intensity = value;
 
 
         if(value < mActivationLevel)
         {
             // Light is off
             mLight->setDiffuseColour(mMinColour);
             mBillboard->setColour(mMinColour);
         } else {
             // Light is blinking on
             mLight->setDiffuseColour(mMaxColour);
             mBillboard->setColour(mMaxColour);
         }
     }
 
 };

Lets now use our new class. Change the line creating the light controller function for the white light to be

mWhiteLightControllerFunc = ControllerFunctionRealPtr(
   new LightFlasherControllerFunction(Ogre::WFT_SAWTOOTH, 0.25, 0.0));

And the line creating the white light flasher.

mWhiteLightFlasher = ControllerValueRealPtr(
   new LightBlinker(mWhiteLight, mWhiteLightBoard, ColourValue::White, ColourValue::Black, 0.975));

So what is this value of 0.975? As described above it is the value that the wave must reach before the light will turn on. But why that particular value? This is the way it works: the saw tooth wave starts at 0 and hits 1.0 at the end of 4 seconds (frequency is 0.25 as stated in the constructor for the LightFlasherFunction). This means that each second will contribute 0.25 to the value. We however only want one tenth of a second, leaving us with 0.025 and since we want the light to be on for only that last tenth of a second we subtract 0.025 from 1.0 and we get 0.975, clear enough?

Compile and run the program so far. You should have all three lights working but the white light will blink on only once every 4 seconds.

Spinning the Camera

Camera Spins

Lets do some camera motion. The first thing we are going to do it spin the camera. Not around itself but around the ship and keep it facing the ship. Ogre gives us a very easy way to do this using SceneNodes.

class SpaceCameraRotator : public ExampleFrameListener

Yep thats right, another class derived from ExampleFrameListener. One of the good things about Ogre is that we can have more than one piece of code monitoring the keyboard, and that is exactly what we are going to do here. Our first FrameListener, SpaceFrameListener will remain and move the ship based on the arrow keys and this new class will move the camera based on some other keys.

{
 protected:
     Camera* mCamera;
     SceneNode* mCentralNode;
     SceneNode* mRotatingNode;
     Vector3 mRotationAxis;
     Real mRotationSpeed;

Nothing special there, just some member variables.

public:
     SpaceCameraRotator(RenderWindow* win, Camera* cam, SceneNode* centralNode, Vector3 initialPosition) 
          : ExampleFrameListener(win, cam)
     {
         mCamera = cam;
         mCentralNode = centralNode;
         mRotationAxis = Vector3::UNIT_Y;
         mRotationSpeed = 60.0;
 
         // Create a node to act as the central rotation point
         mRotatingNode = static_cast<SceneNode*>(
                  mCentralNode->getParentSceneNode()->createChild( "RotationCenter", mCentralNode->getPosition() ) );
 
         mRotatingNode->attachObject(mCamera);
         mCamera->moveRelative(initialPosition);
         mCamera->lookAt(0, 0, 0);
     }

As you can see what we have done is created a new SceneNode called mRotatingNode that is located at the same position as the SceneNode supplied to the constructor, which by the way will be the node that ship is attached to. This node will be the anchor for our rotations. Then we attach the camera to the new node, set its position to be off centre, and tell it to look at the 0,0,0 which just so happens to be the ship.

~SpaceCameraRotator()
     {
         delete mRotatingNode;
     }

Since we created a SceneNode in the constructor we really should destroy it in the destructor.

bool frameStarted(const FrameEvent& evt)
     {
         // Copy the current state of the input devices
         mInputDevice->capture();
 
         if(mInputDevice->isKeyDown(Ogre::KC_SPACE))
             mRotatingNode->rotate(mRotationAxis, Degree(mRotationSpeed * evt.timeSinceLastFrame));    
 
         return true; 
     }
 };

This is pretty simple, rotate the new SceneNode around the axis if the space bar is pressed. All that is left now is creating an instance of SpaceCameraRotator. Insert the following code into createFrameListener

SpaceCameraRotator* cameraRotator = new SpaceCameraRotator(mWindow, mCamera, mShipNode, Vector3(0, 0, 100));
     mRoot->addFrameListener(cameraRotator);

Compile and run the program. When you hold down the space bar you should see the camera is rotating around the ship. You can tell that the camera is spinning and not the ship because the background is moving. If you press the arrow keys the ship will still move as it did before BUT the camera will move with it. The net effect is that the background will look like it is moving and the ship isn't.

I had planned to do some more camera work (like bumping) but another scene would demonstrate them better. So that will have to wait until another day.

<HR>
Creative Commons Copyright -- Some rights reserved.


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.