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