[692] | 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 | }
|
---|