IMPORTANT: This framework is meant to be used with old releases of Ogre. For Ogre 1.10+, rather use OgreBites::ApplicationContext.

First Steps

In this tutorial, you will create and run a barebones Ogre program. As you might guess, this program is very simple and teaches you the very basics of what you'll need to do in each Ogre program. I recommend that you go over this tutorial until you understand everything in it.

I will teach you about Ogre's core objects, but I will not teach you how to show things on the screen just yet. I believe that going that far in this tutorial would compromise the amount of space I could devote to ensuring that you first understand the essentials. N.B. This tutorial does not show you how to get entities and other things on screen, but merely shows you how to get a very basic barebones application running without the use of any frameworks.

Let's get started!

Unlike all of the other demos and tutorials out there, this one will teach you how to make an application without using the ExampleApplication framework. I believe the pre-made framework doesn't give the user a good idea of what they need to do in order to get Ogre running.

Part 1: Project Setup

The first thing you need to do is start a new project. I created a project in a subfolder (Tutorial_2) of the folder that contains our Ogre distribution (in my case, C:\Programming\Tutorials\ and \User\robo\Desktop\Tutorials\ for PC and Mac respectively).

Create that folder, and then open your IDE. Here the tutorial branches into two different sections, one to set up a project in Visual C++ and one to set up your project in XCode.

Visual C++
Click "File->New->Blank Solution". Now enter the solution's name - Ogre_Tutorial. In the Location Box, press Browse and then navigate to the folder you made for your project. Press OK. If you look at the Solution Explorer, "Solution ‘Ogre_Tutorial’ (0 projects)" should now be present.

Now we need to create our project. Right click on the "Solution ‘Ogre_Tutorial’ (0 projects)" text and select "Add->New Project". A box should pop up. In the 'Project Types' box select 'Visual C++ Projects' / 'Win32'. Select 'Win32 Project' in the right-hand pane. In the Name box, type Ogre_Tutorial. In the Location box, browse again to the C:\Programming\Tutorials\Tutorial_2 folder. Click OK. Another box should show up, with two links on the upper left side. Click the bottom link, "Application Settings". Leave the Application Type on 'Windows Application', and check the 'Empty Project' checkbox below.

Add an empty C++ file to the project called main.cpp . This file must exist before editing project properties in order for the 'C/C++' menu to appear!

Now that the project is created, we have a lot of settings to define. Click "Project->Properties" in the top toolbar. Now you need to configure some settings. The paths specified in these settings are appropriate to the configuration established in this and the previous tutorial (Newbie Tutorial 1).

Section Subsection Setting Name Value
C/C++ General Additional Include Directories "C:/Ogre_Tutorials/ogrenew/OgreMain/include"
C/C++ Code Generation Runtime Library Multithreaded Debug DLL
C/C++ Precompiled Headers Create/Use Precompiled Header Not Using Precompiled Headers
Linker General Additional Library Directories "C:/Ogre_Tutorials/ogrenew/OgreMain/lib/Debug"
Linker Input Additional Dependencies OgreMain_d.lib


If you subsequently wish to compile your code in Release Mode instead of Debug: change the 'Configuration' listbox at the top of the Properties Pages to 'Release'; input the above settings again in the Properties Pages, except for: in C/C++'s 'Code Generation' section, for 'Runtime Library' change 'Multithreaded Debug DLL' to 'Multithreaded DLL'; in Linker's 'Input' section, change OgreMain_d.lib to OgreMain.lib; change Linker's 'Additional Library Directories' filepath to end in 'Release' instead of 'Debug'.

Part 2: The Code

