diff --git a/Engine/source/environment/scatterSky.cpp b/Engine/source/environment/scatterSky.cpp index 5de3bdd94..12071d558 100644 --- a/Engine/source/environment/scatterSky.cpp +++ b/Engine/source/environment/scatterSky.cpp @@ -758,73 +758,146 @@ bool ScatterSky::_initShader() return true; } +void ScatterSky::clearVectors() +{ + tmpVertices.clear(); + vertsVec.clear(); +} + +void ScatterSky::addVertex(Point3F vert) +{ + vertsVec.push_back(vert.x); + vertsVec.push_back(vert.y); + vertsVec.push_back(vert.z); +} + +void ScatterSky::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])); + + finalVertData.push_back(temp); + } +} + void ScatterSky::_initVBIB() { + U32 rings = 18; + U32 height = 9; + U32 radius = 10; + + F32 x, y, z, xy; // vertex position + + F32 ringStep = M_2PI / rings; + F32 heightStep = M_HALFPI / height; // M_PI for full sphere. + F32 ringAng, heightAng; + + //clear vecs + clearVectors(); + + for (U32 i = 0; i <= height; ++i) + { + heightAng = M_PI / 2 - (F32)i * heightStep; + xy = radius * mCos(heightAng); + 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)); + + 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); + } + /* UNCOMMENT WHEN FULL SPHERE + else if (i == (height - 1)) + { + // verts for tri. + addVertex(v1.pos); + addVertex(v2.pos); + addVertex(v3.pos); + }*/ + else + { + // verts for quad. + addVertex(v1.pos); + addVertex(v2.pos); + addVertex(v3.pos); + + addVertex(v3.pos); + addVertex(v4.pos); + addVertex(v2.pos); + } + } + } + + BuildFinalVert(); + // Vertex Buffer... - U32 vertStride = 50; - U32 strideMinusOne = vertStride - 1; - mVertCount = vertStride * vertStride; - mPrimCount = strideMinusOne * strideMinusOne * 2; - - Point3F vertScale( 16.0f, 16.0f, 4.0f ); - - F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f ); + mVertCount = finalVertData.size(); + mPrimCount = mVertCount / 3; mVB.set( GFX, mVertCount, GFXBufferTypeStatic ); GFXVertexP *pVert = mVB.lock(); if(!pVert) return; - for ( U32 y = 0; y < vertStride; y++ ) + for ( U32 i = 0; i < mVertCount; i++ ) { - F32 v = ( (F32)y / (F32)strideMinusOne - 0.5f ) * 2.0f; - - for ( U32 x = 0; x < vertStride; x++ ) - { - F32 u = ( (F32)x / (F32)strideMinusOne - 0.5f ) * 2.0f; - - F32 sx = u; - F32 sy = v; - F32 sz = (mCos( mSqrt( sx*sx + sy*sy ) ) * 1.0f) + zOffset; - //F32 sz = 1.0f; - pVert->point.set( sx, sy, sz ); - pVert->point *= vertScale; + pVert->point.set(finalVertData[i].pos); pVert->point.normalize(); pVert->point *= 200000.0f; - pVert++; - } } mVB.unlock(); // Primitive Buffer... - mPrimBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic ); + mPrimBuffer.set( GFX, mVertCount, mPrimCount, GFXBufferTypeStatic ); U16 *pIdx = NULL; mPrimBuffer.lock(&pIdx); U32 curIdx = 0; - for ( U32 y = 0; y < strideMinusOne; y++ ) + for ( U32 i = 0, k = 0; i < mPrimCount; i++, k+=3 ) { - for ( U32 x = 0; x < strideMinusOne; x++ ) - { - U32 offset = x + y * vertStride; - - pIdx[curIdx] = offset; + pIdx[curIdx] = k; curIdx++; - pIdx[curIdx] = offset + 1; + pIdx[curIdx] = k + 1; curIdx++; - pIdx[curIdx] = offset + vertStride + 1; + pIdx[curIdx] = k + 2; curIdx++; - - pIdx[curIdx] = offset; - curIdx++; - pIdx[curIdx] = offset + vertStride + 1; - curIdx++; - pIdx[curIdx] = offset + vertStride; - curIdx++; - } } mPrimBuffer.unlock(); @@ -963,13 +1036,25 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat Point3F camPos2 = state->getCameraPosition(); MatrixF xfm(true); - xfm.setPosition(camPos2 - Point3F(0, 0, mZOffset)); + xfm.setPosition(Point3F( + camPos2.x, + camPos2.y, + mZOffset) ); + GFX->multWorld(xfm); MatrixF xform(proj);//GFX->getProjectionMatrix()); xform *= GFX->getViewMatrix(); xform *= GFX->getWorldMatrix(); + if(state->isReflectPass()) + { + static MatrixF rotMat(EulerF(0.0, 0.0, M_PI_F)); + xform.mul(rotMat); + rotMat.set(EulerF(M_PI_F, 0.0, 0.0)); + xform.mul(rotMat); + } + mShaderConsts->setSafe( mModelViewProjSC, xform ); mShaderConsts->setSafe( mMiscSC, miscParams ); mShaderConsts->setSafe( mSphereRadiiSC, sphereRadii ); diff --git a/Engine/source/environment/scatterSky.h b/Engine/source/environment/scatterSky.h index 0633e9e23..e544e64a5 100644 --- a/Engine/source/environment/scatterSky.h +++ b/Engine/source/environment/scatterSky.h @@ -104,6 +104,27 @@ public: /// F32 getElevation() const { return mSunElevation; } + struct SphereVertex + { + Point3F pos; + }; + + Vector tmpVertices; + Vector vertsVec; + + struct FinalVertexData + { + Point3F pos; + }; + + Vector finalVertData; + + void addVertex(Point3F vert); + + void BuildFinalVert(); + + void clearVectors(); + protected: void _render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ); diff --git a/Engine/source/environment/skySphere.cpp b/Engine/source/environment/skySphere.cpp new file mode 100644 index 000000000..9f52c660c --- /dev/null +++ b/Engine/source/environment/skySphere.cpp @@ -0,0 +1,645 @@ +//----------------------------------------------------------------------------- +// 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(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(); + ri->renderDelegate.bind(this, &SkySphere::_renderObject); + ri->type = RenderPassManager::RIT_Sky; + ri->defaultKey = 10; + 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()); +} + +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()); +} + +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(); +} diff --git a/Engine/source/environment/skySphere.h b/Engine/source/environment/skySphere.h new file mode 100644 index 000000000..37a6fbd12 --- /dev/null +++ b/Engine/source/environment/skySphere.h @@ -0,0 +1,172 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#ifndef _SKYSPHERE_H_ +#define _SKYSPHERE_H_ + +#ifndef _SCENEOBJECT_H_ +#include "scene/sceneObject.h" +#endif + +#ifndef _GFXDEVICE_H_ +#include "gfx/gfxDevice.h" +#endif + +#ifndef _CUBEMAPDATA_H_ +#include "gfx/sim/cubemapData.h" +#endif + +#ifndef _MATERIALLIST_H_ +#include "materials/materialList.h" +#endif + +#ifndef _GFXVERTEXBUFFER_H_ +#include "gfx/gfxVertexBuffer.h" +#endif + +#ifndef _GFXPRIMITIVEBUFFER_H_ +#include "gfx/gfxPrimitiveBuffer.h" +#endif + +#include "T3D/assets/MaterialAsset.h" + +struct SkyMatParams +{ + void init(BaseMatInstance* matInst) {}; +}; + +class MatrixSet; + +class SkySphere : public SceneObject +{ + typedef SceneObject Parent; + +public: + + SkySphere(); + virtual ~SkySphere(); + + DECLARE_CONOBJECT(SkySphere); + + // SimObject + void onStaticModified(const char* slotName, const char* newValue); + + // ConsoleObject + virtual bool onAdd(); + virtual void onRemove(); + static void initPersistFields(); + virtual void inspectPostApply(); + + // NetObject + virtual U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream); + virtual void unpackUpdate(NetConnection* conn, BitStream* stream); + + // SceneObject + void prepRenderImage(SceneRenderState* state); + + /// Our render delegate. + void _renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi); + + void clearVectors(); + + void addVertex(Point3F vert); + + void addNormal(Point3F nor); + + void addTexcoord(F32 s, F32 t); + + void addColor(ColorI col); + + void BuildFinalVert(); + + void BuildFinalFogVert(); + + /// Prepares rendering structures and geometry. + void _initRender(); + + struct SphereVertex + { + Point3F pos; + Point3F nor; + F32 s, t; + }; + + Vector tmpVertices; + Vector vertsVec; + Vector texCoordVec; + Vector normsVec; + + struct FinalVertexData + { + Point3F pos; + Point3F nor; + F32 s; + F32 t; + }; + + Vector finalVertData; + + struct FogVertex + { + // might need normals for smoothing. + Point3F pos; + ColorI col; + }; + + Vector finalFogVertex; + Vector tempFogVertex; + Vector colVec; + Vector fogVerts; + +protected: + + // Material + DECLARE_MATERIALASSET(SkySphere, Material); + DECLARE_ASSET_NET_SETGET(SkySphere, Material, -1); + + BaseMatInstance* mMatInstance; + SkyMatParams mMatParamHandle; + + GFXVertexBufferHandle mVB; + + GFXVertexBufferHandle mFogBandVB; + Material* mFogBandMat; + BaseMatInstance* mFogBandMatInst; + + LinearColorF mLastFogColor; + + bool mIsVBDirty; + U32 mPrimCount; + + MatrixSet* mMatrixSet; + + F32 mFogBandHeight; + U32 mFogPrimCount; + + void _updateMaterial(); + void _initMaterial(); + + BaseMatInstance* _getMaterialInstance(); + +}; + +#endif diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript index 26bc7202b..803a5933a 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript @@ -26,6 +26,7 @@ function AssetBrowser::loadCreatorClasses(%this) %this.addCreatorClass( "RibbonNode", "Ribbon Emitter" ); %this.addCreatorClass( "ScatterSky", "Scatter Sky" ); %this.addCreatorClass( "SkyBox", "Sky Box" ); + %this.addCreatorClass( "SkySphere", "Sky Sphere" ); %this.addCreatorClass( "SFXEmitter", "Sound Emitter" ); %this.addCreatorClass( "TerrainBlock", "Terrain Block" ); %this.addCreatorClass( "VolumetricFog", "Volumetric Fog" ); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript index 7ec1015a7..9524a7849 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript @@ -37,6 +37,7 @@ function ObjectCreator::init( %this ) // Removed Prefab as there doesn't really seem to be a point in creating a blank one //%this.registerMissionObject( "Prefab", "Prefab" ); %this.registerMissionObject( "SkyBox", "Sky Box" ); + %this.registerMissionObject( "SkySphere", "Sky Sphere" ); %this.registerMissionObject( "CloudLayer", "Cloud Layer" ); %this.registerMissionObject( "BasicClouds", "Basic Clouds" ); %this.registerMissionObject( "ScatterSky", "Scatter Sky" );