GFXTextureObject* ReflectionManager::getRefractTex( bool forceUpdate ) { GFXTarget *target = GFX->getActiveRenderTarget(); GFXFormat targetFormat = target->getFormat(); const Point2I &targetSize = target->getSize(); #if defined(TORQUE_OS_XENON) // On the Xbox360, it needs to do a resolveTo from the active target, so this // may as well be the full size of the active target const U32 desWidth = targetSize.x; const U32 desHeight = targetSize.y; #else const U32 desWidth = mFloor( (F32)targetSize.x * smRefractTexScale ); const U32 desHeight = mFloor( ( F32)targetSize.y * smRefractTexScale ); #endif if ( mRefractTex.isNull() || mRefractTex->getWidth() != desWidth || mRefractTex->getHeight() != desHeight || mRefractTex->getFormat() != targetFormat ) { mRefractTex.set( desWidth, desHeight, targetFormat, &RefractTextureProfile, "mRefractTex" ); mUpdateRefract = true; } if ( forceUpdate || mUpdateRefract ) { target->resolveTo( mRefractTex ); mUpdateRefract = false; } return mRefractTex; }
// This "rounds" the projection matrix to remove subtexel movement during shadow map // rasterization. This is here to reduce shadow shimmering. void PSSMLightShadowMap::_roundProjection(const MatrixF& lightMat, const MatrixF& cropMatrix, Point3F &offset, U32 splitNum) { // Round to the nearest shadowmap texel, this helps reduce shimmering MatrixF currentProj = GFX->getProjectionMatrix(); currentProj = cropMatrix * currentProj * lightMat; // Project origin to screen. Point4F originShadow4F(0,0,0,1); currentProj.mul(originShadow4F); Point2F originShadow(originShadow4F.x / originShadow4F.w, originShadow4F.y / originShadow4F.w); // Convert to texture space (0..shadowMapSize) F32 t = mNumSplits < 4 ? mShadowMapTex->getWidth() / mNumSplits : mShadowMapTex->getWidth() / 2; Point2F texelsToTexture(t / 2.0f, mShadowMapTex->getHeight() / 2.0f); if (mNumSplits >= 4) texelsToTexture.y *= 0.5f; originShadow.convolve(texelsToTexture); // Clamp to texel boundary Point2F originRounded; originRounded.x = mFloor(originShadow.x + 0.5f); originRounded.y = mFloor(originShadow.y + 0.5f); // Subtract origin to get an offset to recenter everything on texel boundaries originRounded -= originShadow; // Convert back to texels (0..1) and offset originRounded.convolveInverse(texelsToTexture); offset.x += originRounded.x; offset.y += originRounded.y; }
GFXTextureObject* ReflectionManager::getRefractTex() { GFXTarget *target = GFX->getActiveRenderTarget(); GFXFormat targetFormat = target->getFormat(); const Point2I &targetSize = target->getSize(); const U32 desWidth = mFloor( (F32)targetSize.x * mRefractTexScale ); const U32 desHeight = mFloor( ( F32)targetSize.y * mRefractTexScale ); if ( mRefractTex.isNull() || mRefractTex->getWidth() != desWidth || mRefractTex->getHeight() != desHeight || mRefractTex->getFormat() != targetFormat ) { mRefractTex.set( desWidth, desHeight, targetFormat, &RefractTextureProfile, "mRefractTex" ); mUpdateRefract = true; } if ( mUpdateRefract ) { target->resolveTo( mRefractTex ); mUpdateRefract = false; } return mRefractTex; }
bool VolumetricFogRTManager::Init() { if (mIsInitialized) { Con::errorf("VolumetricFogRTManager allready initialized!!"); return true; } GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas")); if (cv == NULL) { Con::errorf("VolumetricFogRTManager::Init() - Canvas not found!!"); return false; } mPlatformWindow = cv->getPlatformWindow(); mPlatformWindow->getScreenResChangeSignal().notify(this,&VolumetricFogRTManager::ResizeRT); if (mTargetScale < 1 || GFX->getAdapterType() == Direct3D11) mTargetScale = 1; mWidth = mFloor(mPlatformWindow->getClientExtent().x / mTargetScale); mHeight = mFloor(mPlatformWindow->getClientExtent().y / mTargetScale); mDepthBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F, &GFXRenderTargetProfile, avar("%s() - mDepthBuffer (line %d)", __FUNCTION__, __LINE__)); if (!mDepthBuffer.isValid()) { Con::errorf("VolumetricFogRTManager Fatal Error: Unable to create Depthbuffer"); return false; } if (!mDepthTarget.registerWithName("volfogdepth")) { Con::errorf("VolumetricFogRTManager Fatal Error : Unable to register Depthbuffer"); return false; } mDepthTarget.setTexture(mDepthBuffer); mFrontBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F, &GFXRenderTargetProfile, avar("%s() - mFrontBuffer (line %d)", __FUNCTION__, __LINE__)); if (!mFrontBuffer.isValid()) { Con::errorf("VolumetricFogRTManager Fatal Error: Unable to create front buffer"); return false; } if (!mFrontTarget.registerWithName("volfogfront")) { Con::errorf("VolumetricFogRTManager Fatal Error : Unable to register Frontbuffer"); return false; } mFrontTarget.setTexture(mFrontBuffer); Con::setVariable("$VolumetricFog::density", "0.0"); mIsInitialized = true; return true; }
//-------------------------------------------------------------------------- // Get wave offset for texture animations using a wave transform //-------------------------------------------------------------------------- F32 ProcessedShaderMaterial::_getWaveOffset( U32 stage ) { switch( mMaterial->mWaveType[stage] ) { case Material::Sin: { return mMaterial->mWaveAmp[stage] * mSin( M_2PI * mMaterial->mWavePos[stage] ); break; } case Material::Triangle: { F32 frac = mMaterial->mWavePos[stage] - mFloor( mMaterial->mWavePos[stage] ); if( frac > 0.0 && frac <= 0.25 ) { return mMaterial->mWaveAmp[stage] * frac * 4.0; } if( frac > 0.25 && frac <= 0.5 ) { return mMaterial->mWaveAmp[stage] * ( 1.0 - ((frac-0.25)*4.0) ); } if( frac > 0.5 && frac <= 0.75 ) { return mMaterial->mWaveAmp[stage] * (frac-0.5) * -4.0; } if( frac > 0.75 && frac <= 1.0 ) { return -mMaterial->mWaveAmp[stage] * ( 1.0 - ((frac-0.75)*4.0) ); } break; } case Material::Square: { F32 frac = mMaterial->mWavePos[stage] - mFloor( mMaterial->mWavePos[stage] ); if( frac > 0.0 && frac <= 0.5 ) { return 0.0; } else { return mMaterial->mWaveAmp[stage]; } break; } } return 0.0; }
bool RenderTexTargetBinManager::_onPreRender(SceneRenderState * state, bool preserve /* = false */) { PROFILE_SCOPE(RenderTexTargetBinManager_onPreRender); #ifndef TORQUE_SHIPPING AssertFatal( m_NeedsOnPostRender == false, "_onPostRender not called on RenderTexTargetBinManager, or sub-class." ); m_NeedsOnPostRender = false; #endif // Update the render target size const Point2I &rtSize = GFX->getActiveRenderTarget()->getSize(); switch(mTargetSizeType) { case WindowSize: setTargetSize(rtSize); break; case WindowSizeScaled: { Point2I scaledTargetSize(mFloor(rtSize.x * mTargetScale.x), mFloor(rtSize.y * mTargetScale.y)); setTargetSize(scaledTargetSize); break; } case FixedSize: // No adjustment necessary break; } if( mTargetChainLength == 0 ) return false; GFXTextureTargetRef binTarget = _getTextureTarget(mTargetChainIdx); if( binTarget.isNull() ) return false; // Attach active depth target texture binTarget->attachTexture(GFXTextureTarget::DepthStencil, getRenderPass()->getDepthTargetTexture()); // Preserve contents if(preserve) GFX->getActiveRenderTarget()->preserve(); GFX->pushActiveRenderTarget(); GFX->setActiveRenderTarget(binTarget); GFX->setViewport( mNamedTarget.getViewport() ); #ifndef TORQUE_SHIPPING m_NeedsOnPostRender = true; #endif return true; }
void CameraSpline::buildTimeMap() { if (!mIsMapDirty) return; gBuilding = true; mTimeMap.clear(); mTimeMap.reserve(size()*3); // preallocate // Initial node and knot value.. TimeMap map; map.mTime = 0; map.mDistance = 0; mTimeMap.push_back(map); Knot ka,kj,ki; value(0, &kj, true); F32 length = 0.0f; ka = kj; // Loop through the knots and add nodes. Nodes are added for every knot and // whenever the spline length and segment length deviate by epsilon. F32 epsilon = Con::getFloatVariable("CameraSpline::epsilon", 0.90f); const F32 Step = 0.05f; F32 lt = 0,time = 0; do { if ((time += Step) > F32(mSize - 1)) time = (F32)mSize - 1.0f; value(time, &ki, true); length += (ki.mPosition - kj.mPosition).len(); F32 segment = (ki.mPosition - ka.mPosition).len(); if ((segment / length) < epsilon || time == (mSize - 1) || mFloor(lt) != mFloor(time)) { map.mTime = time; map.mDistance = length; mTimeMap.push_back(map); ka = ki; } kj = ki; lt = time; } while (time < mSize - 1); mIsMapDirty = false; gBuilding = false; }
bool default_scan(const String &data, Point2I & result) { // Handle passed as floating point from script if(data.find('.') != String::NPos) { Point2F tempResult; dSscanf(data.c_str(),"%f %f",&tempResult.x,&tempResult.y); result.x = mFloor(tempResult.x); result.y = mFloor(tempResult.y); } else dSscanf(data.c_str(),"%d %d",&result.x,&result.y); return true; }
Box3F PSSMLightShadowMap::_calcClipSpaceAABB(const Frustum& f, const MatrixF& transform, F32 farDist) { // Calculate frustum center Point3F center(0,0,0); for (U32 i = 0; i < 8; i++) { const Point3F& pt = f.getPoints()[i]; center += pt; } center /= 8; // Calculate frustum bounding sphere radius F32 radius = 0.0f; for (U32 i = 0; i < 8; i++) radius = getMax(radius, (f.getPoints()[i] - center).lenSquared()); radius = mFloor( mSqrt(radius) ); // Now build box for sphere Box3F result; Point3F radiusBox(radius, radius, radius); result.minExtents = center - radiusBox; result.maxExtents = center + radiusBox; // Transform to light projection space transform.mul(result); return result; }
void SFXDSVoice::setPitch( F32 pitch ) { F32 sampleRate = _getBuffer()->getFormat().getSamplesPerSecond(); F32 frequency = mFloor( mClampF( sampleRate * pitch, DSBFREQUENCY_MIN, DSBFREQUENCY_MAX ) ); DSAssert( mDSBuffer->SetFrequency( ( U32 )frequency ), "SFXDSVoice::setPitch - couldn't set playback frequency."); }
//-------------------------------------------------------------------------- /// Function to draw a set of boxes blending throughout an array of colors void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors) { GFX->setStateBlock(mStateBlock); S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x + 4; S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y + 4; // Calculate increment value S32 x_inc = int(mFloor((r - l) / F32(numColors-1))); S32 y_inc = int(mFloor((b - t) / F32(numColors-1))); for( U16 i = 0;i < numColors - 1; i++ ) { // This is not efficent, but then again it doesn't really need to be. -pw PrimBuild::begin( GFXTriangleFan, 4 ); if (!vertical) // Horizontal (+x) { // First color PrimBuild::color( colors[i] ); PrimBuild::vertex2i( l, t ); PrimBuild::vertex2i( l, b ); // Second color PrimBuild::color( colors[i+1] ); PrimBuild::vertex2i( l + x_inc, b ); PrimBuild::vertex2i( l + x_inc, t ); l += x_inc; } else // Vertical (+y) { // First color PrimBuild::color( colors[i] ); PrimBuild::vertex2i( l, t ); PrimBuild::vertex2i( r, t ); // Second color PrimBuild::color( colors[i+1] ); PrimBuild::vertex2i( r, t + y_inc ); PrimBuild::vertex2i( l, t + y_inc ); t += y_inc; } PrimBuild::end(); } }
static S32 QSORT_CALLBACK compareReflectors( const void *a, const void *b ) { const ReflectorBase *A = *((ReflectorBase**)a); const ReflectorBase *B = *((ReflectorBase**)b); F32 dif = B->score - A->score; return (S32)mFloor( dif ); }
void AtlasOldMesher::writeVertex(Stream *s, Vert *vert, const S8 level) { S16 x, y, z; const Point2I &vertPos = vert->pos; Point3F center; mBounds.getCenter(¢er); if (vert->special) z = vert->z; else z = mHeight->sampleRead(vertPos); S32 xTmp, yTmp; xTmp = (S32)mFloor(((vertPos.x * mHeight->mSampleSpacing - center.x) * mCompressionFactor.x) + 0.5); yTmp = (S32)mFloor(((vertPos.y * mHeight->mSampleSpacing - center.y) * mCompressionFactor.y) + 0.5); AssertFatal(S16(xTmp) == xTmp, "AtlasOldMesher::writeVertex - Overflow writing x-coordinate!"); AssertFatal(S16(yTmp) == yTmp, "AtlasOldMesher::writeVertex - Overflow writing y-coordinate!"); x = xTmp; y = yTmp; s->write(x); s->write(y); s->write(z); // Morph info. Calculate the difference between the // vert height, and the height of the same spot in the // next lower-LOD mesh. S16 morphHeight; if (vert->special) morphHeight = z; // special verts don't morph. else { morphHeight = mHeight->getHeightAtLOD(vertPos, level + 1); } S32 morphDelta = (S32(morphHeight) - S32(z)); s->write(S16(morphDelta)); if(morphDelta != S16(morphDelta)) Con::warnf("AtlasOldMesher::writeVertex - overflow in lerpedHeight!"); }
S32 VideoCapture::getMsPerFrame() { //Add accumulated error to ms per frame before rounding F32 roundTime = mFloor(mMsPerFrame + mMsPerFrameError + 0.5f); //Accumulate the rounding errors mMsPerFrameError += mMsPerFrame - roundTime; return (S32)roundTime; }
bool VolumetricFogRTManager::Resize() { if (mTargetScale < 1 || GFX->getAdapterType() == Direct3D11) mTargetScale = 1; mWidth = mFloor(mPlatformWindow->getClientExtent().x / mTargetScale); mHeight = mFloor(mPlatformWindow->getClientExtent().y / mTargetScale); if (mWidth < 16 || mHeight < 16) return false; if (mFrontTarget.isRegistered()) mFrontTarget.setTexture(NULL); if (mDepthTarget.isRegistered()) mDepthTarget.setTexture(NULL); if (mDepthBuffer.isValid()) mDepthBuffer->kill(); if (mFrontBuffer.isValid()) mFrontBuffer->kill(); mFrontBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F, &GFXRenderTargetProfile, avar("%s() - mFrontBuffer (line %d)", __FUNCTION__, __LINE__)); if (!mFrontBuffer.isValid()) { Con::errorf("VolumetricFogRTManager::Resize() Fatal Error: Unable to create front buffer"); return false; } mFrontTarget.setTexture(mFrontBuffer); mDepthBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F, &GFXRenderTargetProfile, avar("%s() - mDepthBuffer (line %d)", __FUNCTION__, __LINE__)); if (!mDepthBuffer.isValid()) { Con::errorf("VolumetricFogRTManager::Resize() Fatal Error: Unable to create Depthbuffer"); return false; } mDepthTarget.setTexture(mDepthBuffer); return true; }
void SFXController::_onParameterEvent( SFXParameter* parameter, SFXParameterEvent event ) { Parent::_onParameterEvent( parameter, event ); // Implement cursor semantic. if( event == SFXParameterEvent_ValueChanged && parameter->getChannel() == SFXChannelCursor ) { U32 slot = U32( mFloor( parameter->getValue() ) ); if( slot != getCurrentSlot() ) setCurrentSlot( slot ); } }
void GuiRolloutCtrl::animateTo( S32 height ) { // We do nothing if we're already animating if( mIsAnimating ) return; bool collapsing = (bool)( getHeight() > height ); // If we're already at the destination height, bail if ( getHeight() >= height && !collapsing ) { mIsExpanded = true; return; } // If we're already at the destination height, bail if ( getHeight() <= height && collapsing ) { mIsExpanded = false; return; } // Set destination height mAnimateDestHeight = height; // Set Animation Mode mCollapsing = collapsing; // Set Animation Step (Increment) if ( collapsing ) mAnimateStep = (S32)mFloor( (F32)( getHeight() - height ) / 3.f ); else mAnimateStep = (S32)mFloor( (F32)( height - getHeight() ) / 3.f ); // Start our animation mIsAnimating = true; }
void LeapMotionFrame::copyFromFrameHands(const Leap::HandList& hands, const F32& maxHandAxisRadius) { // Set up Vectors mHandValid.increment(mHandCount); mHandId.increment(mHandCount); mHandRawPos.increment(mHandCount); mHandPos.increment(mHandCount); mHandRot.increment(mHandCount); mHandRotQuat.increment(mHandCount); mHandRotAxis.increment(mHandCount); mHandPointablesCount.increment(mHandCount); // Copy data for(U32 i=0; i<mHandCount; ++i) { const Leap::Hand& hand = hands[i]; mHandValid[i] = hand.isValid(); mHandId[i] = hand.id(); // Position LeapMotionUtil::convertPosition(hand.palmPosition(), mHandRawPos[i]); mHandPos[i].x = (S32)mFloor(mHandRawPos[i].x); mHandPos[i].y = (S32)mFloor(mHandRawPos[i].y); mHandPos[i].z = (S32)mFloor(mHandRawPos[i].z); // Rotation LeapMotionUtil::convertHandRotation(hand, mHandRot[i]); mHandRotQuat[i].set(mHandRot[i]); // Thumb stick axis rotation LeapMotionUtil::calculateHandAxisRotation(mHandRot[i], maxHandAxisRadius, mHandRotAxis[i]); // Pointables mHandPointablesCount[i] = hand.pointables().count(); } }
void main() { Floor mFloor(7); Container1 mContainer1(5, 1); Container2 mContainer2(5, 7); Control mControl(mFloor, 7); system("color F8"); system("chcp 437"); system("cls"); InitialDisplay(); int i; for(i = 1; i <= 7; i++) mFloor.Display(i); char key, firstInput = 0; while(1) { if(kbhit()) { key = getch(); if( KeyTest(key) ) { if( firstInput == 0) { firstInput = key; DisplayKey(key, 0); } else { mFloor.PushPerson(firstInput - '0', key - '0'); DisplayKey(firstInput, key); firstInput = 0; } } } mContainer1.Operater(); mContainer2.Operater(); mControl.Operator( mContainer1 ); mControl.Operator( mContainer2 ); } }
const S32 getElapsedMs() { if(mUsingPerfCounter) { // Use QPC, update remainders so we don't leak time, and return the elapsed time. QueryPerformanceCounter( (LARGE_INTEGER *) &mPerfCountNext); F64 elapsedF64 = (1000.0 * F64(mPerfCountNext - mPerfCountCurrent) / F64(mFrequency)); elapsedF64 += mPerfCountRemainderCurrent; U32 elapsed = (U32)mFloor(elapsedF64); mPerfCountRemainderNext = elapsedF64 - F64(elapsed); return elapsed; } else { // Do something naive with GTC. mTickCountNext = GetTickCount(); return mTickCountNext - mTickCountCurrent; } }
bool LightAnimData::AnimValue<COUNT>::animate(F32 time, F32 *output, bool multiply) { F32 scaledTime, lerpFactor, valueRange, keyFrameLerp; U32 posFrom, posTo; S32 keyFrameFrom, keyFrameTo; F32 initialValue = *output; if (!multiply) initialValue = 1; bool wasAnimated = false; for ( U32 i=0; i < COUNT; i++ ) { if ( mIsZero( timeScale[i] ) ) continue; wasAnimated = true; scaledTime = mFmod( time, period[i] ) * timeScale[i]; posFrom = mFloor( scaledTime ); posTo = mCeil( scaledTime ); keyFrameFrom = dToupper( keys[i][posFrom] ) - 65; keyFrameTo = dToupper( keys[i][posTo] ) - 65; valueRange = ( value2[i] - value1[i] ) / 25.0f; if ( !smooth[i] ) output[i] = (value1[i] + (keyFrameFrom * valueRange)) * initialValue; else { lerpFactor = scaledTime - posFrom; keyFrameLerp = ( keyFrameTo - keyFrameFrom ) * lerpFactor; output[i] = (value1[i] + ((keyFrameFrom + keyFrameLerp) * valueRange)) * initialValue; } } return wasAnimated; }
void ProjectedShadow::_calcScore( const SceneRenderState *state ) { if ( !mDecalInstance ) return; F32 pixRadius = mDecalInstance->calcPixelSize( state->getViewport().extent.y, state->getCameraPosition(), state->getWorldToScreenScale().y ); F32 pct = pixRadius / mDecalInstance->mDataBlock->fadeStartPixelSize; U32 msSinceLastRender = Platform::getVirtualMilliseconds() - getLastRenderTime(); ShapeBaseData *data = NULL; if ( mShapeBase ) data = static_cast<ShapeBaseData*>( mShapeBase->getDataBlock() ); // For every 1s this shadow hasn't been // updated we'll add 10 to the score. F32 secs = mFloor( (F32)msSinceLastRender / 1000.0f ); mScore = pct + secs; mClampF( mScore, 0.0f, 2000.0f ); }
void ClipMap::recenter(Point2F center) { bool wantCompleteRefill = false; if(mNeedRefill || mForceClipmapPurge || Con::getBoolVariable("$forceFullClipmapPurgeEveryFrame", false)) wantCompleteRefill = true; PROFILE_START(ClipMap_recenter); // Reset our budget. mMaxTexelUploadPerRecenter = mClipMapSize * mClipMapSize * 2; AssertFatal(isPow2(mClipMapSize), "ClipMap::recenter - require pow2 clipmap size!"); // Clamp the center to the unit square. /* if(!mTile) { center.x = mClampF(center.x, 0.f, 1.f); center.y = mClampF(center.y, 0.f, 1.f); } */ // Ok, we're going to do toroidal updates on each entry of the clipstack // (except for the cap, which covers the whole texture), based on this // new center point. if( !wantCompleteRefill ) { // Calculate the new texel at most detailed level. Point2F texelCenterF = center * F32(mClipMapSize) * mLevels[0].mScale; Point2I texelCenter((S32)mFloor(texelCenterF.y), (S32)mFloor(texelCenterF.x)); // Update interest region. mImageCache->setInterestCenter(texelCenter); } // Note how many we were at so we can cut off at the right time. S32 lastTexelsUpdated = mTexelsUpdated; // For each texture... for(S32 i=mClipStackDepth-2; i>=0; i--) { ClipStackEntry &cse = mLevels[i]; // Calculate new center point for this texture. Point2F texelCenterF = center * F32(mClipMapSize) * cse.mScale; const S32 texelMin = mClipMapSize/2; //const S32 texelMax = S32(F32(mClipMapSize) * cse.mScale) - texelMin; Point2I texelTopLeft; //if(mTile) //{ texelTopLeft.x = S32(mFloor(texelCenterF.y)) - texelMin; texelTopLeft.y = S32(mFloor(texelCenterF.x)) - texelMin; //} //else //{ // texelTopLeft.x = mClamp(S32(mFloor(texelCenterF.y)), texelMin, texelMax) - texelMin; // texelTopLeft.y = mClamp(S32(mFloor(texelCenterF.x)), texelMin, texelMax) - texelMin; //} // Also, prevent very small updates - the RT changes are costly. Point2I d = cse.mToroidalOffset - texelTopLeft; if(mAbs(d.x) <= 2 && mAbs(d.y) <= 2) { // Update the center; otherwise we get some weird conditions around // edges of the clipmap space. cse.mClipCenter = center; continue; } // This + current toroid offset tells us what regions have to be blasted. RectI oldData(cse.mToroidalOffset, Point2I(mClipMapSize, mClipMapSize)); RectI newData(texelTopLeft, Point2I(mClipMapSize, mClipMapSize)); // Update clipstack level. cse.mClipCenter = center; cse.mToroidalOffset = texelTopLeft; // If we're refilling, that's all we want; continue with next level. if( wantCompleteRefill ) continue; // Make sure we have available data... if(!mImageCache->isDataAvailable(getMipLevel(cse.mScale), newData)) continue; // Alright, determine the set of data we actually need to upload. S32 rectCount = 0; RectI buffer[8]; calculateModuloDeltaBounds(oldData, newData, buffer, &rectCount); AssertFatal(rectCount < 8, "ClipMap::recenter - got too many rects back!"); /*if(rectCount) Con::printf(" issuing %d updates to clipmap level %d (offset=%dx%d)", rectCount, i, texelTopLeft.x, texelTopLeft.y); */ if(rectCount) { if (!mImageCache->beginRectUpdates(cse)) { mForceClipmapPurge = true; return; } //Con::errorf("layer %x, %d updates", &cse, rectCount); // And GO! for(S32 j=0; j<rectCount; j++) { PROFILE_START(ClipMap_recenter_upload); AssertFatal(buffer[j].isValidRect(),"ClipMap::recenter - got invalid rect!"); // Note the rect, so we can then wrap and let the image cache do its thing. RectI srcRegion = buffer[j]; buffer[j].point.x = srcRegion.point.x % mClipMapSize; buffer[j].point.y = srcRegion.point.y % mClipMapSize; AssertFatal(newData.contains(srcRegion), "ClipMap::recenter - got update buffer outside of expected new data bounds."); mTotalUpdates++; mTexelsUpdated += srcRegion.extent.x * srcRegion.extent.y; //Con::printf("updating (%d %d %d %d)", // buffer[j].point.x, buffer[j].point.y, buffer[j].extent.x, buffer[j].extent.y); mImageCache->doRectUpdate(getMipLevel(cse.mScale), cse, srcRegion, buffer[j]); PROFILE_END(); } mImageCache->finishRectUpdates(cse); } // Check if we've overrun our budget. if((mTexelsUpdated - lastTexelsUpdated) > mMaxTexelUploadPerRecenter) { //Con::warnf("ClipMap::recenter - exceeded budget for this frame, deferring till next frame."); break; } } if( wantCompleteRefill ) { fillWithTextureData(); mNeedRefill = false; } PROFILE_END(); }
void TransformTool::renderTool() { if (!mActive) return; // Grid { Point3F editorPos = mEditorManager->mEditorCamera.getWorldPosition(); editorPos = editorPos / 10.0f; editorPos.x = mFloor(editorPos.x); editorPos.y = mFloor(editorPos.y); editorPos = editorPos * 10.0f; Torque::Debug.ddPush(); Torque::Debug.ddSetState(true, false, true); Torque::Debug.ddSetWireframe(true); Torque::Debug.ddSetColor(BGFXCOLOR_RGBA(255, 255, 255, 255)); F32 gridNormal[3] = { 0.0f, 0.0f, 1.0f }; F32 gridPos[3] = { editorPos.x, editorPos.y, -0.01f }; Torque::Debug.ddDrawGrid(gridNormal, gridPos, 100, 10.0f); } // Draw Light Icons /*if (mLightIcon != NULL) { Vector<Lighting::LightData*> lightList = Torque::Lighting.getLightList(); for (S32 n = 0; n < lightList.size(); ++n) { Lighting::LightData* light = lightList[n]; Torque::Graphics.drawBillboard(mEditorManager->mRenderLayer4View->id, mLightIcon, light->position, 1.0f, 1.0f, ColorI(light->color[0] * 255, light->color[1] * 255, light->color[2] * 255, 255), NULL); } }*/ if (mMultiselect) { Box3F multiSelectBox; multiSelectBox.set(Point3F(0, 0, 0)); for (S32 n = 0; n < mSelectedObjects.size(); ++n) { Scene::SceneObject* obj = dynamic_cast<Scene::SceneObject*>(mSelectedObjects[n]); if (obj) { if (n == 0) multiSelectBox = obj->mBoundingBox; else multiSelectBox.intersect(obj->mBoundingBox); } Scene::BaseComponent* component = dynamic_cast<Scene::BaseComponent*>(mSelectedObjects[n]); if (component) { Box3F boundingBox = component->getBoundingBox(); boundingBox.transform(component->mTransform.matrix); if (n == 0) multiSelectBox = boundingBox; else multiSelectBox.intersect(boundingBox); } } mSelectionBounds = true; mSelectionBoundsStart = multiSelectBox.minExtents; mSelectionBoundsEnd = multiSelectBox.maxExtents; } // Object Selected if (mSelectedObject != NULL && mSelectedComponent == NULL) { mSelectionBounds = true; mSelectionBoundsStart = mSelectedObject->mBoundingBox.minExtents; mSelectionBoundsEnd = mSelectedObject->mBoundingBox.maxExtents; } // Component Selected if (mSelectedObject != NULL && mSelectedComponent != NULL) { Box3F boundingBox = mSelectedComponent->getBoundingBox(); boundingBox.transform(mSelectedObject->mTransform.matrix); mSelectionBounds = true; mSelectionBoundsStart = boundingBox.minExtents; mSelectionBoundsEnd = boundingBox.maxExtents; } // Selection Bounding Box if (mSelectionBounds) { Aabb debugBox; debugBox.m_min[0] = mSelectionBoundsStart.x; debugBox.m_min[1] = mSelectionBoundsStart.y; debugBox.m_min[2] = mSelectionBoundsStart.z; debugBox.m_max[0] = mSelectionBoundsEnd.x; debugBox.m_max[1] = mSelectionBoundsEnd.y; debugBox.m_max[2] = mSelectionBoundsEnd.z; Torque::Debug.ddSetWireframe(true); Torque::Debug.ddSetColor(BGFXCOLOR_RGBA(mSelectionBoundsColor.red, mSelectionBoundsColor.green, mSelectionBoundsColor.blue, mSelectionBoundsColor.alpha)); Torque::Debug.ddDrawAabb(debugBox); Torque::Debug.ddPop(); } // Gizmo mGizmo.render(); // Debug if (mDebugWorldRay) { Torque::Debug.ddMoveTo(mLastRayStart.x, mLastRayStart.y, mLastRayStart.z); Torque::Debug.ddLineTo(mLastRayEnd.x, mLastRayEnd.y, mLastRayEnd.z); } if (mDebugBoxSelection) { for (U32 i = 0; i < 4; ++i) { Torque::Debug.ddMoveTo(mBoxNearPoint.x, mBoxNearPoint.y, mBoxNearPoint.z); Torque::Debug.ddLineTo(mBoxFarPoint[i].x, mBoxFarPoint[i].y, mBoxFarPoint[i].z); } } }
//----------------------------------------------------------------------------- void CameraSpline::value(F32 t, CameraSpline::Knot *result, bool skip_rotation) { // Do some easing in and out for t. if(!gBuilding) { F32 oldT = t; if(oldT < 0.5f) { t = 0.5f - (mSin( (0.5 - oldT) * M_PI ) / 2.f); } if((F32(size()) - 1.5f) > 0.f && oldT - (F32(size()) - 1.5f) > 0.f) { oldT -= (F32(size()) - 1.5f); t = (F32(size()) - 1.5f) + (mCos( (0.5f - oldT) * F32(M_PI) ) / 2.f); } } // Verify that t is in range [0 >= t > size] // AssertFatal(t >= 0.0f && t < (F32)size(), "t out of range"); Knot *p1 = getKnot((S32)mFloor(t)); Knot *p2 = next(p1); F32 i = t - mFloor(t); // adjust t to 0 to 1 on p1-p2 interval if (p1->mPath == Knot::SPLINE) { Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1); Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2); result->mPosition.x = mCatmullrom(i, p0->mPosition.x, p1->mPosition.x, p2->mPosition.x, p3->mPosition.x); result->mPosition.y = mCatmullrom(i, p0->mPosition.y, p1->mPosition.y, p2->mPosition.y, p3->mPosition.y); result->mPosition.z = mCatmullrom(i, p0->mPosition.z, p1->mPosition.z, p2->mPosition.z, p3->mPosition.z); } else { // Linear result->mPosition.interpolate(p1->mPosition, p2->mPosition, i); } if (skip_rotation) return; buildTimeMap(); // find the two knots to interpolate rotation and velocity through since some // knots are only positional S32 start = (S32)mFloor(t); S32 end = (p2 == p1) ? start : (start + 1); while (p1->mType == Knot::POSITION_ONLY && p1 != front()) { p1 = prev(p1); start--; } while (p2->mType == Knot::POSITION_ONLY && p2 != back()) { p2 = next(p2); end++; } if (start == end) { result->mRotation = p1->mRotation; result->mSpeed = p1->mSpeed; } else { F32 c = getDistance(t); F32 d1 = getDistance((F32)start); F32 d2 = getDistance((F32)end); if (d1 == d2) { result->mRotation = p2->mRotation; result->mSpeed = p2->mSpeed; } else { i = (c-d1)/(d2-d1); if(p1->mPath == Knot::SPLINE) { Knot *p0 = (p1->mType == Knot::KINK) ? p1 : prev(p1); Knot *p3 = (p2->mType == Knot::KINK) ? p2 : next(p2); F32 q,w,e; q = mCatmullrom(i, 0, 1, 1, 1); w = mCatmullrom(i, 0, 0, 0, 1); e = mCatmullrom(i, 0, 0, 1, 1); QuatF a; a.interpolate(p0->mRotation, p1->mRotation, q); QuatF b; b.interpolate(p2->mRotation, p3->mRotation, w); result->mRotation.interpolate(a, b, e); result->mSpeed = mCatmullrom(i, p0->mSpeed, p1->mSpeed, p2->mSpeed, p3->mSpeed); } else { result->mRotation.interpolate(p1->mRotation, p2->mRotation, i); result->mSpeed = (p1->mSpeed * (1.0f-i)) + (p2->mSpeed * i); } } } }
bool GFXGLShader::_init() { // Don't initialize empty shaders. if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() ) return false; clearShaders(); mProgram = glCreateProgram(); // Set the macros and add the global ones. Vector<GFXShaderMacro> macros; macros.merge( mMacros ); macros.merge( smGlobalMacros ); // Add the shader version to the macros. const U32 mjVer = (U32)mFloor( mPixVersion ); const U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f ); macros.increment(); macros.last().name = "TORQUE_SM"; macros.last().value = String::ToString( mjVer * 10 + mnVer ); // Default to true so we're "successful" if a vertex/pixel shader wasn't specified. bool compiledVertexShader = true; bool compiledPixelShader = true; // Compile the vertex and pixel shaders if specified. if(!mVertexFile.isEmpty()) compiledVertexShader = initShader(mVertexFile, true, macros); if(!mPixelFile.isEmpty()) compiledPixelShader = initShader(mPixelFile, false, macros); // If either shader was present and failed to compile, bail. if(!compiledVertexShader || !compiledPixelShader) return false; // Link it! glLinkProgram( mProgram ); GLint linkStatus; glGetProgramiv( mProgram, GL_LINK_STATUS, &linkStatus ); // Dump the info log to the console U32 logLength = 0; glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, (GLint*)&logLength); if ( logLength ) { FrameAllocatorMarker fam; char* log = (char*)fam.alloc( logLength ); glGetProgramInfoLog( mProgram, logLength, NULL, log ); if ( linkStatus == GL_FALSE ) { if ( smLogErrors ) { Con::errorf( "GFXGLShader::init - Error linking shader!" ); Con::errorf( "Program %s / %s: %s", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); } } else if ( smLogWarnings ) { Con::warnf( "Program %s / %s: %s", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); } } // If we failed to link, bail. if ( linkStatus == GL_FALSE ) return false; initConstantDescs(); initHandles(); // Notify Buffers we might have changed in size. // If this was our first init then we won't have any activeBuffers // to worry about unnecessarily calling. Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin(); for ( ; biter != mActiveBuffers.end(); biter++ ) ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload( this ); return true; }
void LeapMotionFrame::copyFromFramePointables(const Leap::PointableList& pointables) { // Set up Vectors mPointableValid.increment(mPointableCount); mPointableId.increment(mPointableCount); mPointableHandIndex.increment(mPointableCount); mPointableType.increment(mPointableCount); mPointableRawPos.increment(mPointableCount); mPointablePos.increment(mPointableCount); mPointableRot.increment(mPointableCount); mPointableRotQuat.increment(mPointableCount); mPointableLength.increment(mPointableCount); mPointableWidth.increment(mPointableCount); // Copy data for(U32 i=0; i<mPointableCount; ++i) { const Leap::Pointable& pointable = pointables[i]; mPointableValid[i] = pointable.isValid(); mPointableId[i] = pointable.id(); mPointableLength[i] = pointable.length(); mPointableWidth[i] = pointable.width(); mPointableType[i] = PT_UNKNOWN; if(pointable.isFinger()) { mPointableType[i] = PT_FINGER; } else if(pointable.isTool()) { mPointableType[i] = PT_TOOL; } // Which hand, if any const Leap::Hand& hand = pointable.hand(); if(hand.isValid()) { bool found = false; S32 handId = hand.id(); for(U32 j=0; j<mHandCount; ++j) { if(mHandId[j] == handId) { mPointableHandIndex[i] = j; found = true; break; } } if(!found) { mPointableHandIndex[i] = -1; } } else { mPointableHandIndex[i] = -1; } // Position LeapMotionUtil::convertPosition(pointable.tipPosition(), mPointableRawPos[i]); mPointablePos[i].x = (S32)mFloor(mPointableRawPos[i].x); mPointablePos[i].y = (S32)mFloor(mPointableRawPos[i].y); mPointablePos[i].z = (S32)mFloor(mPointableRawPos[i].z); // Rotation LeapMotionUtil::convertPointableRotation(pointable, mPointableRot[i]); mPointableRotQuat[i].set(mPointableRot[i]); } }
bool ClipMap::fillWithTextureData() { PROFILE_SCOPE(ClipMap_fillWithTextureData); mForceClipmapPurge = false; // Note our interest for the cache. { // Calculate the new texel at most detailed level. Point2F texelCenterF = mLevels[0].mClipCenter * F32(mClipMapSize) * mLevels[0].mScale; Point2I texelCenter((S32)mFloor(texelCenterF.y), (S32)mFloor(texelCenterF.x)); // Update interest region. mImageCache->setInterestCenter(texelCenter); } // First generate our desired rects for each level. FrameTemp< RectI > desiredData( mClipStackDepth ); for(S32 i=0; i<mClipStackDepth; i++) { ClipStackEntry &cse = mLevels[i]; // Calculate new center point for this texture. Point2F texelCenterF = cse.mClipCenter * F32(mClipMapSize) * cse.mScale; const S32 texelMin = mClipMapSize/2; //const S32 texelMax = S32(F32(mClipMapSize) * cse.mScale) - texelMin; Point2I texelTopLeft; //if(mTile) //{ texelTopLeft.x = S32(mFloor(texelCenterF.y)) - texelMin; texelTopLeft.y = S32(mFloor(texelCenterF.x)) - texelMin; //} //else //{ // texelTopLeft.x = mClamp(S32(mFloor(texelCenterF.y)), texelMin, texelMax) - texelMin; // texelTopLeft.y = mClamp(S32(mFloor(texelCenterF.x)), texelMin, texelMax) - texelMin; //} desiredData[i] = RectI(texelTopLeft, Point2I(mClipMapSize, mClipMapSize)); // Make sure we have available data... if(!mImageCache->isDataAvailable(getMipLevel(cse.mScale), desiredData[i])) return false; } // Upload all the textures... for(S32 i=0; i<mClipStackDepth; i++) { ClipStackEntry &cse = mLevels[i]; RectI buffer[8]; S32 rectCount = 0; clipAgainstGrid(mClipMapSize, desiredData[i], &rectCount, buffer); AssertFatal(rectCount < 8, "ClipMap::fillWithTextureData - got too many rects back!"); if(rectCount) { if (!mImageCache->beginRectUpdates(cse)) { mForceClipmapPurge = true; return false; } for(S32 j=0; j<rectCount; j++) { RectI srcRegion = buffer[j]; buffer[j].point.x = srcRegion.point.x % mClipMapSize; buffer[j].point.y = srcRegion.point.y % mClipMapSize; mImageCache->doRectUpdate(getMipLevel(cse.mScale), cse, srcRegion, buffer[j]); } mImageCache->finishRectUpdates(cse); } cse.mToroidalOffset = desiredData[i].point; } GRAPHIC->disableShaders(); // Success! return true; }
void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused ) { StringBuffer textBuffer; Point2I drawPoint = drawRect.point; Point2I paddingLeftTop, paddingRightBottom; // Or else just copy it over. char *renderText = Con::getReturnBuffer( GuiTextEditCtrl::MAX_STRING_LENGTH ); getRenderText( renderText ); // Apply password masking (make the masking char optional perhaps?) if(mPasswordText) { const U32 renderLen = dStrlen( renderText ); for( U32 i = 0; i < renderLen; i++ ) textBuffer.append(mPasswordMask); } else { textBuffer.set( renderText ); } // Just a little sanity. if(mCursorPos > textBuffer.length()) mCursorPos = textBuffer.length(); paddingLeftTop.set(( mProfile->mTextOffset.x != 0 ? mProfile->mTextOffset.x : 3 ), mProfile->mTextOffset.y); paddingRightBottom = paddingLeftTop; // Center vertically: drawPoint.y += ( ( drawRect.extent.y - paddingLeftTop.y - paddingRightBottom.y - S32( mProfile->mFont->getHeight() ) ) / 2 ) + paddingLeftTop.y; // Align horizontally: S32 textWidth = mProfile->mFont->getStrNWidth(textBuffer.getPtr(), textBuffer.length()); switch( mProfile->mAlignment ) { case GuiControlProfile::RightJustify: drawPoint.x += ( drawRect.extent.x - textWidth - paddingRightBottom.x ); break; case GuiControlProfile::CenterJustify: drawPoint.x += ( ( drawRect.extent.x - textWidth ) / 2 ); break; default: case GuiControlProfile::LeftJustify : drawPoint.x += paddingLeftTop.x; break; } ColorI fontColor = mActive ? mProfile->mFontColor : mProfile->mFontColorNA; // now draw the text Point2I cursorStart, cursorEnd; mTextOffset.y = drawPoint.y; mTextOffset.x = drawPoint.x; if ( drawRect.extent.x - paddingLeftTop.x > textWidth ) mTextOffset.x = drawPoint.x; else { // Alignment affects large text if ( mProfile->mAlignment == GuiControlProfile::RightJustify || mProfile->mAlignment == GuiControlProfile::CenterJustify ) { if ( mTextOffset.x + textWidth < (drawRect.point.x + drawRect.extent.x) - paddingRightBottom.x) mTextOffset.x = (drawRect.point.x + drawRect.extent.x) - paddingRightBottom.x - textWidth; } } // calculate the cursor if( isFocused && mActive ) { // Where in the string are we? S32 cursorOffset=0, charWidth=0; UTF16 tempChar = textBuffer.getChar(mCursorPos); // Alright, we want to terminate things momentarily. if(mCursorPos > 0) { cursorOffset = mProfile->mFont->getStrNWidth(textBuffer.getPtr(), mCursorPos); } else cursorOffset = 0; if( tempChar && mProfile->mFont->isValidChar( tempChar ) ) charWidth = mProfile->mFont->getCharWidth( tempChar ); else charWidth = paddingRightBottom.x; if( mTextOffset.x + cursorOffset + 1 >= (drawRect.point.x + drawRect.extent.x) ) // +1 is for the cursor width { // Cursor somewhere beyond the textcontrol, // skip forward roughly 25% of the total width (if possible) S32 skipForward = drawRect.extent.x / 4 * 3; if ( cursorOffset + skipForward > textWidth ) mTextOffset.x = (drawRect.point.x + drawRect.extent.x) - paddingRightBottom.x - textWidth; else { //mTextOffset.x -= skipForward; S32 mul = (S32)( mFloor( (cursorOffset-drawRect.extent.x) / skipForward ) ); mTextOffset.x -= skipForward * mul + drawRect.extent.x - 1; // -1 is for the cursor width } } else if( mTextOffset.x + cursorOffset < drawRect.point.x + paddingLeftTop.x ) { // Cursor somewhere before the textcontrol // skip backward roughly 25% of the total width (if possible) S32 skipBackward = drawRect.extent.x / 4 * 3; if ( cursorOffset - skipBackward < 0 ) mTextOffset.x = drawRect.point.x + paddingLeftTop.x; else { S32 mul = (S32)( mFloor( cursorOffset / skipBackward ) ); mTextOffset.x += drawRect.point.x - mTextOffset.x - skipBackward * mul; } } cursorStart.x = mTextOffset.x + cursorOffset; #ifdef TORQUE_OS_MAC cursorStart.x += charWidth/2; #endif cursorEnd.x = cursorStart.x; S32 cursorHeight = mProfile->mFont->getHeight(); if ( cursorHeight < drawRect.extent.y ) { cursorStart.y = drawPoint.y; cursorEnd.y = cursorStart.y + cursorHeight; } else { cursorStart.y = drawRect.point.y; cursorEnd.y = cursorStart.y + drawRect.extent.y; } } //draw the text if ( !isFocused ) mBlockStart = mBlockEnd = 0; //also verify the block start/end if ((mBlockStart > textBuffer.length() || (mBlockEnd > textBuffer.length()) || (mBlockStart > mBlockEnd))) mBlockStart = mBlockEnd = 0; Point2I tempOffset = mTextOffset; //draw the portion before the highlight if ( mBlockStart > 0 ) { GFX->getDrawUtil()->setBitmapModulation( fontColor ); const UTF16* preString2 = textBuffer.getPtr(); GFX->getDrawUtil()->drawText( mProfile->mFont, tempOffset, preString2, mProfile->mFontColors ); tempOffset.x += mProfile->mFont->getStrNWidth(preString2, mBlockStart); } //draw the highlighted portion if ( mBlockEnd > 0 ) { const UTF16* highlightBuff = textBuffer.getPtr() + mBlockStart; U32 highlightBuffLen = mBlockEnd-mBlockStart; S32 highlightWidth = mProfile->mFont->getStrNWidth(highlightBuff, highlightBuffLen); GFX->getDrawUtil()->drawRectFill( Point2I( tempOffset.x, drawRect.point.y ), Point2I( tempOffset.x + highlightWidth, drawRect.point.y + drawRect.extent.y - 1), mProfile->mFontColorSEL ); GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColorHL ); GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, highlightBuff, highlightBuffLen, mProfile->mFontColors ); tempOffset.x += highlightWidth; } //draw the portion after the highlight if(mBlockEnd < textBuffer.length()) { const UTF16* finalBuff = textBuffer.getPtr() + mBlockEnd; U32 finalBuffLen = textBuffer.length() - mBlockEnd; GFX->getDrawUtil()->setBitmapModulation( fontColor ); GFX->getDrawUtil()->drawTextN( mProfile->mFont, tempOffset, finalBuff, finalBuffLen, mProfile->mFontColors ); } //draw the cursor if ( isFocused && mCursorOn ) GFX->getDrawUtil()->drawLine( cursorStart, cursorEnd, mProfile->mCursorColor ); }
bool GFXGLShader::_init() { PROFILE_SCOPE(GFXGLShader_Init); // Don't initialize empty shaders. if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() ) return false; clearShaders(); mProgram = glCreateProgram(); // Set the macros and add the global ones. Vector<GFXShaderMacro> macros; macros.merge( mMacros ); macros.merge( smGlobalMacros ); // Add the shader version to the macros. const U32 mjVer = (U32)mFloor( mPixVersion ); const U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f ); macros.increment(); macros.last().name = "TORQUE_SM"; macros.last().value = String::ToString( mjVer * 10 + mnVer ); macros.increment(); macros.last().name = "TORQUE_VERTEX_SHADER"; macros.last().value = ""; // Default to true so we're "successful" if a vertex/pixel shader wasn't specified. bool compiledVertexShader = true; bool compiledPixelShader = true; // Compile the vertex and pixel shaders if specified. if(!mVertexFile.isEmpty()) compiledVertexShader = initShader(mVertexFile, true, macros); macros.last().name = "TORQUE_PIXEL_SHADER"; if(!mPixelFile.isEmpty()) compiledPixelShader = initShader(mPixelFile, false, macros); // If either shader was present and failed to compile, bail. if(!compiledVertexShader || !compiledPixelShader) return false; //bind vertex attributes glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Position, "vPosition"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Normal, "vNormal"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Color, "vColor"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Tangent, "vTangent"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TangentW, "vTangentW"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Binormal, "vBinormal"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord0, "vTexCoord0"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord1, "vTexCoord1"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord2, "vTexCoord2"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord3, "vTexCoord3"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord4, "vTexCoord4"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord5, "vTexCoord5"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord6, "vTexCoord6"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord7, "vTexCoord7"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord8, "vTexCoord8"); glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord9, "vTexCoord9"); //bind fragment out color glBindFragDataLocation(mProgram, 0, "OUT_col"); glBindFragDataLocation(mProgram, 1, "OUT_col1"); glBindFragDataLocation(mProgram, 2, "OUT_col2"); glBindFragDataLocation(mProgram, 3, "OUT_col3"); // Link it! glLinkProgram( mProgram ); GLint linkStatus; glGetProgramiv( mProgram, GL_LINK_STATUS, &linkStatus ); // Dump the info log to the console U32 logLength = 0; glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, (GLint*)&logLength); if ( logLength ) { FrameAllocatorMarker fam; char* log = (char*)fam.alloc( logLength ); glGetProgramInfoLog( mProgram, logLength, NULL, log ); if ( linkStatus == GL_FALSE ) { if ( smLogErrors ) { Con::errorf( "GFXGLShader::init - Error linking shader!" ); Con::errorf( "Program %s / %s: %s", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); } } else if ( smLogWarnings ) { Con::warnf( "Program %s / %s: %s", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); } } // If we failed to link, bail. if ( linkStatus == GL_FALSE ) return false; initConstantDescs(); initHandles(); // Notify Buffers we might have changed in size. // If this was our first init then we won't have any activeBuffers // to worry about unnecessarily calling. Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin(); for ( ; biter != mActiveBuffers.end(); biter++ ) ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload( this ); return true; }