//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "ts/tsLastDetail.h" #include "dgl/dgl.h" #include "ts/tsShape.h" #include "ts/tsShapeInstance.h" bool TSLastDetail::smDirtyMode = false; Point2F TSLastDetail::smTVerts[4] = { Point2F(0,1), Point2F(1,1), Point2F(1,0), Point2F(0,0) }; Point3F TSLastDetail::smNorms[4] = { Point3F(0,-1,0), Point3F(0,-1,0), Point3F(0,-1,0), Point3F(0,-1,0) }; TSLastDetail::TSLastDetail(TSShapeInstance * shape, U32 numEquatorSteps, U32 numPolarSteps, F32 polarAngle, bool includePoles, S32 dl, S32 dim) { VECTOR_SET_ASSOCIATION(mBitmaps); VECTOR_SET_ASSOCIATION(mTextures); mNumEquatorSteps = numEquatorSteps; mNumPolarSteps = numPolarSteps; mPolarAngle = polarAngle; mIncludePoles = includePoles; F32 equatorStepSize = M_2PI_F / (F32) numEquatorSteps; F32 polarStepSize = numPolarSteps>0 ? (0.5f * M_PI_F - polarAngle) / (F32)numPolarSteps : 0.0f; U32 i; F32 rotZ = 0; for (i=0; i0 ? polarAngle - 0.5f * M_PI_F : 0.0f; for (U32 j=0; j<2*numPolarSteps+1; j++) { MatrixF angMat; angMat.mul(MatrixF(EulerF(0,0,-M_PI_F+rotZ)),MatrixF(EulerF(rotX,0,0))); mBitmaps.push_back(shape->snapshot(dim,dim,true,angMat,dl,1.0f,true)); rotX += polarStepSize; } rotZ += equatorStepSize; } if (includePoles) { MatrixF m1( EulerF( M_PI_F / 2.0f, 0, 0 ) ); MatrixF m2( EulerF( -M_PI_F / 2.0f, 0, 0 ) ); mBitmaps.push_back(shape->snapshot(dim,dim,true,m1,dl,1.0f,true)); mBitmaps.push_back(shape->snapshot(dim,dim,true,m2,dl,1.0f,true)); } mTextures.setSize(mBitmaps.size()); for (i=0; i<(U32)mBitmaps.size(); i++) { if (mBitmaps[i]) // snapshot routine may refuse to give us a bitmap sometimes... mTextures[i] = new TextureHandle(NULL,mBitmaps[i],true); else mTextures[i] = NULL; } mPoints[0].set(-shape->mShape->radius,0, shape->mShape->radius); mPoints[1].set( shape->mShape->radius,0, shape->mShape->radius); mPoints[2].set( shape->mShape->radius,0,-shape->mShape->radius); mPoints[3].set(-shape->mShape->radius,0,-shape->mShape->radius); mCenter = shape->mShape->center; } TSLastDetail::~TSLastDetail() { for (S32 i=0; i=0 && rotXM_PI-mPolarAngle)) { mBitmapIndex = mNumEquatorSteps * (2*mNumPolarSteps+1); if (rotX>mPolarAngle) mBitmapIndex++; // mRotY = mAtan(y.y,x.y); mRotY = mAtan(m[5],m[4]); } else { F32 equatorStepSize = M_2PI_F / (F32) mNumEquatorSteps; F32 polarStepSize = mNumPolarSteps>0 ? (0.5f * M_PI_F - mPolarAngle) / (F32) mNumPolarSteps : 0.0f; rotZ = 0.999f * (mAtan(dotX,dotY) + M_PI_F); // the 0.99f makes sure we are in range AssertFatal(rotZ>=0 && rotZ0) mBitmapIndex = (U32)(mBitmapIndex + ((rotX-mPolarAngle) / polarStepSize)); // mRotY = mAtan(z.x,z.z); mRotY = mAtan(m[2],m[10]); } // make sure we donīt get invalid bitmap index! mBitmapIndex = mClamp(mBitmapIndex, 0, mTextures.size()-1); } void TSLastDetail::render(F32 alpha, bool drawFog) { glPushMatrix(); // get camera matrix, adjust for shape center MatrixF mat; Point3F p,center; dglGetModelview(&mat); mat.getColumn(3,&p); mat.mulV(mCenter,¢er); p += center; mat.setColumn(3,p); Point3F ones( 1, 1, 1 ); chooseView(mat,ones); // following is a quicker version of mat.set(EulerF(0,rotY,0)); // note: we assume mat[12]=1 and mat[3]=mat[7]=mat[11]=0 to start with F32 * m = (F32*)mat; // because [] operator isn't implemented on MatrixF, so it finds mat[0] ambiguous (const) AssertFatal(mFabs(m[15]-1.0f)<0.01f && mFabs(m[14])<0.01f && mFabs(m[13])<0.01f && mFabs(m[12])<0.01f,"TSLastDetail::render"); if (mRotY*mRotY>0.0001f) { m[0] = m[10] = mCos(mRotY); m[2] = mSin(mRotY); m[8] = -m[2]; m[1] = m[4] = m[6] = m[9] = 0.0f; m[5] = 1.0f; } else { m[0] = m[5] = m[10] = 1.0f; m[1] = m[2] = m[4] = m[6] = m[8] = m[9] = 0.0f; } dglLoadMatrix(&mat); if (TSShapeInstance::smRenderData.objectScale) glScalef( TSShapeInstance::smRenderData.objectScale->x, TSShapeInstance::smRenderData.objectScale->y, TSShapeInstance::smRenderData.objectScale->z ); if (!drawFog) renderNoFog(alpha); else { if (dglDoesSupportTextureEnvCombine() && dglDoesSupportARBMultitexture()) renderFog_MultiCombine(alpha); // else if (dglDoesSupportTextureEnvCombine()) // renderFog_Combine(alpha); else renderNoFog(alpha * TSShapeInstance::smRenderData.fogColor.w); } glPopMatrix(); } void TSLastDetail::renderNoFog(F32 alpha) { // set up arrays glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer (3, GL_FLOAT, 0, mPoints); glTexCoordPointer(2, GL_FLOAT, 0, smTVerts); glNormalPointer ( GL_FLOAT, 0, smNorms); // light the material glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,Point4F(1,1,1,alpha)); // additive transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // texture glEnable(GL_TEXTURE_2D); if (TSShapeInstance::smRenderData.useOverride == false) glBindTexture(GL_TEXTURE_2D, mTextures[mBitmapIndex]->getGLName()); else glBindTexture(GL_TEXTURE_2D, TSShapeInstance::smRenderData.override.getGLName()); // set color state glColor4f(1,1,1,1); glDepthMask(GL_FALSE); glDrawArrays(GL_TRIANGLE_FAN,0,4); if(!smDirtyMode) { glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDepthMask(GL_TRUE); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); } } void TSLastDetail::renderFog_Combine(F32 alpha) { // set up arrays glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer (3, GL_FLOAT, 0, mPoints); glTexCoordPointer(2, GL_FLOAT, 0, smTVerts); glNormalPointer ( GL_FLOAT, 0, smNorms); // light the material glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,Point4F(1,1,1,alpha)); glColor4f(1,1,1,1); // additive transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // texture glEnable(GL_TEXTURE_2D); if (TSShapeInstance::smRenderData.useOverride == false) glBindTexture(GL_TEXTURE_2D, mTextures[mBitmapIndex]->getGLName()); else glBindTexture(GL_TEXTURE_2D, TSShapeInstance::smRenderData.override.getGLName()); glDepthMask(GL_FALSE); glDrawArrays(GL_TRIANGLE_FAN,0,4); // now render the fog glDisableClientState(GL_NORMAL_ARRAY); GLboolean wasLit = glIsEnabled(GL_LIGHTING); glDisable(GL_LIGHTING); glDepthMask(GL_TRUE); glColor4fv(TSShapeInstance::smRenderData.fogColor); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); // color comes from constant color... glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR); // alpha is product of texture and constant alpha... glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA,GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA,GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_ALPHA,GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_ALPHA,GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_ALPHA,GL_SRC_ALPHA); glDrawArrays(GL_TRIANGLE_FAN,0,4); // restore state... if (wasLit) glEnable(GL_LIGHTING); if(!smDirtyMode) { glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); } } void TSLastDetail::renderFog_MultiCombine(F32 alpha) { // set up materials glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer (3,GL_FLOAT, 0, mPoints); glTexCoordPointer(2,GL_FLOAT, 0, smTVerts); glNormalPointer ( GL_FLOAT, 0, smNorms); // set color state glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,Point4F(1,1,1,alpha)); glColor4f(1,1,1,1); // first TE applies lighting to billboard texture glEnable(GL_TEXTURE_2D); if (TSShapeInstance::smRenderData.useOverride == false) glBindTexture(GL_TEXTURE_2D, mTextures[mBitmapIndex]->getGLName()); else glBindTexture(GL_TEXTURE_2D, TSShapeInstance::smRenderData.override.getGLName()); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); // second TE applies fog to the result glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR, TSShapeInstance::smRenderData.fogColor); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); // additive transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); // render billboard+fog glDrawArrays(GL_TRIANGLE_FAN,0,4); // restore state... if(!smDirtyMode) { glDisable(GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_BLEND); glDepthMask(GL_TRUE); glDisable(GL_TEXTURE_2D); } else { glActiveTextureARB(GL_TEXTURE0_ARB); } }