123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "environment/skySphere.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "scene/sceneRenderState.h"
- #include "renderInstance/renderPassManager.h"
- #include "gfx/primBuilder.h"
- #include "gfx/gfxTransformSaver.h"
- #include "core/stream/fileStream.h"
- #include "core/stream/bitStream.h"
- #include "materials/materialManager.h"
- #include "materials/materialFeatureTypes.h"
- #include "materials/sceneData.h"
- #include "T3D/gameFunctions.h"
- #include "renderInstance/renderBinManager.h"
- #include "materials/processedMaterial.h"
- #include "gfx/gfxDebugEvent.h"
- #include "math/util/matrixSet.h"
- IMPLEMENT_CO_NETOBJECT_V1(SkySphere);
- ConsoleDocClass(SkySphere,
- "@brief Represents the sky with an artist-created spherical map.\n\n"
- "SkySphere is not a directional light and should be used in conjunction with a Sun object.\n\n"
- "@ingroup Atmosphere"
- );
- SkySphere::SkySphere()
- {
- mTypeMask |= EnvironmentObjectType | StaticObjectType;
- mNetFlags.set(Ghostable | ScopeAlways);
- INIT_ASSET(Material);
- mMatInstance = NULL;
- mIsVBDirty = false;
- mPrimCount = 0;
- mFogBandHeight = 0;
- mFogPrimCount = 0;
- mMatrixSet = reinterpret_cast<MatrixSet*>(dMalloc_aligned(sizeof(MatrixSet), 16));
- constructInPlace(mMatrixSet);
- mFogBandMat = NULL;
- mFogBandMatInst = NULL;
- }
- SkySphere::~SkySphere()
- {
- dFree_aligned(mMatrixSet);
- if (mMatInstance)
- SAFE_DELETE(mMatInstance);
- SAFE_DELETE(mFogBandMatInst);
- if (mFogBandMat)
- {
- mFogBandMat->deleteObject();
- mFogBandMat = NULL;
- }
- }
- bool SkySphere::onAdd()
- {
- if (!Parent::onAdd())
- return false;
- setGlobalBounds();
- resetWorldBox();
- addToScene();
- if (isClientObject())
- {
- _initRender();
- _updateMaterial();
- }
- return true;
- }
- void SkySphere::onRemove()
- {
- removeFromScene();
- Parent::onRemove();
- }
- void SkySphere::initPersistFields()
- {
- addGroup("Sky Sphere");
- INITPERSISTFIELD_MATERIALASSET(Material, SkySphere, "The name of a cubemap material for the sky box.");
- addField("fogBandHeight", TypeF32, Offset(mFogBandHeight, SkySphere),
- "The height (0-1) of the fog band from the horizon to the top of the SkySphere.");
- endGroup("Sky Sphere");
- Parent::initPersistFields();
- }
- void SkySphere::inspectPostApply()
- {
- Parent::inspectPostApply();
- _updateMaterial();
- }
- U32 SkySphere::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
- {
- U32 retMask = Parent::packUpdate(conn, mask, stream);
- PACK_ASSET(conn, Material);
- stream->write(mFogBandHeight);
- return retMask;
- }
- void SkySphere::unpackUpdate(NetConnection* conn, BitStream* stream)
- {
- Parent::unpackUpdate(conn, stream);
- StringTableEntry oldMatName = getMaterial();
- UNPACK_ASSET(conn, Material);
- if (oldMatName != getMaterial())
- {
- _updateMaterial();
- }
- F32 bandHeight = 0;
- stream->read(&bandHeight);
- // If this flag has changed
- // we need to update the vertex buffer.
- if ( bandHeight != mFogBandHeight)
- {
- mFogBandHeight = bandHeight;
- mIsVBDirty = true;
- _initRender();
- }
- }
- void SkySphere::prepRenderImage(SceneRenderState* state)
- {
- PROFILE_SCOPE(SkySphere_prepRenderImage);
- if (state->isShadowPass() ||
- mVB.isNull() ||
- mFogBandVB.isNull() ||
- !mMatInstance)
- return;
- mMatrixSet->setSceneView(GFX->getWorldMatrix());
- mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
- ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
- ri->renderDelegate.bind(this, &SkySphere::_renderObject);
- ri->type = RenderPassManager::RIT_Sky;
- ri->defaultKey = 9;
- ri->defaultKey2 = 0;
- state->getRenderPass()->addInst(ri);
- }
- void SkySphere::_renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi)
- {
- GFXDEBUGEVENT_SCOPE(SkySphere_RenderObject, ColorI::WHITE);
- GFXTransformSaver saver;
- GFX->setVertexBuffer(mVB);
- MatrixF worldMat = MatrixF::Identity;
- worldMat.setPosition(Point3F(
- state->getCameraPosition().x,
- state->getCameraPosition().y,
- state->getCameraPosition().z));
- SceneData sgData;
- sgData.init(state);
- sgData.objTrans = &worldMat;
- mMatrixSet->restoreSceneViewProjection();
- mMatrixSet->setWorld(worldMat);
- if (state->isReflectPass())
- mMatrixSet->setProjection(state->getSceneManager()->getNonClipProjection());
- while (mMatInstance->setupPass(state, sgData))
- {
- mMatInstance->setTransforms(*mMatrixSet, state);
- mMatInstance->setSceneInfo(state, sgData);
- GFX->drawPrimitive(GFXTriangleList, 0, mPrimCount);
- }
- // Draw render band.
- if (mFogBandHeight > 0 && mFogBandMatInst)
- {
- const FogData& fog = state->getSceneManager()->getFogData();
- if (mLastFogColor != fog.color)
- {
- mLastFogColor = fog.color;
- _initRender();
- }
- // Just need it to follow the camera... no rotation.
- MatrixF camPosMat(MatrixF::Identity);
- camPosMat.setPosition(worldMat.getPosition());
- sgData.objTrans = &camPosMat;
- mMatrixSet->setWorld(*sgData.objTrans);
- while (mFogBandMatInst->setupPass(state, sgData))
- {
- mFogBandMatInst->setTransforms(*mMatrixSet, state);
- mFogBandMatInst->setSceneInfo(state, sgData);
- GFX->setVertexBuffer(mFogBandVB);
- GFX->drawPrimitive(GFXTriangleList, 0, mFogPrimCount);
- }
- }
- }
- void SkySphere::clearVectors()
- {
- tmpVertices.clear();
- finalFogVertex.clear();
- tempFogVertex.clear();
- colVec.clear();
- fogVerts.clear();
- vertsVec.clear();
- normsVec.clear();
- texCoordVec.clear();
- finalVertData.clear();
- }
- void SkySphere::addVertex(Point3F vert)
- {
- vertsVec.push_back(vert.x);
- vertsVec.push_back(vert.y);
- vertsVec.push_back(vert.z);
- }
- void SkySphere::addNormal(Point3F nor)
- {
- normsVec.push_back(nor.x);
- normsVec.push_back(nor.y);
- normsVec.push_back(nor.z);
- }
- void SkySphere::addTexcoord(F32 s, F32 t)
- {
- texCoordVec.push_back(s);
- texCoordVec.push_back(t);
- }
- void SkySphere::addColor(ColorI col)
- {
- colVec.push_back(col);
- }
- void SkySphere::BuildFinalVert()
- {
- U32 count = vertsVec.size();
- U32 i, j;
- for (i = 0, j = 0; i < count; i += 3, j += 2)
- {
- FinalVertexData temp;
- temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
- temp.nor.set(Point3F(normsVec[i], normsVec[i + 1], normsVec[i + 2]));
- temp.s = texCoordVec[j];
- temp.t = texCoordVec[j+1];
- finalVertData.push_back(temp);
- }
- }
- void SkySphere::BuildFinalFogVert()
- {
- U32 count = vertsVec.size();
- U32 i, j;
- for (i = 0, j = 0; i < count; i+=3, j++ )
- {
- FogVertex temp;
- temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
- temp.col = colVec[j];
- finalFogVertex.push_back(temp);
- }
- }
- void SkySphere::_initRender()
- {
- U32 rings = 32;
- U32 height = 16;
- U32 radius = 1;
- F32 x, y, z, xy; // vertex position
- F32 nx, ny, nz, lengthInv = 1.0f / radius; // normal
- F32 s, t; // texCoord
- F32 ringStep = M_2PI / rings;
- F32 heightStep = M_PI / height; // M_HALFPI for dome.
- F32 ringAng, heightAng;
- //clear vecs
- clearVectors();
- for (U32 i = 0; i <= height; ++i)
- {
- heightAng = M_PI / 2 - (F32)i * heightStep;
- F32 xy = radius * mCos(heightAng);
- F32 z = radius * mSin(heightAng);
- for (U32 j = 0; j <= rings; ++j)
- {
- SphereVertex vert;
- ringAng = j * ringStep;
- x = xy * mCos(ringAng);
- y = xy * mSin(ringAng);
- vert.pos.set(Point3F(x,y,z));
- nx = x * lengthInv;
- ny = y * lengthInv;
- nz = z * lengthInv;
- vert.nor.set(Point3F(nx, ny, nz));
- s = (F32)j / rings;
- t = (F32)i / height;
- vert.s = s;
- vert.t = t;
- tmpVertices.push_back(vert);
- }
- }
- SphereVertex v1, v2, v3, v4;
- U32 vi1, vi2 = 0;
- for (U32 i = 0; i < height; ++i)
- {
- vi1 = i * (rings + 1);
- vi2 = (i + 1) * (rings + 1);
- for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
- {
- v1 = tmpVertices[vi1];
- v2 = tmpVertices[vi2];
- v3 = tmpVertices[vi1 + 1];
- v4 = tmpVertices[vi2 + 1];
- // 1st = triangle.
- if (i == 0)
- {
- // verts for tri.
- addVertex(v1.pos);
- addVertex(v2.pos);
- addVertex(v4.pos);
- // texcoords for tri.
- addTexcoord(v1.s, v1.t);
- addTexcoord(v2.s, v2.t);
- addTexcoord(v4.s, v4.t);
- // normals for tri.
- addNormal(v1.nor);
- addNormal(v2.nor);
- addNormal(v4.nor);
- }
- else if (i == (height - 1))
- {
- // verts for tri.
- addVertex(v1.pos);
- addVertex(v2.pos);
- addVertex(v3.pos);
- // texcoords for tri.
- addTexcoord(v1.s, v1.t);
- addTexcoord(v2.s, v2.t);
- addTexcoord(v3.s, v3.t);
- // normals for quad.
- addNormal(v1.nor);
- addNormal(v2.nor);
- addNormal(v3.nor);
- }
- else
- {
- // verts for quad.
- addVertex(v1.pos);
- addVertex(v2.pos);
- addVertex(v3.pos);
- addVertex(v3.pos);
- addVertex(v4.pos);
- addVertex(v2.pos);
- // texcoords for quad.
- addTexcoord(v1.s, v1.t);
- addTexcoord(v2.s, v2.t);
- addTexcoord(v3.s, v3.t);
- addTexcoord(v3.s, v3.t);
- addTexcoord(v4.s, v4.t);
- addTexcoord(v2.s, v2.t);
- // normals for quad.
- addNormal(v1.nor);
- addNormal(v2.nor);
- addNormal(v3.nor);
- addNormal(v3.nor);
- addNormal(v4.nor);
- addNormal(v2.nor);
- }
- }
- }
- BuildFinalVert();
- GFXVertexPNT* tmpVerts = NULL;
- U32 vertCount = finalVertData.size();
- tmpVerts = new GFXVertexPNT[(vertCount)];
- mPrimCount = vertCount / 3;
- for (U32 i = 0; i < vertCount; i++)
- {
- tmpVerts[i].point.set(finalVertData[i].pos);
- tmpVerts[i].normal.set(finalVertData[i].nor);
- tmpVerts[i].texCoord.set(finalVertData[i].s, finalVertData[i].t);
- }
- if (mVB.isNull() || mIsVBDirty)
- {
- mVB.set(GFX, vertCount, GFXBufferTypeStatic);
- mIsVBDirty = false;
- }
- GFXVertexPNT* vertPtr = mVB.lock();
- if (!vertPtr)
- {
- delete[] tmpVerts;
- return;
- }
- dMemcpy(vertPtr, tmpVerts, sizeof(GFXVertexPNT) * vertCount);
- mVB.unlock();
- // Clean up temp verts.
- delete[] tmpVerts;
- // Grab the fog color.
- ColorI fogColor(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255);
- ColorI fogColorAlpha(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0);
- clearVectors();
- U32 stepCount = 16;
- F32 cylStep = M_2PI / stepCount;
- F32 cylAngle;
- F32 cylRadius = 10;
- for (U32 i = 0; i <= stepCount; ++i)
- {
- cylAngle = (F32)i * cylStep;
- fogVerts.push_back(mCos(cylAngle));
- fogVerts.push_back(mSin(cylAngle));
- }
- for (U32 i = 0; i < 2; ++i)
- {
- for (U32 j = 0, k = 0; j <= stepCount; ++j, k += 2)
- {
- FogVertex temp;
- F32 ux = fogVerts[k];
- F32 uy = fogVerts[k+1];
- if (i > 0)
- {
- temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), mFogBandHeight));
- temp.col = fogColorAlpha;
- }
- else
- {
- temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), -mFogBandHeight));
- temp.col = fogColor;
- }
- tempFogVertex.push_back(temp);
- }
- }
- FogVertex f1, f2, f3, f4;
- U32 k1 = 0;
- U32 k2 = stepCount + 1;
- for (U32 i = 0; i < stepCount; ++i, ++k1, ++k2)
- {
- f1 = tempFogVertex[k1];
- f2 = tempFogVertex[k1 + 1];
- f3 = tempFogVertex[k2];
- f4 = tempFogVertex[k2 + 1];
- addVertex(f3.pos);
- addVertex(f2.pos);
- addVertex(f4.pos);
- addColor(f3.col);
- addColor(f2.col);
- addColor(f4.col);
- addVertex(f1.pos);
- addVertex(f2.pos);
- addVertex(f3.pos);
- addColor(f1.col);
- addColor(f2.col);
- addColor(f3.col);
- }
- BuildFinalFogVert();
- U32 fogVertCount = finalFogVertex.size();
- mFogPrimCount = fogVertCount / 3;
- if (mFogBandVB.isNull())
- mFogBandVB.set(GFX, fogVertCount, GFXBufferTypeStatic);
- GFXVertexPC* bandVertPtr = mFogBandVB.lock();
- if (!bandVertPtr) return;
-
- for (U32 i = 0; i < fogVertCount; i++)
- {
- bandVertPtr[i].point.set(finalFogVertex[i].pos);
- bandVertPtr[i].color.set(finalFogVertex[i].col);
- }
- mFogBandVB.unlock();
- SAFE_DELETE(mFogBandMatInst);
- if (mFogBandMat)
- {
- mFogBandMat->deleteObject();
- mFogBandMat = NULL;
- }
- // Setup the material for this imposter.
- mFogBandMat = MATMGR->allocateAndRegister(String::EmptyString);
- mFogBandMat->mAutoGenerated = true;
- mFogBandMat->mTranslucent = true;
- mFogBandMat->mVertColor[0] = true;
- mFogBandMat->mDoubleSided = true;
- mFogBandMat->mEmissive[0] = true;
- FeatureSet features = MATMGR->getDefaultFeatures();
- features.addFeature(MFT_isBackground);
- mFogBandMatInst = mFogBandMat->createMatInstance();
- mFogBandMatInst->init(features, getGFXVertexFormat<GFXVertexPC>());
- }
- void SkySphere::onStaticModified(const char* slotName, const char* newValue)
- {
- Parent::onStaticModified(slotName, newValue);
- if (dStricmp(slotName, "material") == 0)
- setMaskBits(0xFFFFFFFF);
- }
- void SkySphere::_initMaterial()
- {
- if (mMatInstance)
- SAFE_DELETE(mMatInstance);
- if (mMaterial)
- mMatInstance = mMaterial->createMatInstance();
- else
- mMatInstance = MATMGR->createMatInstance("WarningMaterial");
- // We want to disable culling and z write.
- GFXStateBlockDesc desc;
- desc.setCullMode(GFXCullNone);
- desc.setBlend(true);
- desc.setZReadWrite(true, false);
- desc.zFunc = GFXCmpLessEqual;
- mMatInstance->addStateBlockDesc(desc);
- // Also disable lighting on the skysphere material by default.
- FeatureSet features = MATMGR->getDefaultFeatures();
- features.removeFeature(MFT_RTLighting);
- features.removeFeature(MFT_Visibility);
- features.addFeature(MFT_isBackground);
- // Now initialize the material.
- mMatInstance->init(features, getGFXVertexFormat<GFXVertexPNT>());
- }
- void SkySphere::_updateMaterial()
- {
- if (!getMaterialResource().isValid())
- {
- //If our materialDef isn't valid, try setting it
- _setMaterial(getMaterial());
- }
- if (getMaterialResource().isValid())
- {
- _initMaterial();
- }
- }
- BaseMatInstance* SkySphere::_getMaterialInstance()
- {
- if (!mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial)
- _initMaterial();
- if (!mMatInstance)
- return NULL;
- return mMatInstance;
- }
- DefineEngineMethod(SkySphere, postApply, void, (), , "")
- {
- object->inspectPostApply();
- }
|