00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "CaelumPrecompiled.h"
00022 #include "CaelumExceptions.h"
00023 #include "InternalUtilities.h"
00024 #include "PrivatePtr.h"
00025
00026 namespace Caelum
00027 {
00028 Ogre::ColourValue InternalUtilities::getInterpolatedColour (
00029 float fx, float fy, Ogre::Image *img, bool wrapX)
00030 {
00031
00032 int imgWidth = static_cast<int>(img->getWidth ());
00033 int imgHeight = static_cast<int>(img->getHeight ());
00034
00035
00036 int py = Ogre::Math::IFloor(Ogre::Math::Abs (fy) * (imgHeight - 1));
00037
00038 py = std::max(0, std::min(py, imgHeight - 1));
00039
00040
00041
00042 float px = fx * (img->getWidth () - 1);
00043 int px1, px2;
00044 px1 = Ogre::Math::IFloor(px);
00045 px2 = Ogre::Math::ICeil(px);
00046
00047 if (wrapX) {
00048
00049
00050 px1 = (px1 % imgWidth + imgWidth) % imgWidth;
00051 px2 = (px2 % imgWidth + imgWidth) % imgWidth;
00052 } else {
00053 px1 = std::max(0, std::min(px1, imgWidth - 1));
00054 px2 = std::max(0, std::min(px2, imgWidth - 1));
00055 }
00056
00057
00058 Ogre::ColourValue c1, c2, cf;
00059 c1 = img->getColourAt (px1, py, 0);
00060 c2 = img->getColourAt (px2, py, 0);
00061
00062
00063
00064 float diff = px - px1;
00065 cf = c1 * (1 - diff) + c2 * diff;
00066
00067 return cf;
00068 }
00069
00070 const Ogre::String InternalUtilities::pointerToString (void* pointer)
00071 {
00072 std::stringstream stream;
00073 stream.width(2 * sizeof(void *));
00074 stream.fill('0');
00075 stream.unsetf(std::ios::dec);
00076 stream.setf(std::ios::hex);
00077 stream.setf(std::ios::uppercase);
00078 stream << reinterpret_cast<ptrdiff_t>(pointer);
00079 return stream.str();
00080 }
00081
00082 Ogre::MaterialPtr InternalUtilities::checkLoadMaterialClone (
00083 const Ogre::String& originalName,
00084 const Ogre::String& cloneName)
00085 {
00086 Ogre::MaterialPtr scriptMaterial = Ogre::MaterialManager::getSingletonPtr()->getByName(originalName);
00087 if (scriptMaterial.isNull()) {
00088 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00089 "Can't find material \"" + originalName + "\"",
00090 "Caelum");
00091 }
00092
00093
00094 Caelum::PrivateMaterialPtr clonedMaterial (scriptMaterial->clone (cloneName));
00095
00096
00097 clonedMaterial->load ();
00098 if (clonedMaterial->getBestTechnique () == 0) {
00099 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00100 "Can't load material \"" + originalName + "\": " + clonedMaterial->getUnsupportedTechniquesExplanation(),
00101 "Caelum");
00102 }
00103
00104 return clonedMaterial.release();
00105 }
00106
00107 Ogre::CompositorPtr InternalUtilities::checkCompositorSupported (const Ogre::String& name)
00108 {
00109 Ogre::CompositorPtr comp = Ogre::CompositorManager::getSingletonPtr()->getByName(name);
00110 if (comp.isNull()) {
00111 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00112 "Can't find compositor \"" + name + "\"",
00113 "Caelum");
00114 }
00115
00116
00117 comp->load ();
00118 if (comp->getNumSupportedTechniques () == 0) {
00119 CAELUM_THROW_UNSUPPORTED_EXCEPTION (
00120 "Can't load compositor \"" + name + "\"",
00121 "Caelum");
00122 }
00123
00124 return comp;
00125 }
00126
00127 void InternalUtilities::generateSphericDome (const Ogre::String &name, int segments, DomeType type)
00128 {
00129
00130 if (Ogre::MeshManager::getSingleton ().resourceExists (name)) {
00131 return;
00132 }
00133
00134 Ogre::LogManager::getSingleton ().logMessage (
00135 "Caelum: Creating " + name + " sphere mesh resource...");
00136
00137
00138 Ogre::MeshPtr msh = Ogre::MeshManager::getSingleton ().createManual (name, RESOURCE_GROUP_NAME);
00139
00140 Ogre::SubMesh *sub = msh->createSubMesh ();
00141
00142
00143 Ogre::VertexData *vertexData = new Ogre::VertexData ();
00144 msh->sharedVertexData = vertexData;
00145
00146
00147 Ogre::VertexDeclaration *vertexDecl = vertexData->vertexDeclaration;
00148 size_t currOffset = 0;
00149
00150 vertexDecl->addElement (0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
00151 currOffset += Ogre::VertexElement::getTypeSize (Ogre::VET_FLOAT3);
00152
00153 vertexDecl->addElement (0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
00154 currOffset += Ogre::VertexElement::getTypeSize (Ogre::VET_FLOAT3);
00155
00156 vertexDecl->addElement (0, currOffset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
00157 currOffset += Ogre::VertexElement::getTypeSize (Ogre::VET_FLOAT2);
00158
00159
00160 switch (type) {
00161 case DT_SKY_DOME:
00162 vertexData->vertexCount = segments * (segments - 1) + 2;
00163 break;
00164 case DT_IMAGE_STARFIELD:
00165 vertexData->vertexCount = (segments + 1) * (segments + 1);
00166 break;
00167 };
00168 Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton ().createVertexBuffer (vertexDecl->getVertexSize (0), vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
00169 Ogre::VertexBufferBinding *binding = vertexData->vertexBufferBinding;
00170 binding->setBinding (0, vBuf);
00171
00172 float *pVertex = static_cast<float *>(vBuf->lock (Ogre::HardwareBuffer::HBL_DISCARD));
00173
00174
00175 switch (type) {
00176 case DT_SKY_DOME:
00177 sub->indexData->indexCount = 2 * segments * (segments - 1) * 3;
00178 break;
00179 case DT_IMAGE_STARFIELD:
00180 sub->indexData->indexCount = 2 * (segments - 1) * segments * 3;
00181 break;
00182 };
00183 sub->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton ().createIndexBuffer (Ogre::HardwareIndexBuffer::IT_16BIT, sub->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
00184 Ogre::HardwareIndexBufferSharedPtr iBuf = sub->indexData->indexBuffer;
00185 unsigned short *pIndices = static_cast<unsigned short *>(iBuf->lock (Ogre::HardwareBuffer::HBL_DISCARD));
00186
00187
00188 switch (type) {
00189 case DT_SKY_DOME:
00190 fillGradientsDomeBuffers (pVertex, pIndices, segments);
00191 break;
00192 case DT_IMAGE_STARFIELD:
00193 fillStarfieldDomeBuffers (pVertex, pIndices, segments);
00194 break;
00195 };
00196
00197
00198 vBuf->unlock ();
00199
00200
00201 iBuf->unlock ();
00202
00203
00204 sub->useSharedVertices = true;
00205 msh->_setBounds (Ogre::AxisAlignedBox (-1, -1, -1, 1, 1, 1), false);
00206 msh->_setBoundingSphereRadius (1);
00207 msh->load ();
00208
00209 Ogre::LogManager::getSingleton ().logMessage (
00210 "Caelum: generateSphericDome DONE");
00211 }
00212
00213 void InternalUtilities::fillGradientsDomeBuffers (float *pVertex, unsigned short *pIndices, int segments)
00214 {
00215 const float deltaLatitude = Ogre::Math::PI / (float )segments;
00216 const float deltaLongitude = Ogre::Math::PI * 2.0 / (float )segments;
00217
00218
00219 for (int i = 1; i < segments; i++) {
00220 float r0 = Ogre::Math::Sin (Ogre::Radian (i * deltaLatitude));
00221 float y0 = Ogre::Math::Cos (Ogre::Radian (i * deltaLatitude));
00222
00223 for (int j = 0; j < segments; j++) {
00224 float x0 = r0 * Ogre::Math::Sin (Ogre::Radian (j * deltaLongitude));
00225 float z0 = r0 * Ogre::Math::Cos (Ogre::Radian (j * deltaLongitude));
00226
00227 *pVertex++ = x0;
00228 *pVertex++ = y0;
00229 *pVertex++ = z0;
00230
00231 *pVertex++ = -x0;
00232 *pVertex++ = -y0;
00233 *pVertex++ = -z0;
00234
00235 *pVertex++ = 0;
00236 *pVertex++ = 1 - y0;
00237 }
00238 }
00239
00240
00241 *pVertex++ = 0;
00242 *pVertex++ = 1;
00243 *pVertex++ = 0;
00244 *pVertex++ = 0;
00245 *pVertex++ = -1;
00246 *pVertex++ = 0;
00247 *pVertex++ = 0;
00248 *pVertex++ = 0;
00249
00250
00251 *pVertex++ = 0;
00252 *pVertex++ = -1;
00253 *pVertex++ = 0;
00254 *pVertex++ = 0;
00255 *pVertex++ = 1;
00256 *pVertex++ = 0;
00257 *pVertex++ = 0;
00258 *pVertex++ = 2;
00259
00260
00261 for (int i = 0; i < segments - 2; i++) {
00262 for (int j = 0; j < segments; j++) {
00263 *pIndices++ = segments * i + j;
00264 *pIndices++ = segments * i + (j + 1) % segments;
00265 *pIndices++ = segments * (i + 1) + (j + 1) % segments;
00266 *pIndices++ = segments * i + j;
00267 *pIndices++ = segments * (i + 1) + (j + 1) % segments;
00268 *pIndices++ = segments * (i + 1) + j;
00269 }
00270 }
00271
00272
00273 for (int i = 0; i < segments; i++) {
00274 *pIndices++ = segments * (segments - 1);
00275 *pIndices++ = (i + 1) % segments;
00276 *pIndices++ = i;
00277 }
00278
00279
00280 for (int i = 0; i < segments; i++) {
00281 *pIndices++ = segments * (segments - 1) + 1;
00282 *pIndices++ = segments * (segments - 2) + i;
00283 *pIndices++ = segments * (segments - 2) + (i + 1) % segments;
00284 }
00285 }
00286
00287 void InternalUtilities::fillStarfieldDomeBuffers (float *pVertex, unsigned short *pIndices, int segments)
00288 {
00289 const float deltaLatitude = Ogre::Math::PI / (float )segments;
00290 const float deltaLongitude = Ogre::Math::PI * 2.0 / (float )segments;
00291
00292
00293 for (int i = 0; i <= segments; i++) {
00294 float r0 = Ogre::Math::Sin (Ogre::Radian (i * deltaLatitude));
00295 float y0 = Ogre::Math::Cos (Ogre::Radian (i * deltaLatitude));
00296
00297 for (int j = 0; j <= segments; j++) {
00298 float x0 = r0 * Ogre::Math::Sin (Ogre::Radian (j * deltaLongitude));
00299 float z0 = r0 * Ogre::Math::Cos (Ogre::Radian (j * deltaLongitude));
00300
00301 *pVertex++ = x0;
00302 *pVertex++ = y0;
00303 *pVertex++ = z0;
00304
00305 *pVertex++ = -x0;
00306 *pVertex++ = -y0;
00307 *pVertex++ = -z0;
00308
00309 *pVertex++ = (float )j / (float )segments;
00310 *pVertex++ = 1 - (y0 * 0.5 + 0.5);
00311 }
00312 }
00313
00314
00315 int vRowSize = segments + 1;
00316 for (int i = 1; i < segments; i++) {
00317 for (int j = 0; j < segments; j++) {
00318 int baseIdx = vRowSize * i + j;
00319 *pIndices++ = baseIdx;
00320 *pIndices++ = baseIdx + 1;
00321 *pIndices++ = baseIdx + vRowSize + 1;
00322 *pIndices++ = baseIdx + 1;
00323 *pIndices++ = baseIdx;
00324 *pIndices++ = baseIdx - vRowSize;
00325 }
00326 }
00327 }
00328 }