[5] | 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 | float* pVertex = static_cast<float*>(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 | } |
---|