private void compactLayers(int bottomLayerIndex, int topLayerIndex) { int sze = (int)(BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight()); //subtract from middle layers first BTerrainTexturingLayer topLayer = giveLayer(topLayerIndex); for (int i = bottomLayerIndex + 1; i < topLayerIndex; i++) { BTerrainTexturingLayer middleLayer = giveLayer(i); // if (middleLayer.mLayerType != BTerrainTexturingLayer.eLayerType.cLayer_Splat) // continue; for (int x = 0; x < sze; x++) { middleLayer.mAlphaLayer[x] = (byte)(BMathLib.Clamp(middleLayer.mAlphaLayer[x] - topLayer.mAlphaLayer[x], 0, 255)); } } //now add it to the bottom layer BTerrainTexturingLayer bottomLayer = giveLayer(bottomLayerIndex); for (int x = 0; x < sze; x++) { bottomLayer.mAlphaLayer[x] = (byte)(BMathLib.Clamp(bottomLayer.mAlphaLayer[x] + topLayer.mAlphaLayer[x], 0, 255)); } //remove top layer removeLayer(topLayerIndex); }
public void copyTo(BTerrainTexturingLayer target) { target.mLayerType = mLayerType; target.mActiveTextureIndex = mActiveTextureIndex; if (target.mAlphaLayer == null) { target.mAlphaLayer = new Byte[BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight()]; } mAlphaLayer.CopyTo(target.mAlphaLayer, 0); }
public void moveSelectdDecalsFromEditorInput() { if (mDecalInstances.Count == 0) { return; } int xCenterGlobal = 0; int zCenterGlobal = 0; //CLM THIS MATH IS VERY TRICKY!! PLEASE TALK TO ME BEFORE SCREWING WITH IT!!!! //CLM THIS MATH IS VERY TRICKY!! PLEASE TALK TO ME BEFORE SCREWING WITH IT!!!! float vertsToHighResPixelSpaceRatio = BTerrainTexturing.getTextureWidth() / BTerrainQuadNode.cMaxWidth; int mVisTileIntetersectionX = TerrainGlobals.getEditor().mVisTileIntetersectionX; int mVisTileIntetersectionZ = TerrainGlobals.getEditor().mVisTileIntetersectionZ; Vector3 intpt = TerrainGlobals.getEditor().mBrushIntersectionPoint; for (int i = 0; i < mDecalInstances.Count; i++) { if (mDecalInstances[i].mIsSelected) { int myTileX = mVisTileIntetersectionX; // (int)((mDecalInstances[i].mTileCenter.X / vertsToHighResPixelSpaceRatio) + (diffX)); int myTileZ = mVisTileIntetersectionZ; // (int)((mDecalInstances[i].mTileCenter.Y / vertsToHighResPixelSpaceRatio) + (diffZ)); BTerrainActiveDecalContainer dcl = mActiveDecals[mDecalInstances[i].mActiveDecalIndex]; Vector3 a = TerrainGlobals.getTerrain().getPostDeformPos(myTileX, myTileZ); Vector3 b = TerrainGlobals.getTerrain().getPostDeformPos(myTileX + 1, myTileZ); Vector3 c = TerrainGlobals.getTerrain().getPostDeformPos(myTileX, myTileZ + 1); Vector3 d = TerrainGlobals.getTerrain().getPostDeformPos(myTileX + 1, myTileZ + 1); //find the max def for this tile float x1 = (float)Math.Abs(a.X - b.X); float x2 = (float)Math.Abs(c.X - d.X); float xM = x1 > x2 ? x1 : x2; float xPT = xM > 0 ? (intpt.X - a.X) / xM : 0; //gives us percentage IN THE TILE float z1 = (float)Math.Abs(a.Z - c.Z); float z2 = (float)Math.Abs(b.Z - d.Z); float zM = z1 > z2 ? z1 : z2; float zPT = zM > 0 ? (intpt.Z - a.Z) / zM : 0; //gives us percentage IN THE TILE //scale that up to percentages in the space of our pixels mDecalInstances[i].mTileCenter.X = ((xPT * vertsToHighResPixelSpaceRatio) + (myTileX * vertsToHighResPixelSpaceRatio)); mDecalInstances[i].mTileCenter.Y = ((zPT * vertsToHighResPixelSpaceRatio) + (myTileZ * vertsToHighResPixelSpaceRatio)); recomputeDecalInstanceBounds(i, true); } } }
public void clearAllAlphasAtPixel(int x, int z) { if (x < 0 || z < 0 || x >= BTerrainTexturing.getAlphaTextureWidth() || z >= BTerrainTexturing.getAlphaTextureHeight()) { return; } for (int i = mLayers.Count - 1; i >= 0; i--) { mLayers[i].mAlphaLayer[x + BTerrainTexturing.getAlphaTextureWidth() * z] = 0; } }
public void create(int width, int height, int startingReserve) { mWidth = width; mHeight = height; int numMips = (mWidth < BTerrainTexturing.getTextureHeight() >> 1) ? 1 : BTerrainTexturing.cMaxNumMips; mCache = new List <BTerrainCompositeTexture>(startingReserve); if (startingReserve >= 2)//256) //use atlas { mAtlasList = new List <BTerrainCompositeAtlasTexture>(); int atlasSize = 1024; int maxColumns = atlasSize / mWidth; int maxRows = atlasSize / mHeight; int maxEntries = maxColumns * maxRows; while (maxEntries / startingReserve >= 2) { atlasSize /= 2; maxColumns = atlasSize / mWidth; maxRows = atlasSize / mHeight; maxEntries = maxColumns * maxRows; } int neededAtlases = (int)Math.Ceiling(startingReserve / (float)maxEntries); int currentIndex = 0; BTerrainCompositeAtlasTexture currentAtlas = new BTerrainCompositeAtlasTexture(mWidth, mHeight, maxEntries, maxRows, maxColumns, numMips, Format.R5G6B5); mAtlasList.Add(currentAtlas); for (int i = 0; i < startingReserve; i++) { mCache.Add(new BTerrainCompositeTexture(mWidth, mHeight, numMips, currentAtlas, currentIndex)); currentIndex++; if (currentIndex >= maxEntries && currentIndex < startingReserve) { currentAtlas = new BTerrainCompositeAtlasTexture(mWidth, mHeight, maxEntries, maxRows, maxColumns, numMips, Format.R5G6B5); mAtlasList.Add(currentAtlas); currentIndex = 0; } } } else //normal way { for (int i = 0; i < startingReserve; i++) { mCache.Add(new BTerrainCompositeTexture(mWidth, mHeight, numMips, null, -1)); } } }
//------------------------------------------ //called to create the mask form the texture public unsafe bool applyMask(BTerrainQuadNode node, int x, int z, bool alternate) { UInt32 *MskPtr = mStroke.getBits(); mMskImgWidth = (uint)mStroke.cBufferSize; mMskImgHeight = (uint)mStroke.cBufferSize; bool changed = Texturing_LayerEditor.setMaskAlphaToTextureBlending(node, BTerrainTexturing.getAlphaTextureWidth(), BTerrainTexturing.getAlphaTextureWidth(), MskPtr, mMskImgWidth, mMskImgHeight, mStroke.mAlphaValue, x, z, alternate); mStroke.unlockBits(); return(changed); }
public bool mIsSelected; //editor can select a decal instance public void computeBounds() { float vertsToHighResPixelSpaceRatio = BTerrainTexturing.getTextureWidth() / BTerrainQuadNode.cMaxWidth; BTerrainActiveDecalContainer dcl = TerrainGlobals.getTexturing().getActiveDecal(mActiveDecalIndex); int h = (int)(dcl.mWidth * (1.0f / mUScale)); int w = (int)(dcl.mHeight * (1.0f / mVScale)); //rotate our bounds float angleRad = mRotation;// -rotAngle * Math.PI / 180; float angleCos = (float)Math.Cos(angleRad); float angleSin = (float)Math.Sin(angleRad); float halfWidth = w >> 1; float halfHeight = h >> 1; float halfNewWidth, halfNewHeight; int newWidth, newHeight; // rotate corners float cx1 = halfWidth * angleCos; float cy1 = halfWidth * angleSin; float cx2 = halfWidth * angleCos - halfHeight * angleSin; float cy2 = halfWidth * angleSin + halfHeight * angleCos; float cx3 = -halfHeight * angleSin; float cy3 = halfHeight * angleCos; float cx4 = 0; float cy4 = 0; halfNewWidth = Math.Max(Math.Max(cx1, cx2), Math.Max(cx3, cx4)) - Math.Min(Math.Min(cx1, cx2), Math.Min(cx3, cx4)); halfNewHeight = Math.Max(Math.Max(cy1, cy2), Math.Max(cy3, cy4)) - Math.Min(Math.Min(cy1, cy2), Math.Min(cy3, cy4)); newWidth = (int)(halfNewWidth * 2 + 0.5); newHeight = (int)(halfNewHeight * 2 + 0.5); w = newWidth >> 1; h = newHeight >> 1; mTileBoundsMin.X = (int)((mTileCenter.X - (w)) / vertsToHighResPixelSpaceRatio); mTileBoundsMax.X = (int)((mTileCenter.X + (w)) / vertsToHighResPixelSpaceRatio); mTileBoundsMin.Y = (int)((mTileCenter.Y - (h)) / vertsToHighResPixelSpaceRatio); mTileBoundsMax.Y = (int)((mTileCenter.Y + (h)) / vertsToHighResPixelSpaceRatio); }
public void fullLayerAlpha(int layerIndex) { if (layerIndex < 0 || layerIndex >= mLayers.Count) { return; } for (int x = 0; x < (int)BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < (int)BTerrainTexturing.getAlphaTextureHeight(); z++) { mLayers[layerIndex].mAlphaLayer[x + BTerrainTexturing.getAlphaTextureWidth() * z] = Byte.MaxValue; } } }
public void decouple() { if (mOwnerNode != null) { //mOwnerNode.getTextureData().mCompositeTexture = null; int lod = BTerrainTexturing.widthToLOD(mWidth); if (mOwnerNode.getTextureData(lod) != null) { mOwnerNode.getTextureData(lod).mCompositeTexture = null; } mOwnerNode = null; } }
public void resizeSelectedDecals(float xScaleAmt, float yScaleAmt) { float vertsToHighResPixelSpaceRatio = BTerrainTexturing.getTextureWidth() / BTerrainQuadNode.cMaxWidth; for (int i = 0; i < mDecalInstances.Count; i++) { if (mDecalInstances[i].mIsSelected) { BTerrainActiveDecalContainer dcl = mActiveDecals[mDecalInstances[i].mActiveDecalIndex]; mDecalInstances[i].mUScale += xScaleAmt; mDecalInstances[i].mVScale += yScaleAmt; recomputeDecalInstanceBounds(i, true); } } }
//Functions will effect Decal Only public int newDecalLayer(int activeDecalInstanceIndex) { if (mLayers.Count > 0 && mLayers[mLayers.Count - 1].mActiveTextureIndex == activeDecalInstanceIndex && mLayers[mLayers.Count - 1].mLayerType == BTerrainTexturingLayer.eLayerType.cLayer_Decal) { return(mLayers.Count - 1); } mLayers.Add(new BTerrainTexturingLayer()); mLayers[mLayers.Count - 1].mLayerType = BTerrainTexturingLayer.eLayerType.cLayer_Decal; mLayers[mLayers.Count - 1].mActiveTextureIndex = activeDecalInstanceIndex; mLayers[mLayers.Count - 1].mAlphaLayer = new Byte[BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight()]; fullLayerAlpha(mLayers.Count - 1); return(mLayers.Count - 1); }
public void removeHiddenLayers() { int sze = (int)(BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight()); //remove layers below a fully opaque layer for (int i = 1; i < mLayers.Count; i++) { if (mLayers[i].mLayerType != BTerrainTexturingLayer.eLayerType.cLayer_Splat) { continue; } if (isLayerAllSolid(i)) { removeLayersBelow(i); i = 0; } } }
public bool isLayerAllClear(int layerIndex) { if (layerIndex < 0 || layerIndex >= mLayers.Count) { return(false); } for (int x = 0; x < (int)BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < (int)BTerrainTexturing.getAlphaTextureHeight(); z++) { if (mLayers[layerIndex].mAlphaLayer[x + BTerrainTexturing.getAlphaTextureWidth() * z] != 0) { return(false); } } } return(true); }
//used for clipart public BTerrainTextureVector giveLayerChainAtPixel(int x, int z) { BTerrainTextureVector v = new BTerrainTextureVector(); if (x < 0 || z < 0 || x >= BTerrainTexturing.getAlphaTextureWidth() || z >= BTerrainTexturing.getAlphaTextureHeight()) { return(v); } for (int i = 0; i < mLayers.Count; i++) { BTerrainPerVertexLayerData layer = new BTerrainPerVertexLayerData(); layer.mActiveTextureIndex = mLayers[i].mActiveTextureIndex; layer.mLayerType = mLayers[i].mLayerType; layer.mAlphaContrib = mLayers[i].mAlphaLayer[x + BTerrainTexturing.getAlphaTextureWidth() * z]; v.mLayers.Add(layer); } return(v); }
public int newSplatLayer(int activeTextureIndex, bool insertKeepOrdering) { if (mLayers.Count > 0 && mLayers[mLayers.Count - 1].mActiveTextureIndex == activeTextureIndex && mLayers[mLayers.Count - 1].mLayerType == BTerrainTexturingLayer.eLayerType.cLayer_Splat) { return(mLayers.Count - 1); } int addedIndex = -1; if (insertKeepOrdering) { for (int i = 0; i < mLayers.Count; i++) { if (mLayers[i].mActiveTextureIndex > activeTextureIndex) { addedIndex = i; break; } } } if (addedIndex == -1) { mLayers.Add(new BTerrainTexturingLayer()); addedIndex = mLayers.Count - 1; } else { mLayers.Insert(addedIndex, new BTerrainTexturingLayer()); } mLayers[addedIndex].mLayerType = BTerrainTexturingLayer.eLayerType.cLayer_Splat; mLayers[addedIndex].mActiveTextureIndex = activeTextureIndex; mLayers[addedIndex].mAlphaLayer = new Byte[BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight()]; return(addedIndex); }
private int giveLayerIDAtPixelInternal(int x, int y, int startingLayer, ref BTerrainTexturingLayer.eLayerType selectedLayerType) { if (startingLayer > mLayers.Count - 1) { startingLayer = mLayers.Count - 1; } if (startingLayer < 0) { selectedLayerType = BTerrainTexturingLayer.eLayerType.cLayer_Splat; return(0); } for (int i = startingLayer; i >= 0; i--) { if (mLayers[i].mAlphaLayer[x + BTerrainTexturing.getAlphaTextureWidth() * y] != 0) { if (mLayers[i].mLayerType == BTerrainTexturingLayer.eLayerType.cLayer_Splat) { selectedLayerType = BTerrainTexturingLayer.eLayerType.cLayer_Splat; return(mLayers[i].mActiveTextureIndex); } else { BTerrainDecalInstance dcli = TerrainGlobals.getTexturing().getActiveDecalInstance(mLayers[i].mActiveTextureIndex); if (TerrainGlobals.getEditor().mVisTileIntetersectionX <= dcli.mTileBoundsMax.X && TerrainGlobals.getEditor().mVisTileIntetersectionX >= dcli.mTileBoundsMin.X && TerrainGlobals.getEditor().mVisTileIntetersectionZ <= dcli.mTileBoundsMax.Y && TerrainGlobals.getEditor().mVisTileIntetersectionZ >= dcli.mTileBoundsMin.Y) { selectedLayerType = BTerrainTexturingLayer.eLayerType.cLayer_Decal; return(i);// dcli.mActiveDecalIndex; } } } } selectedLayerType = BTerrainTexturingLayer.eLayerType.cLayer_Splat; return(-1); }
public void flip(eFlipType type) { int width = (int)(BTerrainTexturing.getAlphaTextureWidth()); int workWidth = width - 1; for (int i = 0; i < mLayers.Count; i++) { if (type == eFlipType.eFlip_Horiz) { byte[] tmpRef = (byte[])mLayers[i].mAlphaLayer.Clone(); for (int x = 0; x < BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < BTerrainTexturing.getAlphaTextureWidth(); z++) { int dstIndex = x + width * z; int srcIndex = (workWidth - x) + width * z; mLayers[i].mAlphaLayer[dstIndex] = tmpRef[srcIndex]; } } } else if (type == eFlipType.eFlip_Vert) { byte[] tmpRef = (byte[])mLayers[i].mAlphaLayer.Clone(); for (int x = 0; x < BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < BTerrainTexturing.getAlphaTextureWidth(); z++) { int dstIndex = x + width * z; int srcIndex = x + width * (workWidth - z); mLayers[i].mAlphaLayer[dstIndex] = tmpRef[srcIndex]; } } } } }
unsafe static public bool setMaskAlphaToLayer(BTerrainQuadNode node, UInt32 *mskImg, uint mskImgWidth, uint mskImgHeight, float alphaScalar, int terrainGridX, int terrainGridZ, char index) { bool changed = false; uint dstImgWidth = BTerrainTexturing.getAlphaTextureWidth(); uint dstImgHeight = BTerrainTexturing.getAlphaTextureWidth(); float vertsToPixelsRatio = BTerrainTexturing.getAlphaTextureWidth() / (float)BTerrainQuadNode.getMaxNodeWidth(); int minxvert = node.getDesc().mMinXVert; int minzvert = node.getDesc().mMinZVert; int maxxvert = node.getDesc().mMaxXVert; int maxzvert = node.getDesc().mMaxZVert; BTerrainLayerContainer layers = node.mLayerContainer; int layerIndex = layers.giveLayerIndex(index, BTerrainTexturingLayer.eLayerType.cLayer_Splat); if (TerrainGlobals.getEditor().mEraseTextureInstead&& layerIndex == 0) { return(false); } // layers.removeRedundantLayers();//CLM is this still needed?!??! if (layerIndex == -1) { if (TerrainGlobals.getEditor().mEraseTextureInstead) //we're erasing, and the texture doesn't exist.. { return(false); } //i don't exist yet. newSplatLayerEverywhere(index); layerIndex = layers.giveLayerIndex(index, BTerrainTexturingLayer.eLayerType.cLayer_Splat); BTerrainTexturingLayer tLayer = layers.giveLayer(layerIndex); for (int x = 0; x < BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < BTerrainTexturing.getAlphaTextureWidth(); z++) { float curWeight = TerrainGlobals.getTerrain().getSoftSelectionWeight(terrainGridX, terrainGridZ); if (!BMathLib.compare(curWeight, 0.0f)) { int cX = (int)((x * vertsToPixelsRatio) + minxvert); int cZ = (int)((z * vertsToPixelsRatio) + minzvert); curWeight = BMathLib.Clamp(curWeight, 0, 1); int dIP = x + ((int)BTerrainTexturing.getAlphaTextureHeight()) * z; byte alphaMapVal = giveBrushAlphaValue(mskImg, mskImgWidth, mskImgHeight, minxvert, minzvert, maxxvert, maxzvert, cX, cZ, terrainGridX, terrainGridZ); byte val = (byte)(alphaMapVal * alphaScalar * curWeight); tLayer.mAlphaLayer[dIP] = val; } } } changed = true; } else { BTerrainTexturingLayer tLayer = layers.giveLayer(layerIndex); //this layer already exists. //If a pixel exists above me, subtract me from it, rather than adding to me. for (int x = 0; x < BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < BTerrainTexturing.getAlphaTextureWidth(); z++) { //find the closest vert int cX = (int)((x * vertsToPixelsRatio) + minxvert); int cZ = (int)((z * vertsToPixelsRatio) + minzvert); int dIP = x + ((int)BTerrainTexturing.getAlphaTextureHeight()) * z; float curWeight = TerrainGlobals.getTerrain().getSoftSelectionWeight(terrainGridX, terrainGridZ); if (!BMathLib.compare(curWeight, 0.0f)) { changed = true; curWeight = BMathLib.Clamp(curWeight, 0, 1); byte alphaMapVal = giveBrushAlphaValue(mskImg, mskImgWidth, mskImgHeight, minxvert, minzvert, maxxvert, maxzvert, cX, cZ, terrainGridX, terrainGridZ); byte val = (byte)(alphaMapVal * alphaScalar * curWeight); valToLayerColumn(layers, tLayer, dIP, val, layerIndex); } } } } layers.removeBlankLayers(); return(changed); }
//---------------------------------------------- unsafe static public bool setIndexToMaskedArea(BTerrainQuadNode node, int minxvert, int minzvert, int maxxvert, int maxzvert, char index) { bool changed = false; uint dstImgWidth = BTerrainTexturing.getAlphaTextureWidth(); uint dstImgHeight = BTerrainTexturing.getAlphaTextureWidth(); float vertsToPixelsRatio = BTerrainTexturing.getAlphaTextureWidth() / (float)BTerrainQuadNode.getMaxNodeWidth(); BTerrainLayerContainer layers = node.mLayerContainer; int layerIndex = layers.giveLayerIndex(index, BTerrainTexturingLayer.eLayerType.cLayer_Splat); if (TerrainGlobals.getEditor().mEraseTextureInstead&& layerIndex == 0) { return(false); } //layers.removeRedundantLayers();//CLM is this still needed?!??! if (layerIndex == -1) { if (TerrainGlobals.getEditor().mEraseTextureInstead) //we're erasing, and the texture doesn't exist.. { return(false); } //i don't exist yet. newSplatLayerEverywhere(index); layerIndex = layers.giveLayerIndex(index, BTerrainTexturingLayer.eLayerType.cLayer_Splat); BTerrainTexturingLayer tLayer = layers.giveLayer(layerIndex); for (int x = 0; x < BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < BTerrainTexturing.getAlphaTextureWidth(); z++) { //find the closest vert int cX = (int)((x * vertsToPixelsRatio) + minxvert); int cZ = (int)((z * vertsToPixelsRatio) + minzvert); int vertIndex = (int)(cX * TerrainGlobals.getTerrain().getNumZVerts() + cZ); float curWeight = 1.0f; if (Masking.isPointSelected(vertIndex, ref curWeight)) { curWeight = BMathLib.Clamp(curWeight, 0, 1); int dIP = x + ((int)BTerrainTexturing.getAlphaTextureHeight()) * z; byte val = (byte)(curWeight * byte.MaxValue); tLayer.mAlphaLayer[dIP] = val; } } } changed = true; } else { BTerrainTexturingLayer tLayer = layers.giveLayer(layerIndex); //this layer already exists. //If a pixel exists above me, subtract me from it, rather than adding to me. for (int x = 0; x < BTerrainTexturing.getAlphaTextureWidth(); x++) { for (int z = 0; z < BTerrainTexturing.getAlphaTextureWidth(); z++) { //find the closest vert int cX = (int)((x * vertsToPixelsRatio) + minxvert); int cZ = (int)((z * vertsToPixelsRatio) + minzvert); int vertIndex = (int)(cX * TerrainGlobals.getTerrain().getNumZVerts() + cZ); float curWeight = 1.0f; if (Masking.isPointSelected(vertIndex, ref curWeight)) { changed = true; int dIP = x + ((int)BTerrainTexturing.getAlphaTextureHeight()) * z; curWeight = BMathLib.Clamp(curWeight, 0, 1); byte val = (byte)(curWeight * byte.MaxValue); valToLayerColumn(layers, tLayer, dIP, val, layerIndex); } } } } layers.removeBlankLayers(); return(changed); }
void fillCreateLayer(byte[] inputImg, int activeTexIndex, BTerrainTexturingLayer.eLayerType type, int minXTile, int minZTile, byte[] tempLargerImge, byte[] tempBorderedImg) { int width = (int)BTerrainTexturing.getAlphaTextureWidth(); int height = (int)BTerrainTexturing.getAlphaTextureHeight(); int lw = width + 2; int lh = height + 2; //Create our texture first, border it, then resize it. //fill the origional texture into the new texture for (int q = 0; q < (width); q++) { for (int j = 0; j < (height); j++) { tempLargerImge[(q + 1) + lw * (j + 1)] = inputImg[q + (width) * j]; } } int numXNodes = (int)(TerrainGlobals.getTerrain().getNumXVerts() / BTerrainQuadNode.cMaxWidth); int rootXNode = (int)(minXTile / BTerrainQuadNode.cMaxWidth); int rootZNode = (int)(minZTile / BTerrainQuadNode.cMaxHeight); BTerrainQuadNode rootNode = TerrainGlobals.getTerrain().getLeafNode(rootXNode, rootZNode);//TerrainGlobals.getTerrain().getQuadNodeRoot().getLeafNodeContainingTile(minXTile, minZTile); BTerrainQuadNode node = null; int layerIndex = 0; BTerrainTexturingLayer lyr = null; #region SIDES //grab neighbor alpha values, paste them into my edges. //LEFT SIDE FILL node = TerrainGlobals.getTerrain().getLeafNode(rootXNode - 1, rootZNode);// rootNode.getNeighborNode(-1, 0); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the RIGHT pixels for (int i = 0; i < height; i++) { int srcIndex = (width - 1) + width * i; int destIndex = 0 + (lw * (i + 1)); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //extend the LEFT pixels for (int i = 0; i < height; i++) { int srcIndex = 0 + width * i; int destIndex = 0 + (lw * (i + 1)); tempLargerImge[destIndex] = inputImg[srcIndex]; } } //RIGHT SIDE FILL node = TerrainGlobals.getTerrain().getLeafNode(rootXNode + 1, rootZNode);// rootNode.getNeighborNode(1, 0); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the LEFT pixels for (int i = 0; i < height; i++) { int srcIndex = 0 + width * i; int destIndex = (lw - 1) + (lw * (i + 1)); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } else { //extend the RIGHT pixels for (int i = 0; i < height; i++) { int srcIndex = (width - 1) + width * i; int destIndex = (lw - 1) + (lw * (i + 1)); tempLargerImge[destIndex] = inputImg[srcIndex]; } } //TOP SIDE FILL node = TerrainGlobals.getTerrain().getLeafNode(rootXNode, rootZNode + 1);// rootNode.getNeighborNode(0, 1); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the BOTTOM pixels for (int i = 0; i < width; i++) { int srcIndex = i + width * 0; int destIndex = (i + 1) + (lw * (lh - 1)); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //extend the TOP pixels for (int i = 0; i < width; i++) { int srcIndex = i + width * (height - 1); int destIndex = (i + 1) + (lw * (lh - 1)); tempLargerImge[destIndex] = inputImg[srcIndex]; } } //BOTTOM SIDE FILL node = TerrainGlobals.getTerrain().getLeafNode(rootXNode, rootZNode - 1);// rootNode.getNeighborNode(0, -1); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the TOP pixels for (int i = 0; i < width; i++) { int srcIndex = i + width * (height - 1); int destIndex = (i + 1) + (lw * 0); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //extend the BOTTOM pixels for (int i = 0; i < width; i++) { int srcIndex = i + width * 0; int destIndex = (i + 1) + (0); tempLargerImge[destIndex] = inputImg[srcIndex]; } } #endregion #region CORNERS //TOP LEFT CORNER node = TerrainGlobals.getTerrain().getLeafNode(rootXNode - 1, rootZNode + 1);//rootNode.getNeighborNode(-1, 1); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the BOTTOM RIGHT pixel //for (int i = 0; i < width; i++) { int srcIndex = (width - 1) + width * 0; int destIndex = 0 + (lw * (lh - 1)); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //grab the tpo+1, left+1 pixel //for (int i = 0; i < width; i++) { int srcIndex = 1 + width * (height - 2); int destIndex = 0 + (lw * (lh - 1)); tempLargerImge[destIndex] = inputImg[srcIndex]; } } //TOP RIGHT CORNER node = TerrainGlobals.getTerrain().getLeafNode(rootXNode + 1, rootZNode + 1);//rootNode.getNeighborNode(1, 1); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the BOTTOM LEFT pixel //for (int i = 0; i < width; i++) { int srcIndex = 0;// +width * (height - 1); int destIndex = (lw - 1) + (lw * (lh - 1)); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //grab the TOP+1 RIGHT+1 pixel //for (int i = 0; i < width; i++) { int srcIndex = (width - 2) + width * (height - 2); int destIndex = (lw - 1) + (lw * (lh - 1)); tempLargerImge[destIndex] = inputImg[srcIndex]; } } //BOTTOM LEFT CORNER node = TerrainGlobals.getTerrain().getLeafNode(rootXNode - 1, rootZNode - 1);//rootNode.getNeighborNode(-1, -1); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the TOP RIGHT pixel //for (int i = 0; i < width; i++) { int srcIndex = (width - 1) + width * (height - 1); int destIndex = 0 + (lw * 0); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //grab the BOTTOM+1 LEFT+1 pixel //for (int i = 0; i < width; i++) { int srcIndex = 1 + width * 1; int destIndex = 0 + (lw * 0); tempLargerImge[destIndex] = inputImg[srcIndex]; } } //BOTTOM RIGHT CORNER node = TerrainGlobals.getTerrain().getLeafNode(rootXNode + 1, rootZNode - 1);//rootNode.getNeighborNode(1, -1); if ((node != null) && ((layerIndex = node.mLayerContainer.giveLayerIndex(activeTexIndex, type)) != -1)) { { lyr = node.mLayerContainer.giveLayer(layerIndex); //grab the TOP LEFT pixel //for (int i = 0; i < width; i++) { int srcIndex = (0) + width * (height - 1); int destIndex = (lw - 1) + (lw * 0); tempLargerImge[destIndex] = lyr.mAlphaLayer[srcIndex]; } } } else { //grab the BOTTOM+1 RIGHT+1 pixel //for (int i = 0; i < width; i++) { int srcIndex = (width - 2) + width * 1; int destIndex = (lw - 1) + (lw * 0); tempLargerImge[destIndex] = inputImg[srcIndex]; } } #endregion ImageManipulation.resizeGreyScaleImg(tempLargerImge, tempBorderedImg, width + 2, height + 2, width, height, ImageManipulation.eFilterType.cFilter_Linear); }
public void computeDecalLayerAlphaContrib(int layerIndex, int minXVertex, int minZVertex) { if (layerIndex < 0 || layerIndex >= mLayers.Count) { return; } //grab our decal instance if (mLayers[layerIndex].mLayerType != BTerrainTexturingLayer.eLayerType.cLayer_Decal) { return; } float vertsToHighResPixelSpaceRatio = BTerrainTexturing.getTextureWidth() / BTerrainQuadNode.cMaxWidth; BTerrainDecalInstance dcli = TerrainGlobals.getTexturing().getActiveDecalInstance(mLayers[layerIndex].mActiveTextureIndex); BTerrainActiveDecalContainer dcl = TerrainGlobals.getTexturing().getActiveDecal(dcli.mActiveDecalIndex); //scale, rotate, translate us int h = dcl.mHeight; int w = dcl.mWidth; int nW = (int)(w * ((1.0f / dcli.mUScale) / vertsToHighResPixelSpaceRatio)); int nH = (int)(h * ((1.0f / dcli.mVScale) / vertsToHighResPixelSpaceRatio)); int tW = 0; int tH = 0; byte[] tImgResized = null; byte[] tImgRotated = null; byte[] imgDat = new byte[h * w]; imgDat = ImageManipulation.valueGreyScaleImg(imgDat, w, h, ImageManipulation.eValueOperation.cValue_Set, 255); tImgResized = ImageManipulation.resizeGreyScaleImg(imgDat, w, h, nW, nH, ImageManipulation.eFilterType.cFilter_Linear); tImgRotated = ImageManipulation.rotateGreyScaleImg(tImgResized, nW, nH, (float)(-dcli.mRotation * (180.0f / Math.PI)), false, out nW, out nH, ImageManipulation.eFilterType.cFilter_Nearest); byte[] tImg = tImgRotated; int startX = (int)((dcli.mTileCenter.X / vertsToHighResPixelSpaceRatio) - (nW >> 1) - minXVertex); int startY = (int)((dcli.mTileCenter.Y / vertsToHighResPixelSpaceRatio) - (nH >> 1) - minZVertex); clearLayerAlpha(layerIndex); //copy back to masking for (int i = 0; i < nW; i++) { for (int j = 0; j < nH; j++) { int iS = startX + i; if (iS < 0 || iS >= BTerrainTexturing.getAlphaTextureWidth()) { continue; } int jS = startY + j; if (jS < 0 || jS >= BTerrainTexturing.getAlphaTextureHeight()) { continue; } int srcIndex = j + i * nW; int dstIndex = (int)(iS + BTerrainTexturing.getAlphaTextureHeight() * jS); byte val = tImg[srcIndex]; mLayers[layerIndex].mAlphaLayer[dstIndex] = val; } } //also, walk any layers that exist above us, and subtract out their values as well for (int k = layerIndex + 1; k < mLayers.Count; k++) { if (mLayers[k].mLayerType == BTerrainTexturingLayer.eLayerType.cLayer_Splat) { for (int i = 0; i < BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight(); i++) { mLayers[layerIndex].mAlphaLayer[i] = (byte)BMathLib.Clamp(mLayers[layerIndex].mAlphaLayer[i] - mLayers[k].mAlphaLayer[i], 0, 255); } } } imgDat = null; tImgResized = null; tImgRotated = null; tImg = null; }
public void ensureProperLayerOrdering() { ensureProperNumberLayers(); int numSplatLayers = TerrainGlobals.getTexturing().getActiveTextureCount(); int aWidth = (int)BTerrainTexturing.getAlphaTextureWidth(); int aHeight = (int)BTerrainTexturing.getAlphaTextureHeight(); for (int y = 0; y < aHeight; y++) { for (int x = 0; x < aWidth; x++) { int aIndex = x + aWidth * y; //create N floatN vectors floatN[] layerVecs = new floatN[numSplatLayers]; for (uint k = 0; k < numSplatLayers; k++) { layerVecs[k] = new floatN((uint)numSplatLayers); layerVecs[k][k] = 1; } //quick early out test to make sure we're not screwing up by re-normalizing.. floatN nVal = new floatN((uint)numSplatLayers); for (uint k = 0; k < numSplatLayers; k++) { byte b = mLayers[(int)k].mAlphaLayer[aIndex]; float alpha = ((float)b) / 255.0f; nVal[k] = alpha; } float len = nVal.Length(); if (len == 1.0f) { continue; } //now, calculate a VContrib vector for the current layering. floatN vContrib = layerVecs[0].Clone();//start with 100% base layer for (uint k = 1; k < numSplatLayers; k++) { byte b = mLayers[(int)k].mAlphaLayer[aIndex]; int lIdx = mLayers[(int)k].mActiveTextureIndex; float alpha = ((float)b) / 255.0f; vContrib = ( (layerVecs[lIdx] * alpha) + (vContrib * (1 - alpha)) ); } //vContrib now holds at each vector element, the amount the layer is visible to the final pixel //although it's not sorted in the current layer ordering //so, calculate the xF for the new layer ordering, and store it in a temp var floatN vContribSorted = new floatN((uint)numSplatLayers); floatN vContribSortedInv = new floatN((uint)numSplatLayers); //back solve to calculate new alpha value. vContribSorted[(uint)(numSplatLayers - 1)] = vContrib[(uint)(numSplatLayers - 1)]; vContribSortedInv[(uint)(numSplatLayers - 1)] = 1 - vContribSorted[(uint)(numSplatLayers - 1)]; for (int k = (numSplatLayers - 2); k >= 0; k--) { //multiply the inversions together that we have so far. float mulSoFar = 1; for (uint q = (uint)k + 1; q < numSplatLayers; q++) { mulSoFar *= vContribSortedInv[q]; } vContribSorted[(uint)k] = mulSoFar == 0 ? 0 : vContrib[(uint)(k)] / mulSoFar; vContribSortedInv[(uint)k] = 1 - vContribSorted[(uint)k]; //uint invK = (uint)((numSplatLayers - 2) - k); //float Vc = vContrib[(uint)(k + 1)]; //vContrib for upper layer //float invVc = 1.0f - Vc; ////current layer vContrib //float cVc = vContrib[(uint)(k)]; //float xF = invVc==0?0:(cVc / invVc); ////move back //vContribSorted[(uint)k] = xF; } //now copy back to the unsorted layer index for (int k = 0; k < numSplatLayers; k++) { mLayers[k].mAlphaLayer[aIndex] = (byte)(vContribSorted[(uint)mLayers[k].mActiveTextureIndex] * 255); } } } //ensure layers are sorted ensureProperSorting(); }
//CLM USED FOR EXPORT public unsafe void convertLayersToTexturingDataHandle(BTerrainLayerContainer input, List <Texture> tempAlphaTextures, BTerrainCompositeTexture output, int minXVert, int minZVert, int lod, int channelCount) { // BTerrainLayerContainer input = node.mLayerContainer; // BTerrainCompositeTexture output = node.getTextureData(lod).mCompositeTexture; Viewport vp = new Viewport(); vp.X = output.mXPixelOffset; vp.Y = output.mYPixelOffset; vp.Width = output.mWidth; vp.Height = output.mWidth; vp.MinZ = 0; vp.MaxZ = 1; BRenderDevice.getDevice().Viewport = vp; Microsoft.DirectX.Direct3D.Effect shader = TerrainGlobals.getTexturing().mCompositeShader; shader.Begin(0); shader.BeginPass(0); for (int i = 0; i < channelCount; i++) { for (int k = 0; k < output.mNumMips; k++) { //actually render Surface compositeTarget = null; float scale = 1; try { if (output.UsingAtlas == false) { compositeTarget = output.mTextures[i].GetSurfaceLevel(k); BRenderDevice.getDevice().SetRenderTarget(0, compositeTarget); } else { BTerrainCompositeAtlasTexture atlas = output.mAtlas; if (atlas.mTextures[i].Disposed == true) { atlas.reCreate(); } scale = atlas.mAtlasScale; compositeTarget = atlas.mTextures[i].GetSurfaceLevel(k); BRenderDevice.getDevice().SetRenderTarget(0, compositeTarget); } { BTerrainTexturingLayer.eLayerType lastType = BTerrainTexturingLayer.eLayerType.cLayer_Splat; float layerInc = 1.0f / (float)(cMaxNumBlends - 1);// (float)input.getNumLayers(); for (int j = 0; j < input.getNumLayers(); j++) { // BRenderDevice.getDevice().Clear(ClearFlags.ZBuffer | ClearFlags.Target, unchecked((int)0xFFFF0000), 1.0f, 0); //compose a splat shader.SetValue(mShaderContribOverride, 1); shader.SetValue(mShaderAlphaOverride, 1); if (input.giveLayer(j).mLayerType == BTerrainTexturingLayer.eLayerType.cLayer_Splat) { if (lastType != BTerrainTexturingLayer.eLayerType.cLayer_Splat) { shader.EndPass(); shader.BeginPass(0); lastType = BTerrainTexturingLayer.eLayerType.cLayer_Splat; } if (TerrainGlobals.getEditor().getRenderMode() == BTerrainEditor.eEditorRenderMode.cRenderTextureSelectRender) { if (TerrainGlobals.getEditor().getMode() != BTerrainEditor.eEditorMode.cModeTexEdit) { if (j == 0) { shader.SetValue(mShaderContribOverride, 0); shader.SetValue(mShaderAlphaOverride, 0); } else { continue; } } else { if (input.giveLayer(j).mActiveTextureIndex != TerrainGlobals.getTerrainFrontEnd().SelectedTextureIndex) { shader.SetValue(mShaderContribOverride, 0); } else { shader.SetValue(mShaderContribOverride, 1); } shader.SetValue(mShaderAlphaOverride, 0); } } float targetLayer = (float)(j * layerInc); shader.SetValue(mShaderNumLayersHandle, targetLayer); shader.SetValue(mShaderAlphaTexArrayHandle, tempAlphaTextures[j]); //lock in our target texture BTerrainActiveTextureContainer active = TerrainGlobals.getTexturing().getActiveTexture(input.giveLayer(j).mActiveTextureIndex); if (active == null) { compositeTarget.Dispose(); continue; } shader.SetValue(mShaderTexArrayHandle, active.mTexChannels[i].mTexture); float[] uvs = new float[2]; uvs[0] = active.mUScale; uvs[1] = active.mVScale; shader.SetValue(mShaderLayerUV, uvs); } else //compose a decal { if (lastType != BTerrainTexturingLayer.eLayerType.cLayer_Decal) { shader.EndPass(); shader.BeginPass(1); lastType = BTerrainTexturingLayer.eLayerType.cLayer_Decal; } bool doWhite = false; if (TerrainGlobals.getEditor().getRenderMode() == BTerrainEditor.eEditorRenderMode.cRenderTextureSelectRender) { if (TerrainGlobals.getEditor().getMode() == BTerrainEditor.eEditorMode.cModeTexEdit) { shader.SetValue(mShaderContribOverride, 0); } else if (TerrainGlobals.getEditor().getMode() == BTerrainEditor.eEditorMode.cModeDecalEdit) { doWhite = true; if (TerrainGlobals.getTexturing().getActiveDecalInstance(input.giveLayer(j).mActiveTextureIndex).mActiveDecalIndex != TerrainGlobals.getTerrainFrontEnd().SelectedDecalIndex) { shader.SetValue(mShaderContribOverride, 0); } else { shader.SetValue(mShaderContribOverride, 1); shader.SetValue(mShaderAlphaOverride, 1); } } } //Grab our decal instance BTerrainDecalInstance decal = getActiveDecalInstance(input.giveLayer(j).mActiveTextureIndex); if (decal == null) { compositeTarget.Dispose(); continue; } Vector4 selColor = new Vector4(1, 1, 1, 1); if (decal.mIsSelected) { selColor.Y = 0.75f; selColor.Z = 0.75f; } shader.SetValue(mShaderColorOverload, selColor); //grab the decal we care about BTerrainActiveDecalContainer active = getActiveDecal(decal.mActiveDecalIndex); if (active == null) { compositeTarget.Dispose(); continue; } if (doWhite) { shader.SetValue(mShaderAlphaTexArrayHandle, tempAlphaTextures[0]); } else { shader.SetValue(mShaderAlphaTexArrayHandle, tempAlphaTextures[j]); } shader.SetValue(mShaderAlphaTexDecalHandle, active.mTexChannels[(int)BTerrainTexturing.eTextureChannels.cOpacity].mTexture); shader.SetValue(mShaderTexDecalHandle, active.mTexChannels[i].mTexture); float[] decalDat = new float[4]; decalDat[0] = decal.mRotation; //compute our U and V offset float vertsToHighResPixelSpaceRatio = BTerrainTexturing.getTextureWidth() / BTerrainQuadNode.cMaxWidth; decalDat[1] = (decal.mTileCenter.X - (minXVert * vertsToHighResPixelSpaceRatio)) / BTerrainTexturing.getTextureWidth(); decalDat[2] = (decal.mTileCenter.Y - (minZVert * vertsToHighResPixelSpaceRatio)) / BTerrainTexturing.getTextureHeight(); decalDat[3] = 0; shader.SetValue(mShaderLayerDecalData, decalDat); float[] uvs = new float[2]; uvs[0] = decal.mUScale; uvs[1] = decal.mVScale; shader.SetValue(mShaderLayerUV, uvs); } shader.CommitChanges(); BRenderDevice.getDevice().Viewport = vp; BRenderDevice.getDevice().DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2); } shader.EndPass(); shader.BeginPass(0); } } catch (Direct3DXException e) { CoreGlobals.getErrorManager().SendToErrorWarningViewer("An error has occured during the compositing process"); } finally { if (compositeTarget != null) { compositeTarget.Dispose(); } } } } shader.EndPass(); shader.End(); }
public void toTextureArray(ref List <Texture> mTempAlphaTextures, int minXVert, int minZVert) { bool doBlendedFill = true; //lock in our alpha texture int slicePitch = (int)(BTerrainTexturing.getAlphaTextureWidth() * BTerrainTexturing.getAlphaTextureHeight()); int count = Math.Min(mTempAlphaTextures.Count, mLayers.Count); int width = (int)BTerrainTexturing.getAlphaTextureWidth(); int height = (int)BTerrainTexturing.getAlphaTextureHeight(); byte[] tempLargerImg = new byte[(width + 2) * (height + 2)]; byte[] bordered = new byte[width * height]; int i = 0; for (i = 0; i < count; i++) { if (mTempAlphaTextures[i] != null) { GraphicsStream texstream = mTempAlphaTextures[i].LockRectangle(0, LockFlags.None); if (i == 0) { for (int k = 0; k < slicePitch; k++) { texstream.WriteByte(255); } } else { if (doBlendedFill) { fillCreateLayer(mLayers[i].mAlphaLayer, mLayers[i].mActiveTextureIndex, mLayers[i].mLayerType, minXVert, minZVert, tempLargerImg, bordered); texstream.Write(bordered, 0, slicePitch); } else { texstream.Write(mLayers[i].mAlphaLayer, 0, slicePitch); } } mTempAlphaTextures[i].UnlockRectangle(0); texstream.Close(); } else { } } //we've got more layers than we've preallocated if (mTempAlphaTextures.Count < mLayers.Count) { int diff = mLayers.Count - mTempAlphaTextures.Count; for (int k = 0; k < diff; k++) { mTempAlphaTextures.Add(new Texture(BRenderDevice.getDevice(), (int)BTerrainTexturing.getAlphaTextureWidth(), (int)BTerrainTexturing.getAlphaTextureHeight(), 1, 0, Format.L8, Pool.Managed)); GraphicsStream texstream = mTempAlphaTextures[mTempAlphaTextures.Count - 1].LockRectangle(0, LockFlags.None); if (doBlendedFill) { fillCreateLayer(mLayers[i + k].mAlphaLayer, mLayers[i + k].mActiveTextureIndex, mLayers[i + k].mLayerType, minXVert, minZVert, tempLargerImg, bordered); texstream.Write(bordered, 0, slicePitch); } else { texstream.Write(mLayers[i + k].mAlphaLayer, 0, slicePitch); } mTempAlphaTextures[mTempAlphaTextures.Count - 1].UnlockRectangle(0); texstream.Close(); } } tempLargerImg = null; }