#include <iostream>
 
 #include "Ogre.h"
 #include <OIS/OIS.h>
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
 #include <macUtils.h>
 #endif
 
 int main()
 {
 	std::string resourcePath;
 	
        #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
            resourcePath = Ogre::macBundlePath() + "/Contents/Resources/";
        #else
  	    resourcePath = "";
        #endif
 	
  	Ogre::Root* root = new Ogre::Root(resourcePath + "plugins.cfg", resourcePath + "ogre.cfg", "Ogre.log");
 	
  	if (!root->showConfigDialog())
 		return -1;
  	
  	Ogre::ConfigFile cf;
  	cf.load(resourcePath + "resources.cfg");
  	
 	// Go through all sections & settings in the file
 	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
 	
 	Ogre::String secName, typeName, archName;
 	while (seci.hasMoreElements())
 	{
 		secName = seci.peekNextKey();
 		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
 		Ogre::ConfigFile::SettingsMultiMap::iterator i;
 		for (i = settings->begin(); i != settings->end(); ++i)
 		{
 			typeName = i->first;
 			archName = i->second;
 			
 			#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
                            if (!Ogre::StringUtil::startsWith(archName, "/", false)) // only adjust relative dirs
                                archName = Ogre::String(Ogre::macBundlePath() + "/" + archName);
 			#endif
  			
 			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
 		}
 	}
 	
 	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
 	
 	Ogre::RenderWindow* window = root->initialise(true);
 	Ogre::SceneManager* smgr = root->createSceneManager(Ogre::ST_GENERIC);
 	
 	//Input Stuff
 	size_t windowHnd = 0;
 	window->getCustomAttribute("WINDOW", &windowHnd);
 	OIS::InputManager* im = OIS::InputManager::createInputSystem(windowHnd);
 	OIS::Keyboard* keyboard = static_cast<OIS::Keyboard*>(im->createInputObject(OIS::OISKeyboard, true));
 	
 	while (1)
 	{
 		Ogre::WindowEventUtilities::messagePump();
 		
 		keyboard->capture();
 		
 		if (keyboard->isKeyDown(OIS::KC_ESCAPE))
 			break;
 		
 		if(root->renderOneFrame() == false)
 			break;
 	}
 	
 	im->destroyInputObject(keyboard);
 	im->destroyInputSystem(im);
 	im = 0;
 	
 	delete root;
 	return 0;
 }

Part 3: Code Breakdown

Alright, let's break down this code step by step to see just what's going on.

#include <iostream>
 
 #include "Ogre.h"
 #include <OIS/OIS.h>
 
 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
 #include <macUtils.h>
 #endif

Pretty basic setup here, we have to include "Ogre.h" and <OIS/OIS.h> to use Ogre and OIS, and iostream is there for some basic output stuff. Finally, in order to support OS X and iPhones, we have to load up the macUtils.h file (included in Ogre) in order to do some processing stuff later on in the tutorial. (NB: this code is cross platform and works on both Windows and OS X. It has not been tested for use in Linux)

