public static uint IntRead(BufferBase src, int n) { #if !AXIOM_SAFE_ONLY unsafe #endif { switch (n) { case 1: return(src.ToBytePointer()[0]); case 2: return(src.ToUShortPointer()[0]); case 3: var s = src.ToBytePointer(); #if AXIOM_BIG_ENDIAN return((uint)(s[0] << 16 | (s[1] << 8) | (s[2]))); #else return((uint)(s[0] | (s[1] << 8) | (s[2] << 16))); #endif case 4: return(src.ToUIntPointer()[0]); } return(0); // ? } }
public static void IntWrite(BufferBase dest, int n, uint value) { #if !AXIOM_SAFE_ONLY unsafe #endif { switch (n) { case 1: dest.ToBytePointer()[0] = (byte)value; break; case 2: dest.ToUShortPointer()[0] = (ushort)value; break; case 3: var d = dest.ToBytePointer(); #if AXIOM_BIG_ENDIAN d[0] = (byte)((value >> 16) & 0xFF); d[1] = (byte)((value >> 8) & 0xFF); d[2] = (byte)(value & 0xFF); #else d[2] = (byte)((value >> 16) & 0xFF); d[1] = (byte)((value >> 8) & 0xFF); d[0] = (byte)(value & 0xFF); #endif break; case 4: dest.ToUIntPointer()[0] = value; break; } } }
public void Convert(BufferBase input, BufferBase output, int offset) { #if !AXIOM_SAFE_ONLY unsafe #endif { var inputPtr = input.ToUShortPointer(); var outputPtr = output.ToBytePointer(); var inp = inputPtr[offset]; outputPtr[offset] = (byte)(inp >> 8); } }
public void Convert(BufferBase input, BufferBase output, int offset) { #if !AXIOM_SAFE_ONLY unsafe #endif { var inputPtr = input.ToBytePointer(); var outputPtr = output.ToUShortPointer(); var inp = inputPtr[offset]; outputPtr[offset] = (ushort)((((uint)inp) << 8) | (((uint)inp))); } }
/// <summary> /// Caches a face group and calculates texture lighting coordinates. /// </summary> protected int CacheLightGeometry( TextureLight light, BufferBase pIndexesBuf, BufferBase pTexLightMapsBuf, BufferBase pVerticesBuf, BspStaticFaceGroup faceGroup ) { #if !AXIOM_SAFE_ONLY unsafe #endif { // Skip sky always if ( faceGroup.isSky ) { return 0; } int idxStart = 0; int numIdx = 0; int vertexStart = 0; if ( faceGroup.type == FaceGroup.FaceList ) { idxStart = faceGroup.elementStart; numIdx = faceGroup.numElements; vertexStart = faceGroup.vertexStart; } else if ( faceGroup.type == FaceGroup.Patch ) { idxStart = faceGroup.patchSurf.IndexOffset; numIdx = faceGroup.patchSurf.CurrentIndexCount; vertexStart = faceGroup.patchSurf.VertexOffset; } else { // Unsupported face type return 0; } var idxSize = this.level.Indexes.IndexSize; var idxSrc = this.level.Indexes.Lock( idxStart*idxSize, numIdx*idxSize, BufferLocking.ReadOnly ); #if SILVERLIGHT var src = idxSrc.ToUShortPointer(); #else var src = idxSrc.ToUIntPointer(); #endif int maxIndex = 0; for ( int i = 0; i < numIdx; i++ ) { var index = (int)src[ i ]; if ( index > maxIndex ) { maxIndex = index; } } var vertexPos = new Vector3[maxIndex + 1]; var vertexIsStored = new bool[maxIndex + 1]; for ( int i = 0; i < numIdx; i++ ) { var index = (int)src[ i ]; var pVertices = pVerticesBuf.ToBspVertexPointer(); if ( !vertexIsStored[ index ] ) { vertexPos[ index ] = pVertices[ vertexStart + index ].position; vertexIsStored[ index ] = true; } pVerticesBuf.UnPin(); } Vector2[] texCoors; ColorEx[] colors; bool res = light.CalculateTexCoordsAndColors( faceGroup.plane, vertexPos, out texCoors, out colors ); if ( res ) { var pTexLightMaps = pTexLightMapsBuf.ToTextureLightMapPointer(); for ( int i = 0; i <= maxIndex; i++ ) { pTexLightMaps[ vertexStart + i ] = new TextureLightMap { color = Root.Instance.RenderSystem.ConvertColor( colors[ i ] ), textureLightMap = texCoors[ i ] }; } pTexLightMapsBuf.UnPin(); // Offset the indexes here // we have to do this now rather than up-front because the // indexes are sometimes reused to address different vertex chunks if ( this.level.Indexes.Type == IndexType.Size16 ) { var pIndexes = pIndexesBuf.ToUShortPointer(); for ( int i = 0; i < numIdx; i++ ) { pIndexes[ i ] = (ushort)( src[ i ] + vertexStart ); } } else { var pIndexes = pIndexesBuf.ToUIntPointer(); for ( int i = 0; i < numIdx; i++ ) { pIndexes[ i ] = (uint)( src[ i ] + vertexStart ); } } this.level.Indexes.Unlock(); // return number of elements return numIdx; } else { this.level.Indexes.Unlock(); return 0; } } }
/// <summary> /// Caches a face group for imminent rendering. /// </summary> protected int CacheGeometry( BufferBase indexes, BspStaticFaceGroup faceGroup ) { // Skip sky always if ( faceGroup.isSky ) { return 0; } int idxStart = 0; int numIdx = 0; int vertexStart = 0; if ( faceGroup.type == FaceGroup.FaceList ) { idxStart = faceGroup.elementStart; numIdx = faceGroup.numElements; vertexStart = faceGroup.vertexStart; } else if ( faceGroup.type == FaceGroup.Patch ) { idxStart = faceGroup.patchSurf.IndexOffset; numIdx = faceGroup.patchSurf.CurrentIndexCount; vertexStart = faceGroup.patchSurf.VertexOffset; } else { // Unsupported face type return 0; } #if !AXIOM_SAFE_ONLY unsafe #endif { // Offset the indexes here // we have to do this now rather than up-front because the // indexes are sometimes reused to address different vertex chunks var idxSize = this.level.Indexes.IndexSize; var idxSrc = this.level.Indexes.Lock( idxStart*idxSize, numIdx*idxSize, BufferLocking.ReadOnly ); if ( this.level.Indexes.Type == IndexType.Size16 ) { var src = idxSrc.ToUShortPointer(); var pIndexes = indexes.ToUShortPointer(); for ( int i = 0; i < numIdx; i++ ) { pIndexes[ i ] = (ushort)( src[ i ] + vertexStart ); } } else { var src = idxSrc.ToUIntPointer(); var pIndexes = indexes.ToUIntPointer(); for ( int i = 0; i < numIdx; i++ ) { pIndexes[ i ] = (uint)( src[ i ] + vertexStart ); } } this.level.Indexes.Unlock(); } // return number of elements return numIdx; }
public int StitchEdge( Neighbor neighbor, int hiLOD, int loLOD, bool omitFirstTri, bool omitLastTri, BufferBase ppIdx ) #endif { Debug.Assert( loLOD > hiLOD, "TerrainZoneRenderable.StitchEdge" ); /* Now do the stitching; we can stitch from any level to any level. The stitch pattern is like this for each pair of vertices in the lower LOD (excuse the poor ascii art): lower LOD *-----------* |\ \ 3 / /| |1\2 \ / 4/5| *--*--*--*--* higher LOD The algorithm is, for each pair of lower LOD vertices: 1. Iterate over the higher LOD vertices, generating tris connected to the first lower LOD vertex, up to and including 1/2 the span of the lower LOD over the higher LOD (tris 1-2). Skip the first tri if it is on the edge of the tile and that edge is to be stitched itself. 2. Generate a single tri for the middle using the 2 lower LOD vertices and the middle vertex of the higher LOD (tri 3). 3. Iterate over the higher LOD vertices from 1/2 the span of the lower LOD to the end, generating tris connected to the second lower LOD vertex (tris 4-5). Skip the last tri if it is on the edge of a tile and that edge is to be stitched itself. The same algorithm works for all edges of the patch; stitching is done clockwise so that the origin and steps used change, but the general approach does not. */ // Get pointer to be updated var pIdx = ppIdx.ToUShortPointer(); var idx = 0; // Work out the steps ie how to increment indexes // Step from one vertex to another in the high detail version var step = 1 << hiLOD; // Step from one vertex to another in the low detail version var superstep = 1 << loLOD; // Step half way between low detail steps var halfsuperstep = superstep >> 1; // Work out the starting points and sign of increments // We always work the strip clockwise int startx, starty, endx, rowstep; startx = starty = endx = rowstep = 0; var horizontal = false; switch ( neighbor ) { case Neighbor.NORTH: startx = starty = 0; endx = this.mOptions.tileSize - 1; rowstep = step; horizontal = true; break; case Neighbor.SOUTH: // invert x AND y direction, helps to keep same winding startx = starty = this.mOptions.tileSize - 1; endx = 0; rowstep = -step; step = -step; superstep = -superstep; halfsuperstep = -halfsuperstep; horizontal = true; break; case Neighbor.EAST: startx = 0; endx = this.mOptions.tileSize - 1; starty = this.mOptions.tileSize - 1; rowstep = -step; horizontal = false; break; case Neighbor.WEST: startx = this.mOptions.tileSize - 1; endx = 0; starty = 0; rowstep = step; step = -step; superstep = -superstep; halfsuperstep = -halfsuperstep; horizontal = false; break; } var numIndexes = 0; for ( var j = startx; j != endx; j += superstep ) { int k; for ( k = 0; k != halfsuperstep; k += step ) { var jk = j + k; //skip the first bit of the corner? if ( j != startx || k != 0 || !omitFirstTri ) { if ( horizontal ) { pIdx[ idx++ ] = Index( jk, starty + rowstep ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( jk + step, starty + rowstep ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( j, starty ); numIndexes++; // original order: 1 } else { pIdx[ idx++ ] = Index( starty + rowstep, jk ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( starty + rowstep, jk + step ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( starty, j ); numIndexes++; // original order: 1 } } } // Middle tri if ( horizontal ) { pIdx[ idx++ ] = Index( j + halfsuperstep, starty + rowstep ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( j + superstep, starty ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( j, starty ); numIndexes++; // original order: 1 } else { pIdx[ idx++ ] = Index( starty + rowstep, j + halfsuperstep ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( starty, j + superstep ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( starty, j ); numIndexes++; // original order: 1 } for ( k = halfsuperstep; k != superstep; k += step ) { var jk = j + k; if ( j != endx - superstep || k != superstep - step || !omitLastTri ) { if ( horizontal ) { pIdx[ idx++ ] = Index( jk, starty + rowstep ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( jk + step, starty + rowstep ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( j + superstep, starty ); numIndexes++; // original order: 1 } else { pIdx[ idx++ ] = Index( starty + rowstep, jk ); numIndexes++; // original order: 2 pIdx[ idx++ ] = Index( starty + rowstep, jk + step ); numIndexes++; // original order: 3 pIdx[ idx++ ] = Index( starty, j + superstep ); numIndexes++; // original order: 1 } } } } ppIdx.Ptr += idx*sizeof ( ushort ); return numIndexes; }
internal static void PopulateIndexBuffer( BufferBase pIndexes, ushort batchSize, ushort vdatasize, int vertexIncrement, ushort xoffset, ushort yoffset, ushort numSkirtRowsCols, ushort skirtRowColSkip ) { /* For even / odd tri strip rows, triangles are this shape: 6---7---8 | \ | \ | 3---4---5 | / | / | 0---1---2 Note how vertex rows count upwards. In order to match up the anti-clockwise winding and this upward transitioning list, we need to start from the right hand side. So we get (2,5,1,4,0,3) etc on even lines (right-left) and (3,6,4,7,5,8) etc on odd lines (left-right). At the turn, we emit the end index twice, this forms a degenerate triangle, which lets us turn without any artefacts. So the full list in this simple case is (2,5,1,4,0,3,3,6,4,7,5,8) Skirts are part of the same strip, so after finishing on 8, where sX is the skirt vertex corresponding to main vertex X, we go anticlockwise around the edge, (s8,7,s7,6,s6) to do the top skirt, then (3,s3,0,s0),(1,s1,2,s2),(5,s5,8,s8) to finish the left, bottom, and right skirts respectively. */ // to issue a complete row, it takes issuing the upper and lower row // and one extra index, which is the degenerate triangle and also turning // around the winding #if !AXIOM_SAFE_ONLY unsafe #endif { var rowSize = vdatasize*vertexIncrement; var numRows = batchSize - 1; var pI = pIndexes.ToUShortPointer(); var offset = 0; // Start on the right var currentVertex = (ushort)( ( batchSize - 1 )*vertexIncrement ); // but, our quad area might not start at 0 in this vertex data // offsets are at main terrain resolution, remember var columnStart = xoffset; var rowStart = yoffset; currentVertex += (ushort)( rowStart*vdatasize + columnStart ); var rightToLeft = true; for ( ushort r = 0; r < numRows; ++r ) { for ( var c = 0; c < batchSize; ++c ) { pI[ offset++ ] = currentVertex; pI[ offset++ ] = (ushort)( currentVertex + rowSize ); // don't increment / decrement at a border, keep this vertex for next // row as we 'snake' across the tile if ( c + 1 < batchSize ) { currentVertex = rightToLeft ? (ushort)( currentVertex - vertexIncrement ) : (ushort)( currentVertex + vertexIncrement ); } } rightToLeft = !rightToLeft; currentVertex += (ushort)rowSize; // issue one extra index to turn winding around pI[ offset++ ] = currentVertex; } // Skirts for ( ushort s = 0; s < 4; ++s ) { // edgeIncrement is the index offset from one original edge vertex to the next // in this row or column. Columns skip based on a row size here // skirtIncrement is the index offset from one skirt vertex to the next, // because skirts are packed in rows/cols then there is no row multiplier for // processing columns int edgeIncrement = 0, skirtIncrement = 0; switch ( s ) { case 0: // top edgeIncrement = -(int)vertexIncrement; skirtIncrement = -(int)vertexIncrement; break; case 1: // left edgeIncrement = -(int)rowSize; skirtIncrement = -(int)vertexIncrement; break; case 2: // bottom edgeIncrement = (int)vertexIncrement; skirtIncrement = (int)vertexIncrement; break; case 3: // right edgeIncrement = (int)rowSize; skirtIncrement = (int)vertexIncrement; break; } // Skirts are stored in contiguous rows / columns (rows 0/2, cols 1/3) var skirtIndex = CalcSkirtVertexIndex( currentVertex, vdatasize, ( s%2 ) != 0, numSkirtRowsCols, skirtRowColSkip ); for ( var c = 0; c < batchSize - 1; ++c ) { pI[ offset++ ] = currentVertex; pI[ offset++ ] = skirtIndex; currentVertex += (ushort)edgeIncrement; skirtIndex += (ushort)skirtIncrement; } if ( s == 3 ) { // we issue an extra 2 indices to finish the skirt off pI[ offset++ ] = currentVertex; pI[ offset++ ] = skirtIndex; currentVertex += (ushort)edgeIncrement; skirtIndex += (ushort)skirtIncrement; } } } }
public static uint IntRead( BufferBase src, int n ) { #if !AXIOM_SAFE_ONLY unsafe #endif { switch ( n ) { case 1: return src.ToBytePointer()[ 0 ]; case 2: return src.ToUShortPointer()[ 0 ]; case 3: var s = src.ToBytePointer(); #if AXIOM_BIG_ENDIAN return (uint)( s[ 0 ] << 16 | ( s[ 1 ] << 8 ) | ( s[ 2 ] ) ); #else return (uint)( s[ 0 ] | ( s[ 1 ] << 8 ) | ( s[ 2 ] << 16 ) ); #endif case 4: return src.ToUIntPointer()[ 0 ]; } return 0; // ? } }
public static void IntWrite( BufferBase dest, int n, uint value ) { #if !AXIOM_SAFE_ONLY unsafe #endif { switch ( n ) { case 1: dest.ToBytePointer()[ 0 ] = (byte)value; break; case 2: dest.ToUShortPointer()[ 0 ] = (ushort)value; break; case 3: var d = dest.ToBytePointer(); #if AXIOM_BIG_ENDIAN d[ 0 ] = (byte)( ( value >> 16 ) & 0xFF ); d[ 1 ] = (byte)( ( value >> 8 ) & 0xFF ); d[ 2 ] = (byte)( value & 0xFF ); #else d[ 2 ] = (byte)( ( value >> 16 ) & 0xFF ); d[ 1 ] = (byte)( ( value >> 8 ) & 0xFF ); d[ 0 ] = (byte)( value & 0xFF ); #endif break; case 4: dest.ToUIntPointer()[ 0 ] = value; break; } } }