vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
	vec4 orig = Texel(texture,texture_coords);

	vec2 coordinatecompressedlocation = vec2(textureoffset % 512, (textureoffset - (textureoffset % 512)) / 512) / 512.0; // Transision from 1d space to 2d space
	vec4 coordinatecompresed = Texel(posbuffer,coordinatecompressedlocation); // Get the screen location data
	vec2 coordinate = vec2(coordinatecompresed.r * 255.0 + (coordinatecompresed.g * 255.0 * 255.0), 
		coordinatecompresed.b * 255.0 + (coordinatecompresed.a * 255.0 * 255.0)); // Change 4 bytes to 2 shorts

	vec4 point = Texel(shadowbuffer,coordinate/textureSize2D(shadowbuffer,0)); // Sample the shadowmap

	if (point.r < 0.1)
	{
		point.r = 0.0;point.g = 0.0;point.b = 0.0;
	}
	else
	{
		point.r = 1.0;point.g = 1.0;point.b = 1.0;
	}
	
	if (orig.a > 0.0)
	{
		orig.a = 1.0;
	}

	
	orig.a *= point.r;
	
	return orig*color;
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
	vec4 orig = Texel(texture,texture_coords);
	vec4 point = Texel(shadowbuffer,pos/textureSize2D(shadowbuffer,0));
	
	if (type46 && orig.a > 0.0 && orig.a < 1.0)
	{
		float id = orig.a * 255.0;
		if(id < 12.0)
		{
			// Unknown use
		}
		else if(id > 12.0 && id < 28.0)
		{
			orig.rgb = Color1.rgb * (orig.r /  32.0);
		}
		else if(id > 28.0 && id < 44.0)
		{
			orig.rgb = Color2.rgb * (orig.r  / 32.0);
		}
		else if(id > 44.0 && id < 66.0f)
		{
			orig.rgb = Color3.rgb * (orig.r  / 32.0);
		}
		else if(id > 66.0 && id < 76.0)
		{
			orig.rgb = Color4.rgb * (orig.r  / 32.0);
		}
		else if(id > 76.0 && id < 92.0)
		{
			orig.rgb = Color5.rgb * (orig.r  / 32.0);
		}
		else	
		{
			orig.rgb = Color6.rgb * (orig.r  / 32.0);
		}
		orig.a = 1.0;
	}
	
	if (wall)
	{
		if (point.r < 0.1)
		{
			point.r = 0.0;point.g = 0.0;point.b = 0.0;
		}
		else
		{
			point.r = 1.0;point.g = 1.0;point.b = 1.0;
		}
	}
	
	if (orig.a > 0.0)
	{
		orig.a = 1.0;
	}
	
	orig.a *= point.r;
	
	return orig*color;
}
Exemple #3
0
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
	vec2 pSize = vec2(1.0 / screen.x, 1.0 / screen.y);
	vec4 col = Texel(texture, texture_coords);
	for(int i = 1; i <= steps; i++) {
		col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y - pSize.y * i));
		col = col + Texel(texture, vec2(texture_coords.x, texture_coords.y + pSize.y * i));
	}
	col = col / (steps * 2.0 + 1.0);
	return vec4(col.r, col.g, col.b, 1.0);
}
Exemple #4
0
void CNormalGenerator::GeneratePass(int x, int y)
{
	// Generate the low/mid pass values from a fast gaussian filter.
	static const float flWeightTable[11][11] = {
		{ 0.004f, 0.004f, 0.005f, 0.005f, 0.005f, 0.005f, 0.005f, 0.005f, 0.005f, 0.004f, 0.004f },
		{ 0.004f, 0.005f, 0.005f, 0.006f, 0.007f, 0.007f, 0.007f, 0.006f, 0.005f, 0.005f, 0.004f },
		{ 0.005f, 0.005f, 0.006f, 0.008f, 0.009f, 0.009f, 0.009f, 0.008f, 0.006f, 0.005f, 0.005f },
		{ 0.005f, 0.006f, 0.008f, 0.010f, 0.012f, 0.014f, 0.012f, 0.010f, 0.008f, 0.006f, 0.005f },
		{ 0.005f, 0.007f, 0.009f, 0.012f, 0.019f, 0.027f, 0.019f, 0.012f, 0.009f, 0.007f, 0.005f },
		{ 0.005f, 0.007f, 0.009f, 0.014f, 0.027f, 0.054f, 0.027f, 0.014f, 0.009f, 0.007f, 0.005f },
		{ 0.005f, 0.007f, 0.009f, 0.012f, 0.019f, 0.027f, 0.019f, 0.012f, 0.009f, 0.007f, 0.005f },
		{ 0.005f, 0.006f, 0.008f, 0.010f, 0.012f, 0.014f, 0.012f, 0.010f, 0.008f, 0.006f, 0.005f },
		{ 0.005f, 0.005f, 0.006f, 0.008f, 0.009f, 0.009f, 0.009f, 0.008f, 0.006f, 0.005f, 0.005f },
		{ 0.004f, 0.005f, 0.005f, 0.006f, 0.007f, 0.007f, 0.007f, 0.006f, 0.005f, 0.005f, 0.004f },
		{ 0.004f, 0.004f, 0.005f, 0.005f, 0.005f, 0.005f, 0.005f, 0.005f, 0.005f, 0.004f, 0.004f },
	};

	float flLowHeight = 0;
	float flTotalLowHeight = 0;
	float flMidHeight = 0;
	float flTotalMidHeight = 0;

	for (int i = -10; i <= 10; i++)
	{
		for (int j = -10; j <= 10; j++)
		{
			size_t iTexel2;
			if (Texel(x+i, y+j, iTexel2, m_iNormal2Width, m_iNormal2Height))
			{
				size_t iTexelOffset = iTexel2;
				float flWeight = flWeightTable[(i/2)+5][(j/2)+5];
				flLowHeight += m_avecTextureTexels[iTexelOffset].Average() * flWeight;
				flTotalLowHeight += flWeight;

				if (i >= -5 && i <= 5 && j >= -5 && j <= 5)
				{
					flWeight = flWeightTable[i+5][j+5];
					flMidHeight += m_avecTextureTexels[iTexelOffset].Average() * flWeight;
					flTotalMidHeight += flWeight;
				}
			}
		}
	}

	size_t iTexel;
	Texel(x, y, iTexel, m_iNormal2Width, m_iNormal2Height);

	m_aflLowPassTexels[iTexel] = flLowHeight/flTotalLowHeight;
	m_aflMidPassTexels[iTexel] = flMidHeight/flTotalMidHeight;
}
Exemple #5
0
		static void call(textureType & Texture, typename convert<textureType, T, P>::writeFunc Write, tvec4<T, P> const & Color)
		{
			assert(Write);

			texture const ConvertTexel(Texture.target(), Texture.format(), texture::texelcoord_type(1), 1, 1, 1);
			textureType Texel(ConvertTexel);
			Write(Texel, typename textureType::texelcoord_type(0), 0, 0, 0, Color);

			size_t const BlockSize(block_size(Texture.format()));
			for(size_t BlockIndex = 0, BlockCount = Texture.size() / BlockSize; BlockIndex < BlockCount; ++BlockIndex)
				memcpy(static_cast<std::uint8_t*>(Texture.data()) + BlockSize * BlockIndex, Texel.data(), BlockSize);
		}
		static texel_type call(texture_type const & Texture, fetch_type Fetch, samplecoord_type const & SampleCoordWrap, size_type Layer, size_type Face, interpolate_type Level, texel_type const & BorderColor)
		{
			size_type const LevelIndex = static_cast<size_type>(Level);
			texelcoord_type const TexelDim(Texture.dimensions(LevelIndex));
			samplecoord_type const TexelLast(samplecoord_type(TexelDim) - samplecoord_type(1));
			texelcoord_type const TexelCoord = texelcoord_type(round(SampleCoordWrap * TexelLast));
			typename texelcoord_type::bool_type const UseTexelCoord = in_interval(TexelCoord, texelcoord_type(0), TexelDim - 1);

			texel_type Texel(BorderColor);
			if(all(UseTexelCoord))
				Texel = Fetch(Texture, TexelCoord, Layer, Face, LevelIndex);

			return Texel;
		}