int main()
 {
 	std::string resourcePath;
 	
     #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
         resourcePath = Ogre::macBundlePath() + "/Contents/Resources/";
     #else
 	 resourcePath = "";
     #endif

Now we start our main function. Before we get into any of the nitty gritty Ogre stuff, we need one housekeeping variable: resourcePath. This variable is only used on Macs to compensate for the way that app bundles are structured. If you're not looking to make OSX apps, you can ignore this variable. We set this variable to the app path plus /Contents/Resources/. If you're familiar with how apps work on OS X and in XCode, all of your data is stored within the app bundle, so there's no root folder like in Windows and Linux. Thus, we need to tell Ogre where to look for resources later on.

Ogre::Root* root = new Ogre::Root(resourcePath + "plugins.cfg", resourcePath + "ogre.cfg", "Ogre.log"); 
	
 if (!root->showConfigDialog())
     return -1;

Now we create and initialize our Ogre::Root. Ogre::Root is the core of the Ogre engine. All of what Ogre does is initiated through the Root. Needless to say, it's an important thing. In order to create it, we create a pointer to an Ogre::Root object and initialize it. The constructor for Root takes three parameters, a plugins.cfg file, a ogre.cfg file, and a log file. The plugins.cfg file lists the different plugins for Ogre to load when the Root is initialized. My plugins.cfg file looks like this:

# Defines plugins to load
 
 # Define plugin folder
 PluginFolder=
 
 # Define plugins
 Plugin=RenderSystem_GL
 Plugin=Plugin_CgProgramManager
 Plugin=Plugin_OctreeSceneManager

The ogre.cfg file manages the device settings. Luckily, we won't have to manual enter this, the config dialog will take care of setting it up for us. Finally, the ogre.log file is a file which saves the log from the last run of ogre. It's very helpful for debugging and troubleshooting. The next line (root->showConfigDialog()) shows the configuration dialog, which will allow you to set various device settings, such as fullscreen, vsync, and the like.

// Go through all sections & settings in the file
 Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
 	
 Ogre::String secName, typeName, archName;
 while (seci.hasMoreElements())
 {
 	secName = seci.peekNextKey();
 	Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
 	Ogre::ConfigFile::SettingsMultiMap::iterator i;
 	for (i = settings->begin(); i != settings->end(); ++i)
 	{
 		typeName = i->first;
 		archName = i->second;
 		
 		#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
                     if (!Ogre::StringUtil::startsWith(archName, "/", false)) // only adjust relative dirs
                     archName = Ogre::String(Ogre::macBundlePath() + "/" + archName);
  		#endif
 			
 		Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
 	}
 }
 	
 Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

Now we get into some gritty stuff. In order for Ogre to be able to see our data, we have to tell it where the data is hiding. In order to do this, we set up a resources.cfg file. This file has a structure that helps Ogre deal with different resource groups and locations throughout your project tree. My resources.cfg file looks like this:

# Resource locations to be added to the default path
 [General]
 FileSystem=./Contents/Resources/media

There are a few things to note on this file. Comments are denoted with a # sign and are single lined. Resource groups are wrapped in [] (The [General] is the only resource group I have set up). These resource groups are useful for deferred loading. For example, you could load the General group for your main GUI and main menu data, then as you load a level, that could have its own separate resource group that could be loaded later! Cool stuff! Finally, there are two different types of file systems that Ogre can use out of the box. First off is the FileSystem type. These FileSystems are just standard folders, either relative to the working directory or as an absolute path. Second, Ogre can load standard zip archives (e.g. Zip=./archive.zip).

Once this file is loaded, Ogre does some parsing in order to separate each line into three keys, the file system name, the type of file system, and the resource group. Once this parsing is done, the resource location is added to the resource group manager. Finally, after the entire file is parsed, we initialize all the resource groups we loaded. (N.B. for more advanced projects, you won't want to do this, but instead load only your core data).

Ogre::RenderWindow* window = root->initialise(true); 
 Ogre::SceneManager* smgr = root->createSceneManager(Ogre::ST_GENERIC);

Next up, we have to create some stuff to make sure we can actually render some graphics! First of all, we have to open a render window. We do this by calling root->initalise(true). This function returns a RenderWindow* and asks if we want to autocreate our window. For the most part, we will want to create one automatically.

Second, we make a scene manager. The Scene Manager is one of critical aspects of any Ogre program. In order to render anything, we need some sort of Scene Manager to tell Ogre how to render. The scene manager takes care of most graphical aspects including culling, world geometry, and node placement. We'll delve more into this in later tutorials. For now, we choose the Generic scene manager because it's generic and suits our purposes well!

//Input Stuff
 size_t windowHnd = 0;
 window->getCustomAttribute("WINDOW", &windowHnd);
 OIS::InputManager* im = OIS::InputManager::createInputSystem(windowHnd);
 OIS::Keyboard* keyboard = static_cast<OIS::Keyboard*>(im->createInputObject(OIS::OISKeyboard, true));

Now, we need some form of input in order to tell our application when to quit. To do this, we use OIS, the input system included in Ogre. Basically, this code grabs the window handle from Ogre and then pushes it to OIS to create an input system. Finally, we create a keyboard object so we can get the state of the keyboard. For more information on using OIS, refer to the OIS Wiki pages.

In terms of initializing Ogre, we're finished! That is all you need to set up a bare-bones Ogre application! This application is pretty useless though because it doesn't actually render anything, so let's make a render loop. This loop serves as the main logic center of the application, and it's here that all of the rendering, event handling, and logic of your program will go. Let's take a look:

while (1)
 {
 	Ogre::WindowEventUtilities::messagePump();
		
 	keyboard->capture();
 		
 	if (keyboard->isKeyDown(OIS::KC_ESCAPE))
 		break;
 		
 	if(root->renderOneFrame() == false)
 		break;
 }

For starters, we create an infinite loop (while (1) { }) which will go until we break out of it. Once inside the loop, we need to do some housekeeping stuff to keep Ogre happy. Because we are not using root->startRendering(), we must do this ourselves, but fortunately it's easy. Ogre::WindowEventUtilities::messagePump() offers a cross platform way to check and pump system messages through the window. Without this line, we wouldn't be able to minimize or pause our application when we move away from the window.

Next, we capture the state of the keyboard, so we can check its state. The next line does just that, checks the keyboard state to see if the user pressed the Escape key. If they did, the loop breaks and we exit the program.

Finally, if the user didn't press escape, we render a single frame by calling root->renderOneFrame(). If this returns false, we break and quit the program.

That's it for the render loop! This is a really basic loop, but it does the trick and gets us rendering with the least amount of effort!

All that's left is to do some final housekeeping before we quit the program!

im->destroyInputObject(keyboard);
 	im->destroyInputSystem(im);
 	im = 0;
 	
 	delete root;
 	return 0;
 }

First, we destroy the keyboard object and then the input system. Finally, we delete the root object in order to shut Ogre down. Then we're done! We return 0 and the program exits!

Part 4: Conclusion

I hope that this tutorial has helped you get a grip on Ogre's design and core objects.

<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.