1 //===============================================================================================================
2 //Example 3 - Trees and Bushes
3 //---------------------------------------------------------------------------------------------------------------
4 //	This example demonstrates the use of PagedGeometry to display trees and bushes with different view ranges.
5 //  Instructions: Move around with the arrow/WASD keys, hold SHIFT to move faster, and hold SPACE to fly.
6 //	HINT: Search this source for "[NOTE]" to find important code and comments related to PagedGeometry.
7 //===============================================================================================================
8 #define AppTitle "PagedGeometry Example 3 - Trees and Bushes"
9 
10 //Include windows/Ogre/OIS headers
11 #include "PagedGeometryConfig.h"
12 #include <Ogre.h>
13 #ifdef OIS_USING_DIR
14 # include "OIS/OIS.h"
15 #else
16 # include "OIS.h"
17 #endif //OIS_USING_DIR
18 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
19 #include <windows.h>
20 #endif
21 using namespace Ogre;
22 
23 
24 //Include PagedGeometry headers that will be needed
25 #include "PagedGeometry.h"
26 #include "BatchPage.h"
27 #include "ImpostorPage.h"
28 #include "TreeLoader2D.h"
29 
30 //Include "HeightFunction.h", a header that provides some useful functions for quickly and easily
31 //getting the height of the terrain at a given point.
32 #include "HeightFunction.h"
33 //[NOTE] Remember that this "HeightFunction.h" file is not related to the PagedGeometry library itself
34 //in any way. It's simply a utility that's included with all these examples to make getting the terrain
35 //height easy. You can use it in your games/applications if you want, although if you're using a
36 //collision/physics library with a faster alternate, you may use that instead.
37 
38 //PagedGeometry's classes and functions are under the "Forests" namespace
39 using namespace Forests;
40 
41 //Demo world class
42 //[NOTE] The main PagedGeometry-related sections of this class are load() and
43 //render. These functions setup and use PagedGeometry in the scene.
44 class World
45 {
46 public:
47 	World();
48 	~World();
49 
50 	void load();	//Loads the 3D scene
51 	void unload();	//Unloads the 3D scene cleanly
52 	void run();		//Runs the simulation
53 
54 private:
55 	void render();			//Renders a single frame, updating PagedGeometry and Ogre
56 	void processInput();	//Accepts keyboard and mouse input, allowing you to move around in the world
57 
58 	bool running;	//A flag which, when set to false, will terminate a simulation started with run()
59 
60 	//Various pointers to Ogre objects are stored here:
61 	Root *root;
62 	RenderWindow *window;
63 	Viewport *viewport;
64 	SceneManager *sceneMgr;
65 	Camera *camera;
66 
67 	//OIS input objects
68 	OIS::InputManager *inputManager;
69 	OIS::Keyboard *keyboard;
70 	OIS::Mouse *mouse;
71 
72 	//Variables used to keep track of the camera's rotation/etc.
73 	Radian camPitch, camYaw;
74 
75 	//Pointers to PagedGeometry class instances:
76 	PagedGeometry *trees, *bushes;
77 };
78 
79 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
WinMain(HINSTANCE hInst,HINSTANCE hPrevInstance,LPSTR strCmdLine,INT nCmdShow)80 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow)
81 #else
82 int main(int argc, char *argv[])
83 #endif
84 {
85 	//Initialize Ogre
86 	Root *root = new Ogre::Root("");
87 
88 	//Load appropriate plugins
89 	//[NOTE] PagedGeometry needs the CgProgramManager plugin to compile shaders
90 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
91 #ifdef _DEBUG
92 	root->loadPlugin("Plugin_CgProgramManager_d");
93 	root->loadPlugin("Plugin_OctreeSceneManager_d");
94 	root->loadPlugin("RenderSystem_Direct3D9_d");
95 	root->loadPlugin("RenderSystem_GL_d");
96 #else
97 	root->loadPlugin("Plugin_CgProgramManager");
98 	root->loadPlugin("Plugin_OctreeSceneManager");
99 	root->loadPlugin("RenderSystem_Direct3D9");
100 	root->loadPlugin("RenderSystem_GL");
101 #endif
102 #else
103 	root->loadPlugin("Plugin_CgProgramManager");
104 	root->loadPlugin("Plugin_OctreeSceneManager");
105 	root->loadPlugin("RenderSystem_GL");
106 #endif
107 
108 	//Show Ogre's default config dialog to let the user setup resolution, etc.
109 	bool result = root->showConfigDialog();
110 
111 	//If the user clicks OK, continue
112 	if (result)	{
113 		World myWorld;
114 		myWorld.load();		//Load world
115 		myWorld.run();		//Display world
116 	}
117 
118 	//Shut down Ogre
119 	delete root;
120 
121 	return 0;
122 }
123 
World()124 World::World()
125 {
126 	//Setup Ogre::Root and the scene manager
127 	root = Root::getSingletonPtr();
128 	window = root->initialise(true, AppTitle);
129 	sceneMgr = root->createSceneManager(ST_EXTERIOR_CLOSE);
130 
131 	//Initialize the camera and viewport
132 	camera = sceneMgr->createCamera("MainCamera");
133 	viewport = window->addViewport(camera);
134 	viewport->setBackgroundColour(ColourValue(0.47f, 0.67f, 0.96f));	//Blue sky background color
135 	camera->setAspectRatio(Real(viewport->getActualWidth()) / Real(viewport->getActualHeight()));
136 	camera->setNearClipDistance(1.0f);
137 	camera->setFarClipDistance(2000.0f);
138 
139 	//Set up lighting
140 	Light *light = sceneMgr->createLight("Sun");
141 	light->setType(Light::LT_DIRECTIONAL);
142 	light->setDirection(Vector3(0.0f, -0.5f, 1.0f));
143 	sceneMgr->setAmbientLight(ColourValue(1, 1, 1));
144 
145 	//Load media (trees, grass, etc.)
146 	ResourceGroupManager::getSingleton().addResourceLocation("media/trees", "FileSystem");
147 	ResourceGroupManager::getSingleton().addResourceLocation("media/terrains", "FileSystem");
148 	ResourceGroupManager::getSingleton().addResourceLocation("media/grass", "FileSystem");
149 	ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
150 
151 	//Initialize OIS
152 	using namespace OIS;
153 	size_t windowHnd;
154 	window->getCustomAttribute("WINDOW", &windowHnd);
155 	inputManager = InputManager::createInputSystem(windowHnd);
156 
157 	keyboard = (Keyboard*)inputManager->createInputObject(OISKeyboard, false);
158 	mouse = (Mouse*)inputManager->createInputObject(OISMouse, false);
159 
160 	//Reset camera orientation
161 	camPitch = 0;
162 	camYaw = 0;
163 }
164 
~World()165 World::~World()
166 {
167 	//Shut down OIS
168 	inputManager->destroyInputObject(keyboard);
169 	inputManager->destroyInputObject(mouse);
170 	OIS::InputManager::destroyInputSystem(inputManager);
171 
172 	unload();
173 }
174 
175 
176 //[NOTE] In addition to some Ogre setup, this function configures PagedGeometry in the scene.
load()177 void World::load()
178 {
179 	//-------------------------------------- LOAD TERRAIN --------------------------------------
180 	//Setup the fog up to 500 units away
181 	sceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 700);
182 
183 	//Load the terrain
184 	sceneMgr->setWorldGeometry("terrain.cfg");
185 
186 	//Start off with the camera at the center of the terrain
187 	camera->setPosition(700, 100, 700);
188 
189 	//-------------------------------------- LOAD TREES --------------------------------------
190 	//Create and configure a new PagedGeometry instance for trees
191 	trees = new PagedGeometry(camera, 80);
192 	trees->addDetailLevel<BatchPage>(150, 50);
193 	trees->addDetailLevel<ImpostorPage>(500, 50);
194 
195 	//Create a new TreeLoader2D object
196 	TreeLoader2D *treeLoader = new TreeLoader2D(trees, TBounds(0, 0, 1500, 1500));
197 	trees->setPageLoader(treeLoader);
198 
199 	//Supply the height function to TreeLoader2D so it can calculate tree Y values
200 	HeightFunction::initialize(sceneMgr);
201 	treeLoader->setHeightFunction(&HeightFunction::getTerrainHeight);
202 
203 	//Load a tree entity
204 	Entity *myTree = sceneMgr->createEntity("Tree", "tree2.mesh");
205 
206 	//Randomly place 10,000 copies of the tree on the terrain
207 	Vector3 position = Vector3::ZERO;
208 	Radian yaw;
209 	Real scale;
210 	for (int i = 0; i < 10000; i++){
211 		yaw = Degree(Math::RangeRandom(0, 360));
212 		position.x = Math::RangeRandom(0, 1500);
213 		position.z = Math::RangeRandom(0, 1500);
214 		scale = Math::RangeRandom(0.5f, 0.6f);
215 
216 		treeLoader->addTree(myTree, position, yaw, scale);
217 	}
218 
219 	//-------------------------------------- LOAD BUSHES --------------------------------------
220 	//Create and configure a new PagedGeometry instance for bushes
221 	bushes = new PagedGeometry(camera, 50);
222 	bushes->addDetailLevel<BatchPage>(80, 50);
223 
224 	//Create a new TreeLoader2D object for the bushes
225 	TreeLoader2D *bushLoader = new TreeLoader2D(bushes, TBounds(0, 0, 1500, 1500));
226 	bushes->setPageLoader(bushLoader);
227 
228 	//Supply the height function to TreeLoader2D so it can calculate tree Y values
229 	HeightFunction::initialize(sceneMgr);
230 	bushLoader->setHeightFunction(&HeightFunction::getTerrainHeight);
231 
232 	//Load a bush entity
233 	Entity *myBush = sceneMgr->createEntity("Bush", "Bush.mesh");
234 
235 	//Randomly place 30,000 copies of the bush on the terrain
236 	for (int i = 0; i < 30000; i++){
237 		yaw = Degree(Math::RangeRandom(0, 360));
238 		position.x = Math::RangeRandom(0, 1500);
239 		position.z = Math::RangeRandom(0, 1500);
240 		scale = Math::RangeRandom(0.7f, 0.8f);
241 
242 		bushLoader->addTree(myBush, position, yaw, scale);
243 	}
244 }
245 
unload()246 void World::unload()
247 {
248 	//[NOTE] Always remember to delete any PageLoader(s) and PagedGeometry instances in order to avoid memory leaks.
249 
250 	//Delete the TreeLoader2D instances
251 	delete trees->getPageLoader();
252 	delete bushes->getPageLoader();
253 
254 	//Delete the PagedGeometry instances
255 	delete trees;
256 	delete bushes;
257 
258 	//Also delete the tree/bush entities
259 	sceneMgr->destroyEntity("Tree");
260 	sceneMgr->destroyEntity("Bush");
261 }
262 
run()263 void World::run()
264 {
265 	//Render loop
266 	running = true;
267 	while(running)
268 	{
269 		//Handle windows events
270 		WindowEventUtilities::messagePump();
271 
272 		//Update frame
273 		processInput();
274 		render();
275 
276 		//Exit immediately if the window is closed
277 		if (window->isClosed())
278 			break;
279 	}
280 }
281 
render()282 void World::render()
283 {
284 	//[NOTE] PagedGeometry::update() is called every frame to keep LODs, etc. up-to-date
285 	trees->update();
286 	bushes->update();
287 
288 	//Render the scene with Ogre
289 	root->renderOneFrame();
290 }
291 
processInput()292 void World::processInput()
293 {
294 	using namespace OIS;
295 	static Ogre::Timer timer;
296 	static unsigned long lastTime = 0;
297 	unsigned long currentTime = timer.getMilliseconds();
298 
299 	//Calculate the amount of time passed since the last frame
300 	Real timeScale = (currentTime - lastTime) * 0.001f;
301 	if (timeScale < 0.001f)
302 		timeScale = 0.001f;
303 	lastTime = currentTime;
304 
305 	//Get the current state of the keyboard and mouse
306 	keyboard->capture();
307 	mouse->capture();
308 
309 	//Always exit if ESC is pressed
310 	if (keyboard->isKeyDown(KC_ESCAPE))
311 		running = false;
312 
313 	//Reload the scene if R is pressed
314 	static bool reloadedLast = false;
315 	if (keyboard->isKeyDown(KC_R) && !reloadedLast){
316 		unload();
317 		load();
318 		reloadedLast = true;
319 	}
320 	else {
321 		reloadedLast = false;
322 	}
323 
324 	//Get mouse movement
325 	const OIS::MouseState &ms = mouse->getMouseState();
326 
327 	//Update camera rotation based on the mouse
328 	camYaw += Radian(-ms.X.rel / 200.0f);
329 	camPitch += Radian(-ms.Y.rel / 200.0f);
330 	camera->setOrientation(Quaternion::IDENTITY);
331 	camera->pitch(camPitch);
332 	camera->yaw(camYaw);
333 
334 	//Allow the camera to move around with the arrow/WASD keys
335 	Ogre::Vector3 trans(0, 0, 0);
336 	if (keyboard->isKeyDown(KC_UP) || keyboard->isKeyDown(KC_W))
337 		trans.z = -1;
338 	if (keyboard->isKeyDown(KC_DOWN) || keyboard->isKeyDown(KC_S))
339 		trans.z = 1;
340 	if (keyboard->isKeyDown(KC_RIGHT) || keyboard->isKeyDown(KC_D))
341 		trans.x = 1;
342 	if (keyboard->isKeyDown(KC_LEFT) || keyboard->isKeyDown(KC_A))
343 		trans.x = -1;
344 	if (keyboard->isKeyDown(KC_PGUP) || keyboard->isKeyDown(KC_E))
345 		trans.y = 1;
346 	if (keyboard->isKeyDown(KC_PGDOWN) || keyboard->isKeyDown(KC_Q))
347 		trans.y = -1;
348 
349 	//Shift = speed boost
350 	if (keyboard->isKeyDown(KC_LSHIFT) || keyboard->isKeyDown(KC_RSHIFT))
351 		trans *= 2;
352 
353 	trans *= 100;
354 	camera->moveRelative(trans * timeScale);
355 
356 	//Make sure the camera doesn't go under the terrain
357 	Ogre::Vector3 camPos = camera->getPosition();
358 	float terrY = HeightFunction::getTerrainHeight(camPos.x, camPos.z);
359 	if (camPos.y < terrY + 2 || !keyboard->isKeyDown(KC_SPACE)){		//Space = fly
360 		camPos.y = terrY + 2;
361 		camera->setPosition(camPos);
362 	}
363 }
364