bool InteriorLMManager::loadBaseLightmaps(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::loadBaseLightmaps: invalid instance handle"); // must use a valid instance handle if(!instanceHandle) return(false); InteriorLMInfo * interiorInfo = mInteriors[interiorHandle]; if(!interiorInfo->mNumLightmaps) return(false); InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0]; // already loaded? (if any bitmap is present, then assumed that all will be) GFXTexHandle texture (baseInstanceInfo->mLightmapHandles[0]); if(texture.isValid() && texture.getBitmap()) return(true); InstanceLMInfo * instanceInfo = interiorInfo->mInstances[instanceHandle]; Resource<InteriorResource> & interiorRes = instanceInfo->mInstance->getResource(); if(!bool(interiorRes)) return(false); GBitmap *** pBitmaps = 0; if(!instanceInfo->mInstance->readLightmaps(&pBitmaps)) return(false); for(U32 i = 0; i < interiorRes->getNumDetailLevels(); i++) { Interior * interior = interiorRes->getDetailLevel(i); AssertFatal(interior, "InteriorLMManager::loadBaseLightmaps: invalid detail level in resource"); AssertFatal(interior->getLMHandle() != LM_HANDLE(-1), "InteriorLMManager::loadBaseLightmaps: interior not added to manager"); AssertFatal(interior->getLMHandle() < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior"); InteriorLMInfo * interiorInfo = mInteriors[interior->getLMHandle()]; InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0]; for(U32 j = 0; j < interiorInfo->mNumLightmaps; j++) { AssertFatal(pBitmaps[i][j], "InteriorLMManager::loadBaseLightmaps: invalid bitmap"); if (baseInstanceInfo->mLightmapHandles[j]) { GFXTextureObject * texObj = baseInstanceInfo->mLightmapHandles[j]; texObj->mBitmap = pBitmaps[i][j]; } else baseInstanceInfo->mLightmapHandles[j].set( pBitmaps[i][j], &GFXDefaultPersistentProfile, false, String("Interior Lightmap Handle") ); } } delete [] pBitmaps; return(true); }
void AtlasTexChunk::writeDDS(Stream *s) { // Load the DDS into a texture, then use D3DX to write it out. GFXTexHandle tex; tex.set(dds, &GFXDefaultStaticDiffuseProfile, false, avar("%s - %s", __FUNCTION__, ( const char* ) dds->mSourcePath.getFullPath() ) ); GFXD3D9TextureObject *gdto = (GFXD3D9TextureObject *)tex.getPointer(); // Write to buffer. ID3DXBuffer *buffer = NULL; GFXD3DX.D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, gdto->getTex(), NULL); // And write that buffer... to a stream. Ho ho ho! s->write(buffer->GetBufferSize(), buffer->GetBufferPointer()); }
GFXTexHandle::GFXTexHandle( const GFXTexHandle &handle, const String &desc ) { StrongObjectRef::set( handle.getPointer() ); #ifdef TORQUE_DEBUG if ( getPointer() ) getPointer()->mDebugDescription = desc; #endif }
LevelInfo::~LevelInfo() { LightManager::smActivateSignal.remove(this, &LevelInfo::_onLMActivate); if (!mAccuTexture.isNull()) { mAccuTexture.free(); gLevelAccuMap.free(); } }
//------------------------------------------------------------------------------ GFXTexHandle &InteriorLMManager::duplicateBaseLightmap(LM_HANDLE interiorHandle, LM_HANDLE instanceHandle, U32 index) { AssertFatal(interiorHandle < mInteriors.size(), "InteriorLMManager::duplicateBaseLightmap: invalid interior handle"); AssertFatal(instanceHandle < mInteriors[interiorHandle]->mInstances.size(), "InteriorLMManager::duplicateBaseLightmap: invalid instance handle"); AssertFatal(index < mInteriors[interiorHandle]->mNumLightmaps, "InteriorLMManager::duplicateBaseLightmap: invalid texture index"); // already exists? GFXTexHandle texHandle = mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]; if(texHandle && texHandle->getBitmap() ) return mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]; AssertFatal(mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index], "InteriorLMManager::duplicateBaseLightmap: invalid base handle"); // copy it GBitmap * src = mInteriors[interiorHandle]->mInstances[0]->mLightmapHandles[index]->getBitmap(); GBitmap * dest = new GBitmap(*src); // don't want this texture to be downloaded yet (SceneLighting will take care of that) GFXTexHandle tHandle( dest, &GFXDefaultPersistentProfile, true, String("Interior Lightmap Handle 2") ); mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index] = tHandle; return mInteriors[interiorHandle]->mInstances[instanceHandle]->mLightmapHandles[index]; }
void ImposterCapture::_renderToTexture( GFXTexHandle texHandle, GBitmap *outBitmap, const ColorI &color ) { GFXDEBUGEVENT_SCOPE( ImposterCapture_RenderToTexture, ColorI::RED ); PROFILE_SCOPE( ImposterCapture_RenderToTexture ); mRenderTarget->attachTexture( GFXTextureTarget::Color0, texHandle ); mRenderTarget->attachTexture( GFXTextureTarget::DepthStencil, mDepthBuffer ); GFX->setActiveRenderTarget( mRenderTarget ); GFX->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, color, 1.0f, 0 ); mShapeInstance->render( mRData, mDl, 1.0f ); mState->getRenderPass()->renderPass( mState ); mRenderTarget->resolve(); texHandle->copyToBmp( outBitmap ); }
void TerrainBlock::_updateBaseTexture(bool writeToCache) { if ( !mBaseShader && !_initBaseShader() ) return; // This can sometimes occur outside a begin/end scene. const bool sceneBegun = GFX->canCurrentlyRender(); if ( !sceneBegun ) GFX->beginScene(); GFXDEBUGEVENT_SCOPE( TerrainBlock_UpdateBaseTexture, ColorI::GREEN ); PROFILE_SCOPE( TerrainBlock_UpdateBaseTexture ); GFXTransformSaver saver; const U32 maxTextureSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 1024 ); U32 baseTexSize = getNextPow2( mBaseTexSize ); baseTexSize = getMin( maxTextureSize, baseTexSize ); Point2I destSize( baseTexSize, baseTexSize ); // Setup geometry GFXVertexBufferHandle<GFXVertexPT> vb; { F32 copyOffsetX = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.x; F32 copyOffsetY = 2.0f * GFX->getFillConventionOffset() / (F32)destSize.y; GFXVertexPT points[4]; points[0].point = Point3F(1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0); points[0].texCoord = Point2F(1.0, 1.0f); points[1].point = Point3F(1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0); points[1].texCoord = Point2F(1.0, 0.0f); points[2].point = Point3F(-1.0 - copyOffsetX, -1.0 + copyOffsetY, 0.0); points[2].texCoord = Point2F(0.0, 1.0f); points[3].point = Point3F(-1.0 - copyOffsetX, 1.0 + copyOffsetY, 0.0); points[3].texCoord = Point2F(0.0, 0.0f); vb.set( GFX, 4, GFXBufferTypeVolatile ); GFXVertexPT *ptr = vb.lock(); if(ptr) { dMemcpy( ptr, points, sizeof(GFXVertexPT) * 4 ); vb.unlock(); } } GFXTexHandle blendTex; // If the base texture is already a valid render target then // use it to render to else we create one. if ( mBaseTex.isValid() && mBaseTex->isRenderTarget() && mBaseTex->getFormat() == GFXFormatR8G8B8A8 && mBaseTex->getWidth() == destSize.x && mBaseTex->getHeight() == destSize.y ) blendTex = mBaseTex; else blendTex.set( destSize.x, destSize.y, GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, "" ); GFX->pushActiveRenderTarget(); // Set our shader stuff GFX->setShader( mBaseShader ); GFX->setShaderConstBuffer( mBaseShaderConsts ); GFX->setStateBlock( mBaseShaderSB ); GFX->setVertexBuffer( vb ); mBaseTarget->attachTexture( GFXTextureTarget::Color0, blendTex ); GFX->setActiveRenderTarget( mBaseTarget ); GFX->clear( GFXClearTarget, ColorI(0,0,0,255), 1.0f, 0 ); GFX->setTexture( 0, mLayerTex ); mBaseShaderConsts->setSafe( mBaseLayerSizeConst, (F32)mLayerTex->getWidth() ); for ( U32 i=0; i < mBaseTextures.size(); i++ ) { GFXTextureObject *tex = mBaseTextures[i]; if ( !tex ) continue; GFX->setTexture( 1, tex ); F32 baseSize = mFile->mMaterials[i]->getDiffuseSize(); F32 scale = 1.0f; if ( !mIsZero( baseSize ) ) scale = getWorldBlockSize() / baseSize; // A mistake early in development means that texture // coords are not flipped correctly. To compensate // we flip the y scale here. mBaseShaderConsts->setSafe( mBaseTexScaleConst, Point2F( scale, -scale ) ); mBaseShaderConsts->setSafe( mBaseTexIdConst, (F32)i ); GFX->drawPrimitive( GFXTriangleStrip, 0, 2 ); } mBaseTarget->resolve(); GFX->setShader( NULL ); //GFX->setStateBlock( NULL ); // WHY NOT? GFX->setShaderConstBuffer( NULL ); GFX->setVertexBuffer( NULL ); GFX->popActiveRenderTarget(); // End it if we begun it... Yeehaw! if ( !sceneBegun ) GFX->endScene(); /// Do we cache this sucker? if (mBaseTexFormat == NONE || !writeToCache) { // We didn't cache the result, so set the base texture // to the render target we updated. This should be good // for realtime painting cases. mBaseTex = blendTex; } else if (mBaseTexFormat == DDS) { String cachePath = _getBaseTexCacheFileName(); FileStream fs; if ( fs.open( _getBaseTexCacheFileName(), Torque::FS::File::Write ) ) { // Read back the render target, dxt compress it, and write it to disk. GBitmap blendBmp( destSize.x, destSize.y, false, GFXFormatR8G8B8A8 ); blendTex.copyToBmp( &blendBmp ); /* // Test code for dumping uncompressed bitmap to disk. { FileStream fs; if ( fs.open( "./basetex.png", Torque::FS::File::Write ) ) { blendBmp.writeBitmap( "png", fs ); fs.close(); } } */ blendBmp.extrudeMipLevels(); DDSFile *blendDDS = DDSFile::createDDSFileFromGBitmap( &blendBmp ); DDSUtil::squishDDS( blendDDS, GFXFormatDXT1 ); // Write result to file stream blendDDS->write( fs ); delete blendDDS; } fs.close(); } else { FileStream stream; if (!stream.open(_getBaseTexCacheFileName(), Torque::FS::File::Write)) { mBaseTex = blendTex; return; } GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8); blendTex->copyToBmp(&bitmap); bitmap.writeBitmap(formatToExtension(mBaseTexFormat), stream); } }
void blInteriorProxy::addToShadowVolume(ShadowVolumeBSP * shadowVolume, LightInfo * light, S32 level) { if(light->getType() != LightInfo::Vector) return; ColorF ambient = light->getAmbient(); bool shadowedTree = true; InteriorInstance* interior = dynamic_cast<InteriorInstance*>(getObject()); if (!interior) return; Resource<InteriorResource> mInteriorRes = interior->getResource(); // check if just getting shadow detail if(level == SceneLighting::SHADOW_DETAIL) { shadowedTree = false; level = mInteriorRes->getNumDetailLevels() - 1; } Interior * detail = mInteriorRes->getDetailLevel(level); bool hasAlarm = detail->hasAlarmState(); // make sure surfaces do not get processed more than once BitVector surfaceProcessed; surfaceProcessed.setSize(detail->mSurfaces.size()); surfaceProcessed.clear(); ColorI color = light->getAmbient(); // go through the zones of the interior and grab outside visible surfaces for(U32 i = 0; i < detail->getNumZones(); i++) { Interior::Zone & zone = detail->mZones[i]; for(U32 j = 0; j < zone.surfaceCount; j++) { U32 surfaceIndex = detail->mZoneSurfaces[zone.surfaceStart + j]; // dont reprocess a surface if(surfaceProcessed.test(surfaceIndex)) continue; surfaceProcessed.set(surfaceIndex); Interior::Surface & surface = detail->mSurfaces[surfaceIndex]; // outside visible? if(!(surface.surfaceFlags & Interior::SurfaceOutsideVisible)) continue; // good surface? PlaneF plane = detail->getPlane(surface.planeIndex); if(Interior::planeIsFlipped(surface.planeIndex)) plane.neg(); // project the plane PlaneF projPlane; mTransformPlane(interior->getTransform(), interior->getScale(), plane, &projPlane); // fill with ambient? (need to do here, because surface will not be // added to the SVBSP tree) F32 dot = mDot(projPlane, light->getDirection()); if(dot > -gParellelVectorThresh)// && !(GFX->getPixelShaderVersion() > 0.0) ) { if(shadowedTree) { // alarm lighting GFXTexHandle normHandle = gInteriorLMManager.duplicateBaseLightmap(detail->getLMHandle(), interior->getLMHandle(), detail->getNormalLMapIndex(surfaceIndex)); GFXTexHandle alarmHandle; GBitmap * normLightmap = normHandle->getBitmap(); GBitmap * alarmLightmap = 0; // check if they share the lightmap if(hasAlarm) { if(detail->getNormalLMapIndex(surfaceIndex) != detail->getAlarmLMapIndex(surfaceIndex)) { alarmHandle = gInteriorLMManager.duplicateBaseLightmap(detail->getLMHandle(), interior->getLMHandle(), detail->getAlarmLMapIndex(surfaceIndex)); alarmLightmap = alarmHandle->getBitmap(); } } // // Support for interior light map border sizes. // U32 xlen, ylen, xoff, yoff; U32 lmborder = detail->getLightMapBorderSize(); xlen = surface.mapSizeX + (lmborder * 2); ylen = surface.mapSizeY + (lmborder * 2); xoff = surface.mapOffsetX - lmborder; yoff = surface.mapOffsetY - lmborder; // attemp to light normal and alarm lighting for(U32 c = 0; c < 2; c++) { GBitmap * lightmap = (c == 0) ? normLightmap : alarmLightmap; if(!lightmap) continue; // fill it for(U32 y = 0; y < ylen; y++) { for(U32 x = 0; x < xlen; x++) { ColorI outColor(255, 0, 0, 255); #ifndef SET_COLORS ColorI lmColor(0, 0, 0, 255); lightmap->getColor(xoff + x, yoff + y, lmColor); U32 _r = static_cast<U32>( color.red ) + static_cast<U32>( lmColor.red ); U32 _g = static_cast<U32>( color.green ) + static_cast<U32>( lmColor.green ); U32 _b = static_cast<U32>( color.blue ) + static_cast<U32>( lmColor.blue ); outColor.red = mClamp(_r, 0, 255); outColor.green = mClamp(_g, 0, 255); outColor.blue = mClamp(_b, 0, 255); #endif lightmap->setColor(xoff + x, yoff + y, outColor); } } } } continue; } ShadowVolumeBSP::SVPoly * poly = buildInteriorPoly(shadowVolume, detail, surfaceIndex, light, shadowedTree); // insert it into the SVBSP tree shadowVolume->insertPoly(poly); } } }
void TerrainFile::_loadLegacy( FileStream &stream ) { // Some legacy constants. enum { MaterialGroups = 8, BlockSquareWidth = 256, }; const U32 sampleCount = BlockSquareWidth * BlockSquareWidth; mSize = BlockSquareWidth; // Load the heightmap. mHeightMap.setSize( sampleCount ); for ( U32 i=0; i < mHeightMap.size(); i++ ) stream.read( &mHeightMap[i] ); // Prior to version 7 we stored this weird material struct. const U32 MATERIAL_GROUP_MASK = 0x7; struct Material { enum Flags { Plain = 0, Rotate = 1, FlipX = 2, FlipXRotate = 3, FlipY = 4, FlipYRotate = 5, FlipXY = 6, FlipXYRotate = 7, RotateMask = 7, Empty = 8, Modified = BIT(7), // must not clobber TerrainFile::MATERIAL_GROUP_MASK bits! PersistMask = BIT(7) }; U8 flags; U8 index; }; // Temp locals for loading before we convert to the new // version 7+ format. U8 baseMaterialMap[sampleCount] = { 0 }; U8 *materialAlphaMap[MaterialGroups] = { 0 }; Material materialMap[BlockSquareWidth * BlockSquareWidth]; // read the material group map and flags... dMemset(materialMap, 0, sizeof(materialMap)); AssertFatal(!(Material::PersistMask & MATERIAL_GROUP_MASK), "Doh! We have flag clobberage..."); for (S32 j=0; j < sampleCount; j++) { U8 val; stream.read(&val); // baseMaterialMap[j] = val & MATERIAL_GROUP_MASK; materialMap[j].flags = val & Material::PersistMask; } // Load the material names. Vector<String> materials; for ( U32 i=0; i < MaterialGroups; i++ ) { String matName; stream.read( &matName ); if ( matName.isEmpty() ) continue; if ( mFileVersion > 3 && mFileVersion < 6 ) { // Between version 3 and 5 we store the texture file names // relative to the terrain file. We restore the full path // here so that we can create a TerrainMaterial from it. materials.push_back( Torque::Path::CompressPath( mFilePath.getRoot() + mFilePath.getPath() + '/' + matName ) ); } else materials.push_back( matName ); } if ( mFileVersion <= 3 ) { GFXTexHandle terrainMat; Torque::Path matRelPath; // Try to automatically fix up our material file names for (U32 i = 0; i < materials.size(); i++) { if ( materials[i].isEmpty() ) continue; terrainMat.set( materials[i], &GFXDefaultPersistentProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) ); if ( terrainMat ) continue; matRelPath = materials[i]; String path = matRelPath.getPath(); String::SizeType n = path.find( '/', 0, String::NoCase ); if ( n != String::NPos ) { matRelPath.setPath( String(Con::getVariable( "$defaultGame" )) + path.substr( n, path.length() - n ) ); terrainMat.set( matRelPath, &GFXDefaultPersistentProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) ); if ( terrainMat ) { materials[i] = matRelPath.getFullPath(); mNeedsResaving = true; } } } // for (U32 i = 0; i < TerrainBlock::MaterialGroups; i++) } // if ( mFileVersion <= 3 ) if ( mFileVersion == 1 ) { for( S32 j = 0; j < sampleCount; j++ ) { if ( materialAlphaMap[baseMaterialMap[j]] == NULL ) { materialAlphaMap[baseMaterialMap[j]] = new U8[sampleCount]; dMemset(materialAlphaMap[baseMaterialMap[j]], 0, sampleCount); } materialAlphaMap[baseMaterialMap[j]][j] = 255; } } else { for( S32 k=0; k < materials.size(); k++ ) { AssertFatal(materialAlphaMap[k] == NULL, "Bad assumption. There should be no alpha map at this point..."); materialAlphaMap[k] = new U8[sampleCount]; stream.read(sampleCount, materialAlphaMap[k]); } } // Throw away the old texture and heightfield scripts. if ( mFileVersion >= 3 ) { U32 len; stream.read(&len); char *textureScript = (char *)dMalloc(len + 1); stream.read(len, textureScript); dFree( textureScript ); stream.read(&len); char *heightfieldScript = (char *)dMalloc(len + 1); stream.read(len, heightfieldScript); dFree( heightfieldScript ); } // Load and throw away the old edge terrain paths. if ( mFileVersion >= 5 ) { stream.readSTString(true); stream.readSTString(true); } U32 layerCount = materials.size() - 1; // Ok... time to convert all this mess to the layer index map! for ( U32 i=0; i < sampleCount; i++ ) { // Find the greatest layer. U32 layer = 0; U32 lastValue = 0; for ( U32 k=0; k < MaterialGroups; k++ ) { if ( materialAlphaMap[k] && materialAlphaMap[k][i] > lastValue ) { layer = k; lastValue = materialAlphaMap[k][i]; } } // Set the layer index. mLayerMap[i] = getMin( layer, layerCount ); } // Cleanup. for ( U32 i=0; i < MaterialGroups; i++ ) delete [] materialAlphaMap[i]; // Force resaving on these old file versions. //mNeedsResaving = false; // Resolve the TerrainMaterial objects from the names. _resolveMaterials( materials ); }
void MaterialList::mapMaterial( U32 i ) { AssertFatal( i < size(), "MaterialList::mapMaterialList - index out of bounds" ); if( mMatInstList[i] != NULL ) return; // lookup a material property entry const String &matName = getMaterialName(i); // JMQ: this code assumes that all materials have names. if( matName.isEmpty() ) { mMatInstList[i] = NULL; return; } String materialName = MATMGR->getMapEntry(matName); // IF we didn't find it, then look for a PolyStatic generated Material // [a little cheesy, but we need to allow for user override of generated Materials] if ( materialName.isEmpty() ) materialName = MATMGR->getMapEntry( String::ToString( "polyMat_%s", matName.c_str() ) ); if ( materialName.isNotEmpty() ) { Material * mat = MATMGR->getMaterialDefinitionByName( materialName ); mMatInstList[i] = mat ? mat->createMatInstance() : MATMGR->createWarningMatInstance(); } else { if ( Con::getBoolVariable( "$Materials::createMissing", true ) ) { // No Material found, create new "default" material with just a diffuseMap // First see if there is a valid diffuse texture GFXTexHandle texHandle; if (mLookupPath.isEmpty()) { texHandle.set( mMaterialNames[i], &GFXDefaultStaticDiffuseProfile, avar("%s() - handle (line %d)", __FUNCTION__, __LINE__) ); } else { // Should we strip off the extension of the path here before trying // to load the texture? String fullPath = String::ToString( "%s/%s", mLookupPath.c_str(), mMaterialNames[i].c_str() ); texHandle.set( fullPath, &GFXDefaultStaticDiffuseProfile, avar("%s() - handle (line %d)", __FUNCTION__, __LINE__) ); } if ( texHandle.isValid() ) { String newMatName = Sim::getUniqueName( "DefaultMaterial" ); Material *newMat = MATMGR->allocateAndRegister( newMatName, mMaterialNames[i] ); // Flag this as an autogenerated Material newMat->mAutoGenerated = true; // Overwrite diffuseMap in new material newMat->mDiffuseMapFilename[0] = texHandle->mTextureLookupName; // Set up some defaults for transparent textures if (texHandle->mHasTransparency) { newMat->mTranslucent = true; newMat->mTranslucentBlendOp = Material::LerpAlpha; newMat->mTranslucentZWrite = true; newMat->mAlphaRef = 20; } // create a MatInstance for the new material mMatInstList[i] = newMat->createMatInstance(); #ifndef TORQUE_SHIPPING Con::warnf( "[MaterialList::mapMaterials] Creating missing material for texture: %s", texHandle->mTextureLookupName.c_str() ); #endif } else { Con::errorf( "[MaterialList::mapMaterials] Unable to find material for texture: %s", mMaterialNames[i].c_str() ); mMatInstList[i] = MATMGR->createWarningMatInstance(); } } else { mMatInstList[i] = MATMGR->createWarningMatInstance(); } } }