//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #include "ts/tsDecal.h" #include "dgl/dgl.h" #include "math/mMath.h" #include "math/mathIO.h" #include "ts/tsShapeInstance.h" #include "core/frameAllocator.h" // Not worth the effort, much less the effort to comment, but if the draw types // are consecutive use addition rather than a table to go from index to command value... #if ((GL_TRIANGLES+1==GL_TRIANGLE_STRIP) && (GL_TRIANGLE_STRIP+1==GL_TRIANGLE_FAN)) #define getDrawType(a) (GL_TRIANGLES+(a)) #else static U32 drawTypes[] = { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }; #define getDrawType(a) (drawTypes[a]) #endif // temp variables for saving and restoring parameters during render static S32 decalSaveFogMethod; static F32 decalSaveAlphaAlways; static F32 gSaveFadeVal; // from tsmesh extern void forceFaceCamera(); extern void forceFaceCameraZAxis(); void TSDecalMesh::render(S32 frame, S32 decalFrame, TSMaterialList * materials) { if (targetMesh == NULL || texgenS.empty() || texgenT.empty() || indices.empty()) return; // we need to face the camera just like our target does if (targetMesh->getFlags(TSMesh::Billboard)) { if (targetMesh->getFlags(TSMesh::BillboardZAxis)) forceFaceCameraZAxis(); else forceFaceCamera(); } S32 firstVert = targetMesh->vertsPerFrame * frame; // generate texture coords S32 sz = indices.size(); Point4F s = texgenS[decalFrame]; Point4F t = texgenT[decalFrame]; Point3F * verts = &targetMesh->verts[firstVert]; U32 waterMark = FrameAllocator::getWaterMark(); F32 * ptr = (F32*)FrameAllocator::alloc(sizeof(F32)*2*targetMesh->vertsPerFrame); S16 * idx = (S16*)indices.address(); S16 * idxEnd = idx + indices.size(); for (; idxx * s.x + v->y * s.y + v->z * s.z + s.w; tv.y = v->x * t.x + v->y * t.y + v->z * t.z + t.w; } // set up vertex arrays glVertexPointer(3,GL_FLOAT,0,verts); glNormalPointer(GL_FLOAT,0,targetMesh->getNormals(firstVert)); glTexCoordPointer(2,GL_FLOAT,0,ptr); // NOTE: we don't lock these arrays since decals tend to use only a small subset of the vertices // material change? We only need to do this once. if ( (TSShapeInstance::smRenderData.materialIndex ^ materialIndex) & (TSDrawPrimitive::MaterialMask|TSDrawPrimitive::NoMaterial)) TSMesh::setMaterial(materialIndex,materials); S32 i; S32 a = startPrimitive[decalFrame]; S32 b = decalFrame+1>30); glDrawElements(drawType,draw.numElements,GL_UNSIGNED_SHORT,&indices[draw.start]); } // return frameAllocator memory FrameAllocator::setWaterMark(waterMark); } void TSDecalMesh::initDecalMaterials() { TSShapeInstance::smRenderData.materialFlags = TSMaterialList::S_Wrap | TSMaterialList::T_Wrap; TSShapeInstance::smRenderData.materialIndex = TSDrawPrimitive::NoMaterial; TSShapeInstance::smRenderData.environmentMapMethod = TSShapeInstance::NO_ENVIRONMENT_MAP; TSShapeInstance::smRenderData.detailMapMethod = TSShapeInstance::NO_DETAIL_MAP; TSShapeInstance::smRenderData.baseTE = 0; // adjust for fading gSaveFadeVal = TSMesh::getOverrideFade(); TSMesh::setOverrideFade( 1.0f ); TSShapeInstance::smRenderData.vertexAlpha.always = gSaveFadeVal; // setMaterial will end up changing vertex color if needed... // draw one-sided... glEnable(GL_CULL_FACE); glFrontFace(GL_CW); // enable vertex arrays... glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // bias depth values to fight z-fighting glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-2,-2); // when blending we modulate and draw using src_alpha, 1-src_alpha... glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // but we don't blend by default... glDisable(GL_BLEND); glDepthMask(GL_TRUE); // this should be off by default, but we'll end up turning it on asap... glDisable(GL_TEXTURE_2D); // fog the decals (or rather, don't...we'll fog the whole shape later if // we are 2-passing it, otherwise we just want to fade the decal out)... decalSaveFogMethod = TSShapeInstance::smRenderData.fogMethod; if (decalSaveFogMethod != TSShapeInstance::NO_FOG) decalSaveAlphaAlways = TSShapeInstance::smRenderData.alwaysAlphaValue; TSShapeInstance::smRenderData.fogMethod = TSShapeInstance::FOG_TWO_PASS; // decal will be faded (since decal is translucent) } void TSDecalMesh::resetDecalMaterials() { glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glDepthMask(GL_TRUE); glDisable(GL_CULL_FACE); TSMesh::setOverrideFade( gSaveFadeVal ); // fog the decals (or rather, don't...we'll fog the whole shape later if // we are 2-passing it, otherwise we just want to fade the decal out)... if (decalSaveFogMethod != TSShapeInstance::NO_FOG) TSShapeInstance::smRenderData.alwaysAlphaValue = decalSaveAlphaAlways; TSShapeInstance::smRenderData.fogMethod = decalSaveFogMethod; } //----------------------------------------------------- // TSDecalMesh assembly/dissembly methods // used for transfer to/from memory buffers //----------------------------------------------------- #define alloc TSShape::alloc void TSDecalMesh::assemble(bool) { if (TSShape::smReadVersion<20) { // read empty mesh...decals used to be derived from meshes alloc.checkGuard(); alloc.getPointer32(15); } S32 sz = alloc.get32(); S32 * ptr32 = alloc.copyToShape32(0); // get current shape address w/o doing anything for (S32 i=0; i=19) { ptr32 = alloc.copyToShape32(sz*4); texgenS.set(ptr32,startPrimitive.size()); ptr32 = alloc.copyToShape32(sz*4); texgenT.set(ptr32,startPrimitive.size()); } else { texgenS.set(NULL,0); texgenT.set(NULL,0); } materialIndex = alloc.get32(); alloc.checkGuard(); } void TSDecalMesh::disassemble() { alloc.set32(primitives.size()); for (S32 i=0; i