1 #ifndef __Lighting_H__
2 #define __Lighting_H__
3 
4 #include "SdkSample.h"
5 
6 using namespace Ogre;
7 using namespace OgreBites;
8 
9 const uint8 cPriorityMain = 50;
10 const uint8 cPriorityQuery = 51;
11 const uint8 cPriorityLights = 55;
12 
13 
14 class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderObjectListener
15 {
16 public:
17 
Sample_Lighting()18 	Sample_Lighting() :
19 	  	mGreenLightAnimState(NULL),
20 		mYellowLightAnimState(NULL),
21 		mLight1BBFlare(NULL),
22 		mLight1BBQueryArea(NULL),
23 		mLight1BBQueryVisible(NULL),
24 		mLight2BBFlare(NULL),
25 		mLight2BBQueryArea(NULL),
26 		mLight2BBQueryVisible(NULL),
27 		mLight1QueryArea(NULL),
28 		mLight1QueryVisible(NULL),
29 		mLight2QueryArea(NULL),
30 		mLight2QueryVisible(NULL),
31         mActiveQuery(NULL),
32 		mUseOcclusionQuery(false),
33 		mDoOcclusionQuery(false)
34 
35 	{
36 		mInfo["Title"] = "Lighting";
37 		mInfo["Description"] = "Shows OGRE's lighting support. Also demonstrates "
38 			"usage of occlusion queries and automatic time-relative behaviour "
39 			"using billboards and controllers.";
40 		mInfo["Thumbnail"] = "thumb_lighting.png";
41 		mInfo["Category"] = "Lighting";
42 	}
43 
frameRenderingQueued(const FrameEvent & evt)44     bool frameRenderingQueued(const FrameEvent& evt)
45     {
46 		// Move the lights along their paths
47 		mGreenLightAnimState->addTime(evt.timeSinceLastFrame);
48 		mYellowLightAnimState->addTime(evt.timeSinceLastFrame);
49 
50 		// Modulate the light flare according to performed occlusion queries
51 		if (mUseOcclusionQuery)
52 		{
53 			// Stop occlusion queries until we get their information
54 			// (may not happen on the same frame they are requested in)
55 			mDoOcclusionQuery = false;
56 
57 			// Check if all query information available
58 			if ((mLight1QueryArea->isStillOutstanding() == false) &&
59 				(mLight1QueryVisible->isStillOutstanding() == false) &&
60 				(mLight2QueryArea->isStillOutstanding() == false) &&
61 				(mLight2QueryVisible->isStillOutstanding() == false))
62 			{
63 				// Modulate the lights according to the query data
64 				unsigned int lightAreaCount;
65 				unsigned int lightVisibleCount;
66 				float ratio;
67 
68 				mLight1QueryArea->pullOcclusionQuery(&lightAreaCount);
69 				mLight1QueryVisible->pullOcclusionQuery(&lightVisibleCount);
70 				ratio = float(lightVisibleCount) / float(lightAreaCount);
71 				mLight1BBFlare->setColour(mTrail->getInitialColour(0) * ratio);
72 
73 				mLight2QueryArea->pullOcclusionQuery(&lightAreaCount);
74 				mLight2QueryVisible->pullOcclusionQuery(&lightVisibleCount);
75 				ratio = float(lightVisibleCount) / float(lightAreaCount);
76 				mLight2BBFlare->setColour(mTrail->getInitialColour(1) * ratio);
77 
78 				// Request new query data
79 				mDoOcclusionQuery = true;
80 			}
81 		}
82 
83 
84 		return SdkSample::frameRenderingQueued(evt);   // don't forget the parent class updates!
85     }
86 
87 protected:
88 
setupContent()89 	void setupContent()
90 	{
91 		// Set our camera to orbit around the origin at a suitable distance
92 		mCameraMan->setStyle(CS_ORBIT);
93 		mCameraMan->setYawPitchDist(Radian(0), Radian(0), 400);
94 
95 		mTrayMgr->showCursor();
96 
97 		// Create an ogre head and place it at the origin
98 		Entity* head = mSceneMgr->createEntity("Head", "ogrehead.mesh");
99 		head->setRenderQueueGroup(cPriorityMain);
100 		mSceneMgr->getRootSceneNode()->attachObject(head);
101 
102 		setupLights();
103 	}
104 
setupLights()105 	void setupLights()
106 	{
107 
108 		mSceneMgr->setAmbientLight(ColourValue(0.1, 0.1, 0.1));  // Dim ambient lighting
109 
110 		// Create a ribbon trail that our lights will leave behind
111 		NameValuePairList params;
112 		params["numberOfChains"] = "2";
113 		params["maxElements"] = "80";
114 		mTrail = (RibbonTrail*)mSceneMgr->createMovableObject("RibbonTrail", &params);
115 		mSceneMgr->getRootSceneNode()->attachObject(mTrail);
116 		mTrail->setMaterialName("Examples/LightRibbonTrail");
117 		mTrail->setTrailLength(400);
118 		mTrail->setRenderQueueGroup(cPriorityLights);
119 
120 		// Create the occlusion queries to be used in this sample
121 		try {
122 			RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem();
123 			mLight1QueryArea = renderSystem->createHardwareOcclusionQuery();
124 			mLight1QueryVisible = renderSystem->createHardwareOcclusionQuery();
125 			mLight2QueryArea = renderSystem->createHardwareOcclusionQuery();
126 			mLight2QueryVisible = renderSystem->createHardwareOcclusionQuery();
127 
128 			mUseOcclusionQuery = (mLight1QueryArea != NULL) &&
129 				(mLight1QueryVisible != NULL) &&
130 				(mLight2QueryArea != NULL) &&
131 				(mLight2QueryVisible != NULL);
132 		}
133 		catch (Ogre::Exception e)
134 		{
135 			mUseOcclusionQuery = false;
136 		}
137 
138 		if (mUseOcclusionQuery == false)
139 		{
140 			LogManager::getSingleton().logMessage("Sample_Lighting - Error: failed to create hardware occlusion query", LML_CRITICAL);
141 		}
142 
143 		// Create the materials to be used by the objects used fo the occlusion query
144 		MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
145 		MaterialPtr matQueryArea = matBase->clone("QueryArea");
146 		matQueryArea->setDepthWriteEnabled(false);
147 		matQueryArea->setColourWriteEnabled(false);
148 		matQueryArea->setDepthCheckEnabled(false); // Not occluded by objects
149 		MaterialPtr matQueryVisible = matBase->clone("QueryVisible");
150 		matQueryVisible->setDepthWriteEnabled(false);
151 		matQueryVisible->setColourWriteEnabled(false);
152 		matQueryVisible->setDepthCheckEnabled(true); // Occluded by objects
153 
154 		SceneNode* node;
155 		Animation* anim;
156 		NodeAnimationTrack* track;
157 		Light* light;
158 		BillboardSet* bbs;
159 
160 		// Create a light node
161 		node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(50, 30, 0));
162 
163 		// Create a 14 second animation with spline interpolation
164 		anim = mSceneMgr->createAnimation("Path1", 14);
165 		anim->setInterpolationMode(Animation::IM_SPLINE);
166 
167 		track = anim->createNodeTrack(1, node);  // Create a node track for our animation
168 
169 		// Enter keyframes for our track to define a path for the light to follow
170 		track->createNodeKeyFrame(0)->setTranslate(Vector3(50, 30, 0));
171 		track->createNodeKeyFrame(2)->setTranslate(Vector3(100, -30, 0));
172 		track->createNodeKeyFrame(4)->setTranslate(Vector3(120, -80, 150));
173 		track->createNodeKeyFrame(6)->setTranslate(Vector3(30, -80, 50));
174 		track->createNodeKeyFrame(8)->setTranslate(Vector3(-50, 30, -50));
175 		track->createNodeKeyFrame(10)->setTranslate(Vector3(-150, -20, -100));
176 		track->createNodeKeyFrame(12)->setTranslate(Vector3(-50, -30, 0));
177 		track->createNodeKeyFrame(14)->setTranslate(Vector3(50, 30, 0));
178 
179 		// Create an animation state from the animation and enable it
180 		mYellowLightAnimState = mSceneMgr->createAnimationState("Path1");
181 		mYellowLightAnimState->setEnabled(true);
182 
183 		// Set initial settings for the ribbon mTrail and add the light node
184 		mTrail->setInitialColour(0, 1.0, 0.8, 0);
185 		mTrail->setColourChange(0, 0.5, 0.5, 0.5, 0.5);
186 		mTrail->setInitialWidth(0, 5);
187 		mTrail->addNode(node);
188 
189 
190 		// Attach a light with the same colour to the light node
191 		light = mSceneMgr->createLight();
192 		light->setDiffuseColour(mTrail->getInitialColour(0));
193 		node->attachObject(light);
194 
195 		// Attach a flare with the same colour to the light node
196 		bbs = mSceneMgr->createBillboardSet(1);
197 		mLight1BBFlare = bbs->createBillboard(Vector3::ZERO, mTrail->getInitialColour(0));
198 		bbs->setMaterialName("Examples/Flare");
199 		bbs->setRenderQueueGroup(cPriorityLights);
200 		node->attachObject(bbs);
201 
202 		if (mUseOcclusionQuery)
203 		{
204 			// Attach a billboard which will be used to get a relative area occupied by the light
205 			mLight1BBQueryArea = mSceneMgr->createBillboardSet(1);
206 			mLight1BBQueryArea->setDefaultDimensions(10,10);
207 			mLight1BBQueryArea->createBillboard(Vector3::ZERO);
208 			mLight1BBQueryArea->setMaterialName("QueryArea");
209 			mLight1BBQueryArea->setRenderQueueGroup(cPriorityQuery);
210 			node->attachObject(mLight1BBQueryArea);
211 
212 			// Attach a billboard which will be used to get the visible area occupied by the light
213 			mLight1BBQueryVisible = mSceneMgr->createBillboardSet(1);
214 			mLight1BBQueryVisible->setDefaultDimensions(10,10);
215 			mLight1BBQueryVisible->createBillboard(Vector3::ZERO);
216 			mLight1BBQueryVisible->setMaterialName("QueryVisible");
217 			mLight1BBQueryVisible->setRenderQueueGroup(cPriorityQuery);
218 			node->attachObject(mLight1BBQueryVisible);
219 		}
220 
221 		// Create a second light node
222 		node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-50, 100, 0));
223 
224 		// Create a 10 second animation with spline interpolation
225 		anim = mSceneMgr->createAnimation("Path2", 10);
226 		anim->setInterpolationMode(Animation::IM_SPLINE);
227 
228 		track = anim->createNodeTrack(1, node);  // Create a node track for our animation
229 
230 		// Enter keyframes for our track to define a path for the light to follow
231 		track->createNodeKeyFrame(0)->setTranslate(Vector3(-50, 100, 0));
232 		track->createNodeKeyFrame(2)->setTranslate(Vector3(-100, 150, -30));
233 		track->createNodeKeyFrame(4)->setTranslate(Vector3(-200, 0, 40));
234 		track->createNodeKeyFrame(6)->setTranslate(Vector3(0, -150, 70));
235 		track->createNodeKeyFrame(8)->setTranslate(Vector3(50, 0, 30));
236 		track->createNodeKeyFrame(10)->setTranslate(Vector3(-50, 100, 0));
237 
238 		// Create an animation state from the animation and enable it
239 		mGreenLightAnimState = mSceneMgr->createAnimationState("Path2");
240 		mGreenLightAnimState->setEnabled(true);
241 
242 		// Set initial settings for the ribbon mTrail and add the light node
243 		mTrail->setInitialColour(1, 0.0, 1.0, 0.4);
244 		mTrail->setColourChange(1, 0.5, 0.5, 0.5, 0.5);
245 		mTrail->setInitialWidth(1, 5);
246 		mTrail->addNode(node);
247 
248 		// Attach a light with the same colour to the light node
249 		light = mSceneMgr->createLight();
250 		light->setDiffuseColour(mTrail->getInitialColour(1));
251 		node->attachObject(light);
252 
253 		// Attach a flare with the same colour to the light node
254 		bbs = mSceneMgr->createBillboardSet(1);
255 		mLight2BBFlare = bbs->createBillboard(Vector3::ZERO, mTrail->getInitialColour(1));
256 		bbs->setMaterialName("Examples/Flare");
257 		bbs->setRenderQueueGroup(cPriorityLights);
258 		node->attachObject(bbs);
259 
260 		if (mUseOcclusionQuery)
261 		{
262 			// Attach a billboard which will be used to get a relative area occupied by the light
263 			mLight2BBQueryArea = mSceneMgr->createBillboardSet(1);
264 			mLight2BBQueryArea->setDefaultDimensions(10,10);
265 			mLight2BBQueryArea->createBillboard(Vector3::ZERO);
266 			mLight2BBQueryArea->setMaterialName("QueryArea");
267 			mLight2BBQueryArea->setRenderQueueGroup(cPriorityQuery);
268 			node->attachObject(mLight2BBQueryArea);
269 
270 			// Attach a billboard which will be used to get the visible area occupied by the light
271 			mLight2BBQueryVisible = mSceneMgr->createBillboardSet(1);
272 			mLight2BBQueryVisible->setDefaultDimensions(10,10);
273 			mLight2BBQueryVisible->createBillboard(Vector3::ZERO);
274 			mLight2BBQueryVisible->setMaterialName("QueryVisible");
275 			mLight2BBQueryVisible->setRenderQueueGroup(cPriorityQuery);
276 			node->attachObject(mLight2BBQueryVisible);
277 		}
278 
279 		// Setup the listener for the occlusion query
280 		if (mUseOcclusionQuery)
281 		{
282 			mSceneMgr->addRenderObjectListener(this);
283 			mDoOcclusionQuery = true;
284 		}
285 	}
286 
287 	// Event raised when render single object started.
notifyRenderSingleObject(Renderable * rend,const Pass * pass,const AutoParamDataSource * source,const LightList * pLightList,bool suppressRenderStateChanges)288 	virtual void notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source,
289 			const LightList* pLightList, bool suppressRenderStateChanges)
290 	{
291 		//
292 		// The following code activates and deactivates the occlusion queries
293 		// so that the queries only include the rendering of their intended targets
294 		//
295 
296 		// Close the last occlusion query
297 		// Each occlusion query should only last a single rendering
298 		if (mActiveQuery != NULL)
299 		{
300 			mActiveQuery->endOcclusionQuery();
301 			mActiveQuery = NULL;
302 		}
303 
304 		// Open a new occlusion query
305 		if (mDoOcclusionQuery == true)
306 		{
307 			// Check if a the object being rendered needs
308 			// to be occlusion queried, and by which query instance.
309 			if (rend == mLight1BBQueryArea)
310 				mActiveQuery = mLight1QueryArea;
311 			else if (rend == mLight1BBQueryVisible)
312 				mActiveQuery = mLight1QueryVisible;
313 			else if (rend == mLight2BBQueryArea)
314 				mActiveQuery = mLight2QueryArea;
315 			else if (rend == mLight2BBQueryVisible)
316 				mActiveQuery = mLight2QueryVisible;
317 
318 			if (mActiveQuery != NULL)
319 			{
320 				mActiveQuery->beginOcclusionQuery();
321 			}
322 		}
323 	}
324 
cleanupContent()325     void cleanupContent()
326     {
327         RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem();
328 		if (mLight1QueryArea != NULL)
329             renderSystem->destroyHardwareOcclusionQuery(mLight1QueryArea);
330 		if (mLight1QueryVisible != NULL)
331             renderSystem->destroyHardwareOcclusionQuery(mLight1QueryVisible);
332 		if (mLight2QueryArea != NULL)
333             renderSystem->destroyHardwareOcclusionQuery(mLight2QueryArea);
334 		if (mLight2QueryVisible != NULL)
335             renderSystem->destroyHardwareOcclusionQuery(mLight2QueryVisible);
336     }
337 
338 	AnimationState* mGreenLightAnimState;
339 	AnimationState* mYellowLightAnimState;
340 
341 	RibbonTrail* mTrail;
342 
343 	Billboard* mLight1BBFlare;
344 	BillboardSet* mLight1BBQueryArea;
345 	BillboardSet* mLight1BBQueryVisible;
346 	Billboard* mLight2BBFlare;
347 	BillboardSet* mLight2BBQueryArea;
348 	BillboardSet* mLight2BBQueryVisible;
349 
350 	HardwareOcclusionQuery* mLight1QueryArea;
351 	HardwareOcclusionQuery* mLight1QueryVisible;
352 	HardwareOcclusionQuery* mLight2QueryArea;
353 	HardwareOcclusionQuery* mLight2QueryVisible;
354 	HardwareOcclusionQuery* mActiveQuery;
355 
356 	bool mUseOcclusionQuery;
357 	bool mDoOcclusionQuery;
358 };
359 
360 #endif
361