1 | /******************************************************************************
|
---|
2 | Copyright (c) W.J. van der Laan
|
---|
3 |
|
---|
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of
|
---|
5 | this software and associated documentation files (the "Software"), to deal in
|
---|
6 | the Software without restriction, including without limitation the rights to use,
|
---|
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
---|
8 | Software, and to permit persons to whom the Software is furnished to do so, subject
|
---|
9 | to the following conditions:
|
---|
10 |
|
---|
11 | The above copyright notice and this permission notice shall be included in all copies
|
---|
12 | or substantial portions of the Software.
|
---|
13 |
|
---|
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
---|
15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
---|
16 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
---|
17 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
---|
18 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE
|
---|
19 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
---|
20 | ******************************************************************************/
|
---|
21 | #include "MLight.h"
|
---|
22 |
|
---|
23 | #include "OgreStringConverter.h"
|
---|
24 | #include "OgreException.h"
|
---|
25 |
|
---|
26 | #include "OgreMesh.h"
|
---|
27 | #include "OgreSubMesh.h"
|
---|
28 | #include "OgreResourceGroupManager.h"
|
---|
29 | #include "OgreMeshManager.h"
|
---|
30 | #include "OgreHardwareVertexBuffer.h"
|
---|
31 | #include "OgreHardwarePixelBuffer.h"
|
---|
32 | #include "OgreHardwareBufferManager.h"
|
---|
33 |
|
---|
34 | #include "OgreRoot.h"
|
---|
35 |
|
---|
36 | #include "OgreCamera.h"
|
---|
37 |
|
---|
38 | #include "MaterialGenerator.h"
|
---|
39 |
|
---|
40 | using namespace Ogre;
|
---|
41 | //-----------------------------------------------------------------------
|
---|
42 | MLight::MLight(MaterialGenerator *sys):
|
---|
43 | bIgnoreWorld(false), mGenerator(sys),mPermutation(0)
|
---|
44 | {
|
---|
45 | // Set up geometry
|
---|
46 | //setMaterial("DeferredShading/Post/LightMaterial");
|
---|
47 | // Set render priority to high (just after normal postprocess)
|
---|
48 | setRenderQueueGroup(RENDER_QUEUE_2);
|
---|
49 | // Allocate render operation
|
---|
50 | mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
|
---|
51 | mRenderOp.indexData = 0;
|
---|
52 | mRenderOp.vertexData = 0;
|
---|
53 | mRenderOp.useIndexes = true;
|
---|
54 |
|
---|
55 | // Diffuse and specular colour
|
---|
56 | setDiffuseColour(Ogre::ColourValue(1,1,1));
|
---|
57 | setSpecularColour(Ogre::ColourValue(0,0,0));
|
---|
58 | // Set Attenuation
|
---|
59 | setAttenuation(1.0f,0.0f,0.0f);
|
---|
60 | }
|
---|
61 | //-----------------------------------------------------------------------
|
---|
62 | MLight::~MLight()
|
---|
63 | {
|
---|
64 | // need to release IndexData and vertexData created for renderable
|
---|
65 | delete mRenderOp.indexData;
|
---|
66 | delete mRenderOp.vertexData;
|
---|
67 | }
|
---|
68 | //-----------------------------------------------------------------------
|
---|
69 | void MLight::setAttenuation(float c, float b, float a)
|
---|
70 | {
|
---|
71 | // Set Attenuation parameter to shader
|
---|
72 | setCustomParameter(3, Vector4(c, b, a, 0));
|
---|
73 |
|
---|
74 | /// There is attenuation? Set material accordingly
|
---|
75 | if(c != 1.0f || b != 0.0f || a != 0.0f)
|
---|
76 | mPermutation |= MI_ATTENUATED;
|
---|
77 | else
|
---|
78 | mPermutation &= ~MI_ATTENUATED;
|
---|
79 |
|
---|
80 | // Calculate radius from Attenuation
|
---|
81 | int threshold_level = 15;// differece of 10-15 levels deemed unnoticable
|
---|
82 | float threshold = 1.0f/((float)threshold_level/256.0f);
|
---|
83 |
|
---|
84 | // Use quadratic formula to determine outer radius
|
---|
85 | c = c-threshold;
|
---|
86 | float d=sqrt(b*b-4*a*c);
|
---|
87 | float x=(-2*c)/(b+d);
|
---|
88 |
|
---|
89 | rebuildGeometry(x);
|
---|
90 | }
|
---|
91 | //-----------------------------------------------------------------------
|
---|
92 | void MLight::setDiffuseColour(const Ogre::ColourValue &col)
|
---|
93 | {
|
---|
94 | setCustomParameter(1, Vector4(col.r, col.g, col.b, col.a));
|
---|
95 | }
|
---|
96 | //-----------------------------------------------------------------------
|
---|
97 | void MLight::setSpecularColour(const Ogre::ColourValue &col)
|
---|
98 | {
|
---|
99 | setCustomParameter(2, Vector4(col.r, col.g, col.b, col.a));
|
---|
100 | /// There is a specular component? Set material accordingly
|
---|
101 |
|
---|
102 | if(col.r != 0.0f || col.g != 0.0f || col.b != 0.0f)
|
---|
103 | mPermutation |= MI_SPECULAR;
|
---|
104 | else
|
---|
105 | mPermutation &= ~MI_SPECULAR;
|
---|
106 |
|
---|
107 | }
|
---|
108 | //-----------------------------------------------------------------------
|
---|
109 | Ogre::ColourValue MLight::getDiffuseColour()
|
---|
110 | {
|
---|
111 | Ogre::Vector4 val = getCustomParameter(1);
|
---|
112 | return Ogre::ColourValue(val[0], val[1], val[2], val[3]);
|
---|
113 | }
|
---|
114 | //-----------------------------------------------------------------------
|
---|
115 | Ogre::ColourValue MLight::getSpecularColour()
|
---|
116 | {
|
---|
117 | Ogre::Vector4 val = getCustomParameter(2);
|
---|
118 | return Ogre::ColourValue(val[0], val[1], val[2], val[3]);
|
---|
119 | }
|
---|
120 | //-----------------------------------------------------------------------
|
---|
121 | void MLight::rebuildGeometry(float radius)
|
---|
122 | {
|
---|
123 | // Scale node to radius
|
---|
124 |
|
---|
125 | if(radius > 10000.0f)
|
---|
126 | {
|
---|
127 | createRectangle2D();
|
---|
128 | mPermutation |= MI_QUAD;
|
---|
129 | }
|
---|
130 | else
|
---|
131 | {
|
---|
132 | /// XXX some more intelligent expression for rings and segments
|
---|
133 | createSphere(radius, 5, 5);
|
---|
134 | mPermutation &= ~MI_QUAD;
|
---|
135 | }
|
---|
136 | }
|
---|
137 | //-----------------------------------------------------------------------
|
---|
138 | void MLight::createRectangle2D()
|
---|
139 | {
|
---|
140 | /// XXX this RenderOp should really be re-used between MLight objects,
|
---|
141 | /// not generated every time
|
---|
142 | delete mRenderOp.vertexData;
|
---|
143 | delete mRenderOp.indexData;
|
---|
144 | mRenderOp.vertexData = new VertexData();
|
---|
145 | mRenderOp.indexData = 0;
|
---|
146 |
|
---|
147 | mRenderOp.vertexData->vertexCount = 4;
|
---|
148 | mRenderOp.vertexData->vertexStart = 0;
|
---|
149 | mRenderOp.operationType = RenderOperation::OT_TRIANGLE_STRIP;
|
---|
150 | mRenderOp.useIndexes = false;
|
---|
151 |
|
---|
152 | VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
|
---|
153 | VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;
|
---|
154 |
|
---|
155 | decl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
|
---|
156 |
|
---|
157 | HardwareVertexBufferSharedPtr vbuf =
|
---|
158 | HardwareBufferManager::getSingleton().createVertexBuffer(
|
---|
159 | decl->getVertexSize(0),
|
---|
160 | mRenderOp.vertexData->vertexCount,
|
---|
161 | HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
---|
162 |
|
---|
163 | // Bind buffer
|
---|
164 | bind->setBinding(0, vbuf);
|
---|
165 | // Upload data
|
---|
166 | float data[]={
|
---|
167 | -1,1,-1, // corner 1
|
---|
168 | -1,-1,-1, // corner 2
|
---|
169 | 1,1,-1, // corner 3
|
---|
170 | 1,-1,-1}; // corner 4
|
---|
171 | vbuf->writeData(0, sizeof(data), data, true);
|
---|
172 |
|
---|
173 | // Set bounding
|
---|
174 | setBoundingBox(AxisAlignedBox(-10000,-10000,-10000,10000,10000,10000));
|
---|
175 | mRadius = 15000;
|
---|
176 | bIgnoreWorld = true;
|
---|
177 | }
|
---|
178 | //-----------------------------------------------------------------------
|
---|
179 | void MLight::createSphere(const float r, const int nRings, const int nSegments)
|
---|
180 | {
|
---|
181 | delete mRenderOp.vertexData;
|
---|
182 | delete mRenderOp.indexData;
|
---|
183 | mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
|
---|
184 | mRenderOp.indexData = new IndexData();
|
---|
185 | mRenderOp.vertexData = new VertexData();
|
---|
186 | mRenderOp.useIndexes = true;
|
---|
187 |
|
---|
188 | VertexData* vertexData = mRenderOp.vertexData;
|
---|
189 | IndexData* indexData = mRenderOp.indexData;
|
---|
190 |
|
---|
191 | // define the vertex format
|
---|
192 | VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
|
---|
193 | size_t currOffset = 0;
|
---|
194 | // only generate positions
|
---|
195 | vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
|
---|
196 | currOffset += VertexElement::getTypeSize(VET_FLOAT3);
|
---|
197 | // allocate the vertex buffer
|
---|
198 | vertexData->vertexCount = (nRings + 1) * (nSegments+1);
|
---|
199 | HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
|
---|
200 | VertexBufferBinding* binding = vertexData->vertexBufferBinding;
|
---|
201 | binding->setBinding(0, vBuf);
|
---|
202 | Real* pVertex = static_cast<Real*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));
|
---|
203 |
|
---|
204 | // allocate index buffer
|
---|
205 | indexData->indexCount = 6 * nRings * (nSegments + 1);
|
---|
206 | indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
|
---|
207 | HardwareIndexBufferSharedPtr iBuf = indexData->indexBuffer;
|
---|
208 | unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));
|
---|
209 |
|
---|
210 | float fDeltaRingAngle = (Math::PI / nRings);
|
---|
211 | float fDeltaSegAngle = (2 * Math::PI / nSegments);
|
---|
212 | unsigned short wVerticeIndex = 0 ;
|
---|
213 |
|
---|
214 | // Generate the group of rings for the sphere
|
---|
215 | for( int ring = 0; ring <= nRings; ring++ ) {
|
---|
216 | float r0 = r * sinf (ring * fDeltaRingAngle);
|
---|
217 | float y0 = r * cosf (ring * fDeltaRingAngle);
|
---|
218 |
|
---|
219 | // Generate the group of segments for the current ring
|
---|
220 | for(int seg = 0; seg <= nSegments; seg++) {
|
---|
221 | float x0 = r0 * sinf(seg * fDeltaSegAngle);
|
---|
222 | float z0 = r0 * cosf(seg * fDeltaSegAngle);
|
---|
223 |
|
---|
224 | // Add one vertex to the strip which makes up the sphere
|
---|
225 | *pVertex++ = x0;
|
---|
226 | *pVertex++ = y0;
|
---|
227 | *pVertex++ = z0;
|
---|
228 |
|
---|
229 | if (ring != nRings)
|
---|
230 | {
|
---|
231 | // each vertex (except the last) has six indicies pointing to it
|
---|
232 | *pIndices++ = wVerticeIndex + nSegments + 1;
|
---|
233 | *pIndices++ = wVerticeIndex;
|
---|
234 | *pIndices++ = wVerticeIndex + nSegments;
|
---|
235 | *pIndices++ = wVerticeIndex + nSegments + 1;
|
---|
236 | *pIndices++ = wVerticeIndex + 1;
|
---|
237 | *pIndices++ = wVerticeIndex;
|
---|
238 | wVerticeIndex ++;
|
---|
239 | }
|
---|
240 | }; // end for seg
|
---|
241 | } // end for ring
|
---|
242 |
|
---|
243 | // Unlock
|
---|
244 | vBuf->unlock();
|
---|
245 | iBuf->unlock();
|
---|
246 |
|
---|
247 | // Set bounding box and sphere
|
---|
248 | setBoundingBox( AxisAlignedBox( Vector3(-r, -r, -r), Vector3(r, r, r) ) );
|
---|
249 | mRadius = r;
|
---|
250 | bIgnoreWorld = false;
|
---|
251 | }
|
---|
252 | //-----------------------------------------------------------------------
|
---|
253 | Real MLight::getBoundingRadius(void) const
|
---|
254 | {
|
---|
255 | return mRadius;
|
---|
256 | }
|
---|
257 | //-----------------------------------------------------------------------
|
---|
258 | Ogre::Real MLight::getSquaredViewDepth(const Ogre::Camera* cam) const
|
---|
259 | {
|
---|
260 | if(bIgnoreWorld)
|
---|
261 | {
|
---|
262 | return 0.0f;
|
---|
263 | }
|
---|
264 | else
|
---|
265 | {
|
---|
266 | Vector3 dist = cam->getDerivedPosition() - getWorldPosition();
|
---|
267 | return dist.squaredLength();
|
---|
268 | }
|
---|
269 | }
|
---|
270 | //-----------------------------------------------------------------------
|
---|
271 | const MaterialPtr& MLight::getMaterial(void) const
|
---|
272 | {
|
---|
273 | return mGenerator->getMaterial(mPermutation);
|
---|
274 | }
|
---|