vec4 effect(vec4 vcolor, Image texture, vec2 texcoord, vec2 pixel_coords)
{	
	vec4 input0 = Texel(texture, texcoord);
		
	//exposure knee	
	input0 *= (exp2(input0)*vec4(exposure));
	
	vec4 lumacomponents = vec4(lumcoeff * lumacomponents, 0.0 );
	
	float luminance = dot(input0,lumacomponents);
	
	vec4 luma = vec4(luminance);

	return vec4(luma.rgb * brightness, 1.0);
} 
Exemple #8
0
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
{
	vec4 c = Texel(texture,texture_coords);
	
	if (c.a > 0.0001 && c.a < 0.9999)
	{
		float id = c.a * 255.0;
		if(id < 12.0)
		{
			 // Unknown use
		}
		else if(id > 12.0 && id < 28.0)
		{
			c.rgb = Color1.rgb * (c.r  / 32.0);
		}
		else if(id > 28.0 && id < 44.0)
		{
			c.rgb = Color2.rgb * (c.r  / 32.0);
		}
		else if(id > 44.0 && id < 66.0f)
		{
			c.rgb = Color3.rgb * (c.r  / 32.0);
		}
		else if(id > 66.0 && id < 76.0)
		{
			c.rgb = Color4.rgb * (c.r  / 32.0);
		}
		else if(id > 76.0 && id < 92.0)
		{
			c.rgb = Color5.rgb * (c.r  / 32.0);
		}
		else	
		{
			c.rgb = Color6.rgb * (c.r  / 32.0);
		}
		c.a = 1.0;
	}
	
	return c;
}
Exemple #9
0
void CAOGenerator::Bleed()
{
    bool* abPixelMask = (bool*)malloc(m_iWidth*m_iHeight*sizeof(bool));

    m_pWorkListener->SetAction("Bleeding edges", m_iBleed);

    for (size_t i = 0; i < m_iBleed; i++)
    {
        // This is for pixels that have been set this frame.
        memset(&abPixelMask[0], 0, m_iWidth*m_iHeight*sizeof(bool));

        for (size_t w = 0; w < m_iWidth; w++)
        {
            for (size_t h = 0; h < m_iHeight; h++)
            {
                Vector vecTotal(0,0,0);
                size_t iTotal = 0;
                size_t iTexel;

                // If the texel has the mask on then it already has a value so skip it.
                if (Texel(w, h, iTexel, true))
                    continue;

                if (Texel(w-1, h-1, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w-1, h, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w-1, h+1, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w, h+1, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w+1, h+1, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w+1, h, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w+1, h-1, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                if (Texel(w, h-1, iTexel))
                {
                    vecTotal += m_avecShadowValues[iTexel];
                    iTotal++;
                }

                Texel(w, h, iTexel, false);

                if (iTotal)
                {
                    vecTotal /= (float)iTotal;
                    m_avecShadowValues[iTexel] = vecTotal;
                    abPixelMask[iTexel] = true;
                }
            }
        }

        for (size_t p = 0; p < m_iWidth*m_iHeight; p++)
            m_bPixelMask[p] |= abPixelMask[p];

        m_pWorkListener->WorkProgress(i);

        if (m_bStopGenerating)
            break;
    }

    free(abPixelMask);
}
Exemple #10
0
vec4 checkTexelBounds(Image texture, vec2 coords, vec2 bounds)
{
	vec2 ss = step(coords, vec2(bounds.x, 1.0)) * step(vec2(0.0, bounds.y), coords);
	return Texel(texture, coords) * ss.x * ss.y;
}
Exemple #11
0
bool CTexelGenerator::Texel(size_t w, size_t h, size_t& iTexel, bool bUseMask)
{
	return Texel(w, h, iTexel, m_iWidth, m_iHeight, bUseMask?m_abTexelMask:NULL);
}
Exemple #12
0
void CTexelGenerator::FindHiResMeshLocation(CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, size_t i, size_t j, raytrace::CRaytracer* pTracer)
{
	CConversionMesh* pMesh = pMeshInstance->GetMesh();

	Vector vu1 = pMesh->GetUV(pV1->vu);
	Vector vu2 = pMesh->GetUV(pV2->vu);
	Vector vu3 = pMesh->GetUV(pV3->vu);

	float flU = ((float)i + 0.5f)/(float)m_iWidth;
	float flV = ((float)j + 0.5f)/(float)m_iHeight;

	bool bInside = PointInTriangle(Vector(flU,flV,0), vu1, vu2, vu3);

	if (!bInside)
		return;

	Vector v1 = pMeshInstance->GetVertex(pV1->v);
	Vector v2 = pMeshInstance->GetVertex(pV2->v);
	Vector v3 = pMeshInstance->GetVertex(pV3->v);

	// Find where the UV is in world space.

	// First build 2x2 a "matrix" of the UV values.
	float mta = vu2.x - vu1.x;
	float mtb = vu3.x - vu1.x;
	float mtc = vu2.y - vu1.y;
	float mtd = vu3.y - vu1.y;

	// Invert it.
	float d = mta*mtd - mtb*mtc;
	float mtia =  mtd / d;
	float mtib = -mtb / d;
	float mtic = -mtc / d;
	float mtid =  mta / d;

	// Now build a 2x3 "matrix" of the vertices.
	float mva = v2.x - v1.x;
	float mvb = v3.x - v1.x;
	float mvc = v2.y - v1.y;
	float mvd = v3.y - v1.y;
	float mve = v2.z - v1.z;
	float mvf = v3.z - v1.z;

	// Multiply them together.
	// [a b]   [a b]   [a b]
	// [c d] * [c d] = [c d]
	// [e f]           [e f]
	// Really wish I had a matrix math library about now!
	float mra = mva*mtia + mvb*mtic;
	float mrb = mva*mtib + mvb*mtid;
	float mrc = mvc*mtia + mvd*mtic;
	float mrd = mvc*mtib + mvd*mtid;
	float mre = mve*mtia + mvf*mtic;
	float mrf = mve*mtib + mvf*mtid;

	// These vectors should be the U and V axis in world space.
	Vector vecUAxis(mra, mrc, mre);
	Vector vecVAxis(mrb, mrd, mrf);

	Vector vecUVOrigin = v1 - vecUAxis * vu1.x - vecVAxis * vu1.y;

	Vector vecUVPosition = vecUVOrigin + vecUAxis * flU + vecVAxis * flV;

	Vector vecNormal = pFace->GetNormal(vecUVPosition, pMeshInstance);

	size_t iTexel;
	Texel(i, j, iTexel, false);

	// Maybe use a closest-poly check here to eliminate the need for some raytracing?

	raytrace::CTraceResult trFront;
	bool bHitFront = pTracer->Raytrace(Ray(vecUVPosition, vecNormal), &trFront);

	raytrace::CTraceResult trBack;
	bool bHitBack = pTracer->Raytrace(Ray(vecUVPosition, -vecNormal), &trBack);

#ifdef NORMAL_DEBUG
	GetParallelizer()->LockData();
	if (bHitFront && (vecUVPosition - trFront.m_vecHit).LengthSqr() > 0.001f)
		SMAKWindow()->AddDebugLine(vecUVPosition, trFront.m_vecHit);
	if (bHitBack && (vecUVPosition - trBack.m_vecHit).LengthSqr() > 0.001f)
		SMAKWindow()->AddDebugLine(vecUVPosition, trBack.m_vecHit);
	GetParallelizer()->UnlockData();
#endif

	if (!bHitBack && !bHitFront)
		return;

	raytrace::CTraceResult* trFinal;

	if (bHitFront && !bHitBack)
		trFinal = &trFront;
	else if (bHitBack && !bHitFront)
		trFinal = &trBack;
	else
	{
		float flHitFront = (vecUVPosition - trFront.m_vecHit).LengthSqr();
		float flHitBack = (vecUVPosition - trBack.m_vecHit).LengthSqr();

		if (flHitFront < flHitBack)
			trFinal = &trFront;
		else
			trFinal = &trBack;
	}

#ifdef NORMAL_DEBUG
	GetParallelizer()->LockData();
//	SMAKWindow()->AddDebugLine(vecUVPosition, vecUVPosition+vecHitNormal);
	if (bHitFront && (vecUVPosition - trFront.m_vecHit).LengthSqr() > 0.001f)
		SMAKWindow()->AddDebugLine(trFront.m_vecHit, trFront.m_vecHit + trFront.m_pFace->GetNormal(trFront.m_vecHit, trFront.m_pMeshInstance));
	if (bHitBack && (vecUVPosition - trBack.m_vecHit).LengthSqr() > 0.001f)
		SMAKWindow()->AddDebugLine(trBack.m_vecHit, trBack.m_vecHit + trBack.m_pFace->GetNormal(trBack.m_vecHit, trBack.m_pMeshInstance));
	GetParallelizer()->UnlockData();
#endif

	for (size_t i = 0; i < m_apMethods.size(); i++)
	{
		m_apMethods[i]->GenerateTexel(iTexel, pMeshInstance, pFace, pV1, pV2, pV3, trFinal, vecUVPosition, pTracer);
	}
}
Exemple #13
0
void CAOGenerator::GenerateTriangleByTexel(CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t v1, size_t v2, size_t v3, raytrace::CRaytracer* pTracer, size_t& iRendered)
{
    CConversionVertex* pV1 = pFace->GetVertex(v1);
    CConversionVertex* pV2 = pFace->GetVertex(v2);
    CConversionVertex* pV3 = pFace->GetVertex(v3);

    CConversionMesh* pMesh = pMeshInstance->GetMesh();

    Vector vu1 = pMesh->GetUV(pV1->vu);
    Vector vu2 = pMesh->GetUV(pV2->vu);
    Vector vu3 = pMesh->GetUV(pV3->vu);

    Vector vecLoUV = vu1;
    Vector vecHiUV = vu1;

    if (vu2.x < vecLoUV.x)
        vecLoUV.x = vu2.x;
    if (vu3.x < vecLoUV.x)
        vecLoUV.x = vu3.x;
    if (vu2.x > vecHiUV.x)
        vecHiUV.x = vu2.x;
    if (vu3.x > vecHiUV.x)
        vecHiUV.x = vu3.x;

    if (vu2.y < vecLoUV.y)
        vecLoUV.y = vu2.y;
    if (vu3.y < vecLoUV.y)
        vecLoUV.y = vu3.y;
    if (vu2.y > vecHiUV.y)
        vecHiUV.y = vu2.y;
    if (vu3.y > vecHiUV.y)
        vecHiUV.y = vu3.y;

    size_t iLoX = (size_t)(vecLoUV.x * m_iWidth);
    size_t iLoY = (size_t)(vecLoUV.y * m_iHeight);
    size_t iHiX = (size_t)(vecHiUV.x * m_iWidth);
    size_t iHiY = (size_t)(vecHiUV.y * m_iHeight);

    for (size_t i = iLoX; i <= iHiX; i++)
    {
        for (size_t j = iLoY; j <= iHiY; j++)
        {
            float flU = ((float)i + 0.5f)/(float)m_iWidth;
            float flV = ((float)j + 0.5f)/(float)m_iHeight;

            bool bInside = PointInTriangle(Vector(flU,flV,0), vu1, vu2, vu3);

            if (!bInside)
                continue;

            Vector v1 = pMeshInstance->GetVertex(pV1->v);
            Vector v2 = pMeshInstance->GetVertex(pV2->v);
            Vector v3 = pMeshInstance->GetVertex(pV3->v);

            Vector vn1 = pMeshInstance->GetNormal(pV1->vn);
            Vector vn2 = pMeshInstance->GetNormal(pV2->vn);
            Vector vn3 = pMeshInstance->GetNormal(pV3->vn);

            // Find where the UV is in world space.

            // First build 2x2 a "matrix" of the UV values.
            float mta = vu2.x - vu1.x;
            float mtb = vu3.x - vu1.x;
            float mtc = vu2.y - vu1.y;
            float mtd = vu3.y - vu1.y;

            // Invert it.
            float d = mta*mtd - mtb*mtc;
            float mtia =  mtd / d;
            float mtib = -mtb / d;
            float mtic = -mtc / d;
            float mtid =  mta / d;

            // Now build a 2x3 "matrix" of the vertices.
            float mva = v2.x - v1.x;
            float mvb = v3.x - v1.x;
            float mvc = v2.y - v1.y;
            float mvd = v3.y - v1.y;
            float mve = v2.z - v1.z;
            float mvf = v3.z - v1.z;

            // Multiply them together.
            // [a b]   [a b]   [a b]
            // [c d] * [c d] = [c d]
            // [e f]           [e f]
            // Really wish I had a matrix math library about now!
            float mra = mva*mtia + mvb*mtic;
            float mrb = mva*mtib + mvb*mtid;
            float mrc = mvc*mtia + mvd*mtic;
            float mrd = mvc*mtib + mvd*mtid;
            float mre = mve*mtia + mvf*mtic;
            float mrf = mve*mtib + mvf*mtid;

            // These vectors should be the U and V axis in world space.
            Vector vecUAxis(mra, mrc, mre);
            Vector vecVAxis(mrb, mrd, mrf);

            Vector vecUVOrigin = v1 - vecUAxis * vu1.x - vecVAxis * vu1.y;

            Vector vecUVPosition = vecUVOrigin + vecUAxis * flU + vecVAxis * flV;

            Vector vecNormal;

            if (m_bCreaseEdges)
                vecNormal = pFace->GetNormal();
            else
            {
                float wv1 = DistanceToLine(vecUVPosition, v2, v3) / DistanceToLine(v1, v2, v3);
                float wv2 = DistanceToLine(vecUVPosition, v1, v3) / DistanceToLine(v2, v1, v3);
                float wv3 = DistanceToLine(vecUVPosition, v1, v2) / DistanceToLine(v3, v1, v2);

                vecNormal = vn1 * wv1 + vn2 * wv2 + vn3 * wv3;
            }

            if (ao_debug.GetInt() > 1)
                SMAKWindow()->AddDebugLine(vecUVPosition, vecUVPosition + vecNormal/2);

            size_t iTexel;
            if (!Texel(i, j, iTexel, false))
                continue;

            if (m_eAOMethod == AOMETHOD_RENDER)
            {
                // Render the scene from this location
                m_avecShadowValues[iTexel] += RenderSceneFromPosition(vecUVPosition, vecNormal, pFace);
            }
            else if (m_eAOMethod == AOMETHOD_RAYTRACE)
            {
                RaytraceSceneMultithreaded(pTracer, vecUVPosition, vecNormal, pMeshInstance, pFace, iTexel);
            }

            m_aiShadowReads[iTexel]++;
            m_bPixelMask[iTexel] = true;

            m_pWorkListener->WorkProgress(++iRendered);

            if (m_bStopGenerating)
                break;
        }
        if (m_bStopGenerating)
            break;
    }
}
  TextureComp::TextureComp(GLuint textureID) :
    textureID_(textureID),
    transform_(Texel(0.f, 0.f), Texel(0.f, 0.f), Texel(1.f, 1.f))
  {

  }
 const Texel operator +(const Texel &lhs, const Texel &rhs) {
   return Texel(lhs.x + rhs.x, lhs.y + rhs.y);
 }
 const Texel operator *(const Texel &lhs, const float rhs) {
   return Texel(lhs.x * rhs, lhs.y * rhs);
 }
Exemple #17
0
void CNormalGenerator::NormalizeHeightValue(size_t x, size_t y)
{
	if (!m_avecTextureTexels.size())
		return;

	float flHiScale = ((m_iNormal2Width+m_iNormal2Height)/2.0f)/200.0f * m_flNormalTextureDepth;
	float flMidScale = ((m_iNormal2Width+m_iNormal2Height)/2.0f)/100.0f * m_flNormalTextureDepth;
	float flLowScale = ((m_iNormal2Width+m_iNormal2Height)/2.0f)/50.0f * m_flNormalTextureDepth;

	size_t iTexel;
	Texel(x, y, iTexel, m_iNormal2Width, m_iNormal2Height, false);

	tvector<Vector> avecHeights;

	float flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
	float flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
	float flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;

	Vector vecCenter((float)x, (float)y, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
	Vector vecNormal(0,0,0);

	if (Texel(x+1, y, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor(x+1.0f, (float)y, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(0, 1, 0));
	}

	if (Texel(x-1, y, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor(x-1.0f, (float)y, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(0, -1, 0));
	}

	if (Texel(x, y+1, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor((float)x, y+1.0f, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(-1, 0, 0));
	}

	if (Texel(x, y-1, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor((float)x, y-1.0f, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(1, 0, 0));
	}

	vecNormal.Normalize();

	for (size_t i = 0; i < 3; i++)
		vecNormal[i] = RemapVal(vecNormal[i], -1.0f, 1.0f, 0.0f, 0.99f);	// Don't use 1.0 because of integer overflow.

	// Don't need to lock the data because we're guaranteed never to access the same texel twice due to the generation method.
	m_avecNormal2Texels[iTexel] = vecNormal;
}