void GuiSplitContainer::solvePanelConstraints( Point2I newDragPos, GuiContainer * firstPanel, GuiContainer * secondPanel, RectI clientRect ) { if( !firstPanel || !secondPanel ) return; if ( mOrientation == Horizontal ) { // Constrain based on Y axis (Horizontal Splitter) // This accounts for the splitter width S32 splitterSize = (S32)(mSplitRect.extent.y * 0.5); // Collapsed fixed panel if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() ) { newDragPos = Point2I(mSplitPoint.x, getExtent().y - splitterSize ); } else if( mFixedPanel == SecondPanel && !firstPanel->isVisible() ) { newDragPos = Point2I(mSplitPoint.x, splitterSize ); } else // Normal constraints { //newDragPos.y -= splitterSize; S32 newPosition = mClamp( newDragPos.y, firstPanel->getMinExtent().y + splitterSize, getExtent().y - secondPanel->getMinExtent().y - splitterSize ); newDragPos = Point2I( mSplitPoint.x, newPosition ); } } else { // Constrain based on X axis (Vertical Splitter) // This accounts for the splitter width S32 splitterSize = (S32)(mSplitRect.extent.x * 0.5); // Collapsed fixed panel if ( mFixedPanel == SecondPanel && !secondPanel->isVisible() ) { newDragPos = Point2I(getExtent().x - splitterSize, mSplitPoint.y ); } else if ( mFixedPanel == FirstPanel && !firstPanel->isVisible() ) { newDragPos = Point2I( splitterSize, mSplitPoint.x ); } else // Normal constraints { S32 newPosition = mClamp( newDragPos.x, firstPanel->getMinExtent().x + splitterSize, getExtent().x - secondPanel->getMinExtent().x - splitterSize ); newDragPos = Point2I( newPosition, mSplitPoint.y ); } } // Just in case, clamp to bounds of controls newDragPos.x = mClamp( newDragPos.x, clientRect.point.x, clientRect.point.x + clientRect.extent.x ); newDragPos.y = mClamp( newDragPos.y, clientRect.point.y, clientRect.point.y + clientRect.extent.y ); mSplitPoint = newDragPos; }
virtual void sampleChannels(int x, int y, unsigned char *out) { const U32 off = (x * mSourceSize + y) * mNumberOfChannels; for(S32 i=0; i<getNumberChannels(); i++) out[i] = mClamp(mSourceBuffer[off + i] * mScale, 0x0, 0xFF); }
//----------------------------------------------------------------------------- // // VEvent::setTriggerTime( pTime ); // // Apply the given trigger time to the object. // // If the project was built using the VT_EDITOR preprocessor argument, then // the validity of the passed value is verified. It also cannot be changed // while the controller is playing. // //----------------------------------------------------------------------------- void VEvent::setTriggerTime( const S32 &pTime ) { #ifdef VT_EDITOR VTrack *track = getTrack(); if ( !track ) { // Apply Time. mTriggerTime = pTime; return; } if ( track->isControllerPlaying() ) { // Don't Change While Playing. return; } /* // Check For Overlap. for ( ITreeNode *node = mChildNode; node != NULL; node = node->mSiblingNextNode ) { VEvent *event = ( VEvent* )node; if ( event == this ) { // Skip. continue; } const U32 startTime = getStartTime(); const U32 finishTime = getFinishTime(); if ( ( pTime > startTime && pTime < finishTime ) || ( ( pTime + mDuration ) > startTime && ( pTime + mDuration ) < finishTime ) || ( pTime < startTime && ( pTime + mDuration ) > finishTime ) ) { // Overlap! return; } } */ // Apply Time. mTriggerTime = mClamp( pTime, 0, getControllerDuration() ); // Sort Events. track->sort(); // Reset Track. track->onControllerReset( getControllerTime(), isControllerPlayingForward() ); #else // Apply Time. mTriggerTime = pTime; #endif }
void StdMoveList::clearMoves(U32 count) { if (!mConnection->isConnectionToServer()) { count = mClamp(count,0,mMoveCredit); mMoveCredit -= count; } Parent::clearMoves(count); }
bool AtlasClipMapImageSource::isDataAvailable( const U32 mipLevel, const RectI& inRegion ) const { // We need to convert from a mip level to a level in our TOC, potentially scaling. U32 baseMips = getBinLog2(mTOC->getTextureChunkSize()); U32 tocLevel = -1; if(mipLevel >= baseMips) { // In an inner or leaf tile. tocLevel = mipLevel - baseMips; } else { // It's in our base tile. tocLevel = 0; } // We don't scale beyond the depth of the TOC, so simply assert in that // case. AssertFatal(tocLevel < mTOC->getTreeDepth(), "AtlasClipMapImageSource::isDataAvailable - went beyond depth of tree."); // Check all the chunks of all the stubs in the appropriate region... RectI r; convertToTOCRect(tocLevel, inRegion, r); const S32 xStart = mClamp(r.point.x, 0, BIT(tocLevel)); const S32 xEnd = mClamp(r.point.x + r.extent.x, 0, BIT(tocLevel)); const S32 yStart = mClamp(r.point.y, 0, BIT(tocLevel)); const S32 yEnd = mClamp(r.point.y + r.extent.y, 0, BIT(tocLevel)); for(S32 x=xStart; x<xEnd; x++) { for(S32 y=yStart; y<yEnd; y++) { AtlasResourceTexStub *arts = mTOC->getResourceStub(mTOC->getStub(tocLevel, Point2I(x,y))); if(!arts->hasResource()) return false; } } return true; }
virtual void getColor(int x, int y, unsigned char &r, unsigned char &b, unsigned char &g, unsigned char &a) { const U32 off = (y * mSourceSize + x) * mNumberOfChannels; r = mClamp(U32(mSourceBuffer[off + 0]) *mScale, 0, 0xFF); if(mNumberOfChannels >= 2) b = mClamp(U32(mSourceBuffer[off + 1]) * mScale, 0, 0xFF); else b = 0; if(mNumberOfChannels >= 3) g = mClamp(U32(mSourceBuffer[off + 2]) * mScale, 0, 0xFF); else g = 0; if(mNumberOfChannels >= 4) a = mClamp(U32(mSourceBuffer[off + 3]) * mScale, 0, 0xFF); else a = 0; }
/// Helper for converting floating point linear volume /// to a logrithmic integer volume for dsound. LONG SFXDSVoice::_linearToLogVolume( F32 linVolume ) { LONG logVolume; if ( linVolume <= 0.0f ) logVolume = DSBVOLUME_MIN; else { logVolume = -2000.0 * mLog( 1.0f / linVolume ); logVolume = mClamp( logVolume, DSBVOLUME_MIN, DSBVOLUME_MAX ); } return logVolume; }
void mkFluid::setReflectionSize(U32 size) { mReflectionSize = getNextPow2(mClamp(size, 1, getGlobalReflectionSize())); if(mReflectionRT && mReflectionRT->getWidth() != mReflectionSize) { RenderTextureManager->deleteRenderTexture(mReflectionRT); mReflectionRT = NULL; } if(!mReflectionRT && mReflectionSize > 1) { RenderTextureFormat testFormat(RGBA8, Depth24, None, Stencil0, 0, false, false); RenderTextureFormat bestFit; RenderTextureManager->getClosestMatch(testFormat, bestFit); mReflectionRT = RenderTextureManager->createRenderTexture(mReflectionSize, mReflectionSize, bestFit); } }
void TSShapeInstance::setCurrentDetail( S32 dl, F32 intraDL ) { PROFILE_SCOPE( TSShapeInstance_setCurrentDetail ); mCurrentDetailLevel = mClamp( dl, -1, mShape->mSmallestVisibleDL ); mCurrentIntraDetailLevel = intraDL > 1.0f ? 1.0f : (intraDL < 0.0f ? 0.0f : intraDL); // Restrict the chosen detail level by cutoff value. if ( smNumSkipRenderDetails > 0 && mCurrentDetailLevel >= 0 ) { S32 cutoff = getMin( smNumSkipRenderDetails, mShape->mSmallestVisibleDL ); if ( mCurrentDetailLevel < cutoff ) { mCurrentDetailLevel = cutoff; mCurrentIntraDetailLevel = 1.0f; } } }
void GuiGameListMenuCtrl::setSelected(S32 index) { if (index == NO_ROW) { // deselection mSelected = NO_ROW; return; } if (! isValidRowIndex(index)) { return; } if (! isRowEnabled(index)) { // row is disabled, it can't be selected return; } mSelected = mClamp(index, 0, mRows.size() - 1); }
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 ClipMap::calculateClipMapLevels(const F32 near, const F32 far, const RectF &texBounds, S32 &outStartLevel, S32 &outEndLevel) { PROFILE_START(ClipMap_calculateClipMapLevels); // We also have to deal w/ the available data. So let's figure out if our // desired TCs are in the loaded textureset. // Adjust the specified TC range into a texel range. F32 ftexsize = F32(mTextureSize); RectF tcR(Point2F(texBounds.point.y * ftexsize, texBounds.point.x * ftexsize), ftexsize * texBounds.extent); // If we're tiling, make sure we're only insetting away from the clipmap bounds. // This avoids making bad LOD selections at clipmap boundaries. // Note: compress several compares into one since a*b=0 iff a==0 or b==0 bool doInset = true;//mTile || (tcR.point.x * tcR.point.y * (tcR.extent.x+tcR.point.x-mTextureSize) * (tcR.extent.y+tcR.point.y-mTextureSize) != 0); if(doInset) tcR.inset(-1, -1); // Put some safe defaults in for starters. outEndLevel = mClipStackDepth-1; outStartLevel = getMax(outEndLevel-3, S32(0)); // Now iterate over every clipstack entry and find the smallest that contains // the relevant TCs. S32 minLevelOverlap = mClipStackDepth - 1; S32 maxLevelOverlap = mClipStackDepth - 1; for(S32 i=mClipStackDepth-2; i>=0; i--) { // Find region for entry at this level. RectF r; F32 biti = F32(BIT(i)); F32 biticms = F32(BIT(i) * mClipMapSize); r.point = Point2F( biti * mLevels[i].mToroidalOffset.x, biti * mLevels[i].mToroidalOffset.y); r.extent.set(biticms,biticms); // Is our tex region fully contained? if(r.contains(tcR)) { // If we're fully contained, then this is our new max. maxLevelOverlap = i; minLevelOverlap = i; continue; } // Or else maybe we've got overlap? if (!r.overlaps(tcR)) break; // If we're overlapping then this is our new min... minLevelOverlap = getMin(minLevelOverlap, i); } // Given our level range, do a best fit. We ALWAYS have to have // enough for the minimum detail, so we fit that constraint then // do our best to give additional detail on top of that. // bias the minimum detail to allow smooth transitions to work properly, // this avoids a LOT of texture popping. maxLevelOverlap++; outEndLevel = mClamp(maxLevelOverlap, 0, mClipStackDepth-1); outStartLevel = mClamp(minLevelOverlap, outEndLevel - 3, outEndLevel - 1); // Make sure we're not exceeding our max delta. const S32 delta = outEndLevel - outStartLevel; AssertFatal(delta >= 1 && delta <= 4, "ClipMap::calculateClipMapLevels - range in levels outside of 2..4 range!"); PROFILE_END(); }
void ColladaShapeLoader::enumerateScene() { // Get animation clips Vector<const domAnimation_clip*> animationClips; for (S32 iClipLib = 0; iClipLib < root->getLibrary_animation_clips_array().getCount(); iClipLib++) { const domLibrary_animation_clips* libraryClips = root->getLibrary_animation_clips_array()[iClipLib]; for (S32 iClip = 0; iClip < libraryClips->getAnimation_clip_array().getCount(); iClip++) appSequences.push_back(new ColladaAppSequence(libraryClips->getAnimation_clip_array()[iClip])); } // Process all animations => this attaches animation channels to the targeted // Collada elements, and determines the length of the sequence if it is not // already specified in the Collada <animation_clip> element for (S32 iSeq = 0; iSeq < appSequences.size(); iSeq++) { ColladaAppSequence* appSeq = dynamic_cast<ColladaAppSequence*>(appSequences[iSeq]); F32 maxEndTime = 0; F32 minFrameTime = 1000.0f; for (S32 iAnim = 0; iAnim < appSeq->getClip()->getInstance_animation_array().getCount(); iAnim++) { domAnimation* anim = daeSafeCast<domAnimation>(appSeq->getClip()->getInstance_animation_array()[iAnim]->getUrl().getElement()); if (anim) processAnimation(anim, maxEndTime, minFrameTime); } if (appSeq->getEnd() == 0) appSeq->setEnd(maxEndTime); // Collada animations can be stored as sampled frames or true keyframes. For // sampled frames, use the same frame rate as the DAE file. For true keyframes, // resample at a fixed frame rate. appSeq->fps = mClamp(1.0f / minFrameTime + 0.5f, TSShapeLoader::MinFrameRate, TSShapeLoader::MaxFrameRate); } // First grab all of the top-level nodes Vector<domNode*> sceneNodes; for (S32 iSceneLib = 0; iSceneLib < root->getLibrary_visual_scenes_array().getCount(); iSceneLib++) { const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[iSceneLib]; for (S32 iScene = 0; iScene < libScenes->getVisual_scene_array().getCount(); iScene++) { const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[iScene]; for (S32 iNode = 0; iNode < visualScene->getNode_array().getCount(); iNode++) sceneNodes.push_back(visualScene->getNode_array()[iNode]); } } // Set LOD option bool singleDetail = true; switch (ColladaUtils::getOptions().lodType) { case ColladaUtils::ImportOptions::DetectDTS: // Check for a baseXX->startXX hierarchy at the top-level, if we find // one, use trailing numbers for LOD, otherwise use a single size for (S32 iNode = 0; singleDetail && (iNode < sceneNodes.size()); iNode++) { domNode* node = sceneNodes[iNode]; if (dStrStartsWith(_GetNameOrId(node), "base")) { for (S32 iChild = 0; iChild < node->getNode_array().getCount(); iChild++) { domNode* child = node->getNode_array()[iChild]; if (dStrStartsWith(_GetNameOrId(child), "start")) { singleDetail = false; break; } } } } break; case ColladaUtils::ImportOptions::SingleSize: singleDetail = true; break; case ColladaUtils::ImportOptions::TrailingNumber: singleDetail = false; break; default: break; } ColladaAppMesh::fixDetailSize( singleDetail, ColladaUtils::getOptions().singleDetailSize ); // Process the top level nodes for (S32 iNode = 0; iNode < sceneNodes.size(); iNode++) { ColladaAppNode* node = new ColladaAppNode(sceneNodes[iNode], 0); if (!processNode(node)) delete node; } // Make sure that the scene has a bounds node (for getting the root scene transform) if (!boundsNode) { domVisual_scene* visualScene = root->getLibrary_visual_scenes_array()[0]->getVisual_scene_array()[0]; domNode* dombounds = daeSafeCast<domNode>( visualScene->createAndPlace( "node" ) ); dombounds->setName( "bounds" ); ColladaAppNode *appBounds = new ColladaAppNode(dombounds, 0); if (!processNode(appBounds)) delete appBounds; } }
void ArrayObject::insert( const String &key, const String &value, S32 index ) { index = mClamp( index, 0, mArray.size() ); mArray.insert( index, Element( key, value ) ); }
{ AssertFatal( terrain, "TerrainSmoothAction::smooth() - Got null object!" ); // Store our input parameters. mTerrainId = terrain->getId(); mSteps = steps; mFactor = factor; // The redo can do the rest. redo(); } DefineConsoleMethod( TerrainSmoothAction, smooth, void, ( TerrainBlock *terrain, F32 factor, U32 steps ), , "( TerrainBlock obj, F32 factor, U32 steps )") { if (terrain) object->smooth( terrain, factor, mClamp( steps, 1, 13 ) ); } void TerrainSmoothAction::undo() { // First find the terrain from the id. TerrainBlock *terrain; if ( !Sim::findObject( mTerrainId, terrain ) || !terrain ) return; // Get the terrain file. TerrainFile *terrFile = terrain->getFile(); // Copy our stored heightmap to the file. terrFile->setHeightMap( mUnsmoothedHeights, false );
void AtlasClipMapImageSource::setInterestCenter( const Point2I& origin, const U32 radius ) { // Walk the quadtree, topmost unloaded stuff has highest priority. // We also need to issue unloads for stuff around the old origin... // So let's iterate over everything within the bounds of our radius of BOTH // origins. If it's within the originRect, keep it, otherwise cancel it. RectI oldOriginTexelRect, newOriginTexelRect; RectI oldOriginTOCRect, newOriginTOCRect; RectI unionRect; for(S32 i=mTOC->getTreeDepth()-1; i>=0; i--) { const U32 shift = mTOC->getTreeDepth() - i - 1; oldOriginTexelRect.point = mCacheOrigin; oldOriginTexelRect.point.x >>= shift; oldOriginTexelRect.point.y >>= shift; oldOriginTexelRect.extent.set(0,0); S32 rad = (S32)radius; oldOriginTexelRect.inset(-rad, -rad); newOriginTexelRect.point = origin; newOriginTexelRect.point.x >>= shift; newOriginTexelRect.point.y >>= shift; newOriginTexelRect.extent.set(0,0); newOriginTexelRect.inset(-rad, -rad); convertToTOCRect(i, oldOriginTexelRect, oldOriginTOCRect); convertToTOCRect(i, newOriginTexelRect, newOriginTOCRect); unionRect = oldOriginTOCRect; unionRect.unionRects(newOriginTOCRect); // Clamp our update region so we're not walking stuff that is out of range. const S32 xStart = mClamp(unionRect.point.x, 0, BIT(i)); const S32 xEnd = mClamp(unionRect.point.x + unionRect.extent.x, 0, BIT(i)); const S32 yStart = mClamp(unionRect.point.y, 0, BIT(i)); const S32 yEnd = mClamp(unionRect.point.y + unionRect.extent.y, 0, BIT(i)); for(S32 x=xStart; x<xEnd; x++) { for(S32 y=yStart; y<yEnd; y++) { const Point2I pos(x, y); AtlasInstanceTexStub *aits = mTOC->getStub(i, pos); // Note we weight our loads by depth - the closest to the root // goes first. if(newOriginTOCRect.pointInRect(pos)) mTOC->requestLoad(aits, AtlasTOC::NormalPriority, F32(shift + 1) / F32(mTOC->getTreeDepth() + 1)); else { mTOC->cancelLoadRequest(aits, AtlasTOC::NormalPriority); } } } } // Now we can update the cache origin. mCacheOrigin = origin; }
void mkFluid::enableRefraction(bool refract) { mDoRefraction = mClamp((U32)refract, 0, (U32)isGlobalRefractive()); }
void terrTexGen( vertexType vtype, Point4F *clipmapMapping, const MatrixF &blockTransform, const Point3F &cameraPosition, LightInfo *light, SceneState * state) { PROFILE_SCOPE(Terrain_TexGen); SceneManager * sceneManager = state->getSceneManager(); Point3F relative; const F32 blockTexCoordScale = 1.0f / (TerrainRender::mCurrentBlock->getSquareSize() * TerrainBlock::BlockSize); // Apply texgen to the new verts... if (vtype == vertexTypeFullClipMapping) { for(U32 i=0; i<mCurVertex; i++) { mVertexStore[i].texCoord.x = mVertexStore[i].point.x * blockTexCoordScale; mVertexStore[i].texCoord.y = mVertexStore[i].point.y * blockTexCoordScale; } } else if (vtype == vertexTypeSingleTextureClipMapping) { // Compute the fixedfunction vert stuff now AssertFatal(clipmapMapping != NULL, "TerrBatch::end - vertexTypeSingleTextureClipMapping requires clipmapMapping variable!"); const F32 fadeConstant = 3.0f; const F32 blockTexCoordScale2 = blockTexCoordScale * clipmapMapping->z; for(U32 i=0; i<mCurVertex; i++) { mVertexStorePCNT[i].point = mVertexStore[i].point; mVertexStorePCNT[i].normal = mVertexStore[i].normal; mVertexStorePCNT[i].texCoord.x = mVertexStore[i].point.x * blockTexCoordScale2; mVertexStorePCNT[i].texCoord.y = mVertexStore[i].point.y * blockTexCoordScale2; relative.x = mVertexStorePCNT[i].texCoord.x - clipmapMapping->x; relative.y = mVertexStorePCNT[i].texCoord.y - clipmapMapping->y; relative.z = 0; // note: this uses 128.0f - instead of 255.0f - to hide some // transition artifacts at the edges (which are not visible // in the shader path due to its use of /2 in the vertex // shader and saturate(fade*2) in the pixel shader, which // allows sharp transitions to be interpolated more cleanly) mVertexStorePCNT[i].color.set(255, 255, 255, (U8)mClampF(128.0f - (relative.len() * (2.0f * fadeConstant) - (fadeConstant - 1.0f)) * 255.0f, 0.0f, 255.0f)); } } else if (vtype == vertexTypeDLight) { // Compute the fixedfunction vert stuff now AssertFatal(clipmapMapping != NULL, "TerrBatch::end - vertexTypeDLight requires clipmapMapping variable!"); AssertFatal(light != NULL, "TerrBatch::end - vertexTypeDLight requires light variable!"); AssertFatal(light->mRadius > 0, "TerrBatch::end - vertexTypeDLight requires light->mRadius > 0!"); const F32 blockTexCoordScale2 = blockTexCoordScale * clipmapMapping->z; const F32 heightOffset = sceneManager->getFogHeightOffset(); const F32 inverseHeightRange = sceneManager->getFogInvHeightRange(); const F32 inverseVisibleDistanceMod = 1.0f / sceneManager->getVisibleDistanceMod(); Point3F worldPoint; const F32 lightRadius = light->mRadius; const Point3F lightPosition = light->mPos; F32 intensity; const F32 inverseLightRadius = 1.0f / lightRadius; // note: this imitates sgLightingModel only very loosely for // performance reasons, it does look very similar to the shader path for(U32 i=0; i<mCurVertex; i++) { mVertexStorePCNTT[i].point = mVertexStore[i].point; mVertexStorePCNTT[i].normal = mVertexStore[i].normal; mVertexStorePCNTT[i].texCoord[0].x = mVertexStore[i].point.x * blockTexCoordScale2; mVertexStorePCNTT[i].texCoord[0].y = mVertexStore[i].point.y * blockTexCoordScale2; blockTransform.mulP(mVertexStore[i].point, &worldPoint); relative = worldPoint - cameraPosition; mVertexStorePCNTT[i].texCoord[1].x = 1.0 - (relative.len() * inverseVisibleDistanceMod); mVertexStorePCNTT[i].texCoord[1].y = (worldPoint.z - heightOffset) * inverseHeightRange; relative = worldPoint - lightPosition; intensity = getMax(1.0f - relative.len() * inverseLightRadius, 0.0f); intensity = 512.0f * intensity; if (intensity > 0) mVertexStorePCNTT[i].color.set((U8)getMin(light->mColor.red * intensity, 255.0f), (U8)getMin(light->mColor.green * intensity, 255.0f), (U8)getMin(light->mColor.blue * intensity, 255.0f), 255); else mVertexStorePCNTT[i].color.set(0, 0, 0, 255); } } else if (vtype == vertexTypeFog) { const F32 heightOffset = sceneManager->getFogHeightOffset(); const F32 inverseHeightRange = sceneManager->getFogInvHeightRange(); const F32 inverseVisibleDistanceMod = 1.0f / sceneManager->getVisibleDistanceMod(); Point3F worldPoint; for(U32 i=0; i<mCurVertex; i++) { mVertexStorePCNT[i].point = mVertexStore[i].point; mVertexStorePCNT[i].normal = mVertexStore[i].normal; blockTransform.mulP(mVertexStore[i].point, &worldPoint); relative = worldPoint - cameraPosition; mVertexStorePCNT[i].texCoord.x = 1.0 - (relative.len() * inverseVisibleDistanceMod); mVertexStorePCNT[i].texCoord.y = (worldPoint.z - heightOffset) * inverseHeightRange; mVertexStorePCNT[i].color.set(255, 255, 255, 255); } } // The only time 'vertexTypeDetail' is used is during a fixed-function detail pass. else if( vtype == vertexTypeDetail ) { // Get detail distance squared to save us from sqrt const F32 detailDistanceSquared = TerrainRender::mCurrentBlock->mDetailDistance * TerrainRender::mCurrentBlock->mDetailDistance; // Detail Brightness done via assignment of color values const U8 colorByte = mClamp( 255 * TerrainRender::mCurrentBlock->mDetailBrightness, 0, 255 ); Point3F worldPoint; for( U32 i = 0; i < mCurVertex; i++ ) { mVertexStorePCNT[i].point = mVertexStore[i].point; mVertexStorePCNT[i].normal = mVertexStore[i].normal; mVertexStorePCNT[i].texCoord.x = mVertexStore[i].point.x * blockTexCoordScale; mVertexStorePCNT[i].texCoord.y = mVertexStore[i].point.y * blockTexCoordScale; // Transform vertex into world space blockTransform.mulP( mVertexStore[i].point, &worldPoint ); relative = worldPoint - cameraPosition; // Alpha const F32 alpha = TerrainRender::mCurrentBlock->mDetailBrightness * ( 1.0f - ( relative.lenSquared() / detailDistanceSquared ) ); // Assign alpha value to vert so the detail texture blend fades mVertexStorePCNT[i].color.set( colorByte, colorByte, colorByte, mClamp( alpha * 255, 0, 255 ) ); } } else { for(U32 i=0; i<mCurVertex; i++) { mVertexStorePCNT[i].point = mVertexStore[i].point; mVertexStorePCNT[i].normal = mVertexStore[i].normal; mVertexStorePCNT[i].texCoord.x = mVertexStore[i].point.x * blockTexCoordScale; mVertexStorePCNT[i].texCoord.y = mVertexStore[i].point.y * blockTexCoordScale; mVertexStorePCNT[i].color.set(255, 255, 255, 255); } } }
bool StandardMainLoop::doMainLoop() { #ifdef TORQUE_DEBUG if( gStartupTimer ) { Con::printf( "Started up in %.2f seconds...", F32( gStartupTimer->getElapsedMs() ) / 1000.f ); SAFE_DELETE( gStartupTimer ); } #endif bool keepRunning = true; // while(keepRunning) { tm->setBackgroundThreshold(mClamp(sgBackgroundProcessSleepTime, 1, 200)); tm->setForegroundThreshold(mClamp(sgTimeManagerProcessInterval, 1, 200)); // update foreground/background status if(WindowManager->getFirstWindow()) { static bool lastFocus = false; bool newFocus = ( WindowManager->getFocusedWindow() != NULL ); if(lastFocus != newFocus) { #ifndef TORQUE_SHIPPING Con::printf("Window focus status changed: focus: %d", newFocus); if (!newFocus) Con::printf(" Using background sleep time: %u", Platform::getBackgroundSleepTime()); #endif #ifdef TORQUE_OS_MAC if (newFocus) WindowManager->getFirstWindow()->show(); #endif lastFocus = newFocus; } #ifndef TORQUE_OS_MAC // under the web plugin do not sleep the process when the child window loses focus as this will cripple the browser perfomance if (!Platform::getWebDeployment()) tm->setBackground(!newFocus); else tm->setBackground(false); #else tm->setBackground(false); #endif } else { tm->setBackground(false); } PROFILE_START(MainLoop); Sampler::beginFrame(); if(!Process::processEvents()) keepRunning = false; ThreadPool::processMainThreadWorkItems(); Sampler::endFrame(); PROFILE_END_NAMED(MainLoop); } return keepRunning; }
void TerrCell::_updateVertexBuffer() { PROFILE_SCOPE( TerrCell_UpdateVertexBuffer ); // Start off with no empty squares mHasEmpty = false; mEmptyVertexList.clear(); mVertexBuffer.set( GFX, smVBSize, GFXBufferTypeStatic ); const F32 squareSize = mTerrain->getSquareSize(); const U32 blockSize = mTerrain->getBlockSize(); const U32 stepSize = mSize / smMinCellSize; U32 vbcounter = 0; TerrVertex *vert = mVertexBuffer.lock(); Point2I gridPt; Point2F point; F32 height; Point3F normal; const TerrainFile *file = mTerrain->getFile(); for ( U32 y = 0; y < smVBStride; y++ ) { for ( U32 x = 0; x < smVBStride; x++ ) { // We clamp here to keep the geometry from reading across // one side of the height map to the other causing walls // around the edges of the terrain. gridPt.x = mClamp( mPoint.x + x * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + y * stepSize, 0, blockSize - 1 ); // Setup this point. point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height; // Get the normal. mTerrain->getSmoothNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent z. vert->tangentZ = fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ) - height; // Test the empty state for this vert. if ( file->isEmptyAt( gridPt.x, gridPt.y ) ) { mHasEmpty = true; mEmptyVertexList.push_back( vbcounter ); } vbcounter++; ++vert; } } // Add verts for 'skirts' around/beneath the edge verts of this cell. // This could probably be reduced to a loop... const F32 skirtDepth = mSize / smMinCellSize * mTerrain->getSquareSize(); // Top edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x + i * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } // Bottom edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x + i * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + smMinCellSize * stepSize, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } // Left edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + i * stepSize, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } // Right edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x + smMinCellSize * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + i * stepSize, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } AssertFatal( vbcounter == smVBSize, "bad" ); mVertexBuffer.unlock(); }