/// <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> /// Creates a specialised texture light. /// </summary> public override Light CreateLight(string name) { // create a new texture light and add it to our internal list TextureLight light = new TextureLight(name, this); // add the light to the list lightList.Add(name, light); // add it in the bsp tree NotifyObjectMoved(light, light.Position); return light; }
/// <summary> /// Caches a face group and calculates texture lighting coordinates. /// </summary> unsafe protected int CacheLightGeometry( TextureLight light, uint* pIndexes, TextureLightMap* pTexLightMaps, BspVertex* pVertices, 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; } uint* src = (uint*)level.Indexes.Lock( idxStart * sizeof( uint ), numIdx * sizeof( uint ), BufferLocking.ReadOnly ); int maxIndex = 0; for ( int i = 0; i < numIdx; i++ ) { int index = (int)*( src + i ); if ( index > maxIndex ) maxIndex = index; } Vector3[] vertexPos = new Vector3[ maxIndex + 1 ]; bool[] vertexIsStored = new bool[ maxIndex + 1 ]; for ( int i = 0; i < numIdx; i++ ) { uint index = *( src + i ); if ( !vertexIsStored[ index ] ) { vertexPos[ index ] = ( *( pVertices + vertexStart + index ) ).position; vertexIsStored[ index ] = true; } } Vector2[] texCoors; ColorEx[] colors; bool res = light.CalculateTexCoordsAndColors( faceGroup.plane, vertexPos, out texCoors, out colors ); if ( res ) { for ( int i = 0; i <= maxIndex; i++ ) { pTexLightMaps[ vertexStart + i ].color = Root.Instance.RenderSystem.ConvertColor( colors[ i ] ); pTexLightMaps[ vertexStart + i ].textureLightMap = texCoors[ i ]; } // 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 for ( int i = 0; i < numIdx; i++ ) *pIndexes++ = (uint)( *src++ + vertexStart ); level.Indexes.Unlock(); // return number of elements return numIdx; } else { level.Indexes.Unlock(); return 0; } }
/// <summary> /// Walks the BSP tree looking for the node which the camera is in, and tags any geometry /// which is in a visible leaf for later processing. /// </summary> protected BspNode WalkTree(Camera camera, bool onlyShadowCasters) { // Locate the leaf node where the camera is located BspNode cameraNode = level.FindLeaf(camera.DerivedPosition); matFaceGroupMap.Clear(); faceGroupChecked = new bool[level.FaceGroups.Length]; TextureLight[] lights = new TextureLight[lightList.Count]; BspNode[] lightNodes = new BspNode[lightList.Count]; Sphere[] lightSpheres = new Sphere[lightList.Count]; // The base SceneManager uses this for shadows. // The BspSceneManager uses this for texture lighting as well. if (shadowTechnique == ShadowTechnique.None) { lightsAffectingFrustum.Clear(); lightAddedToFrustum = new bool[lightList.Count]; } for (int lp=0; lp < lightList.Count; lp++) { TextureLight light = (TextureLight) lightList[lp]; lights[lp] = light; lightNodes[lp] = (BspNode) level.objectToNodeMap.FindFirst(light); if (light.Type != LightType.Directional) { // treating spotlight as point for simplicity lightSpheres[lp] = new Sphere(light.DerivedPosition, light.AttenuationRange); } } // Scan through all the other leaf nodes looking for visibles int i = level.NumNodes - level.LeafStart; int p = level.LeafStart; BspNode node; while(i-- > 0) { node = level.Nodes[p]; if(level.IsLeafVisible(cameraNode, node)) { // Visible according to PVS, check bounding box against frustum FrustumPlane plane; if(camera.IsObjectVisible(node.BoundingBox, out plane)) { if (!onlyShadowCasters) { for (int lp=0; lp < lights.Length; lp++) { if (lightAddedToFrustum[lp] || !lights[lp].IsVisible) continue; if (level.IsLeafVisible(lightNodes[lp], node) && (lights[lp].Type == LightType.Directional || lightSpheres[lp].Intersects(node.BoundingBox))) { // This is set so that the lights are rendered with ascending // Priority order. lights[lp].TempSquaredDist = lights[lp].Priority; lightsAffectingFrustum.Add(lights[lp]); lightAddedToFrustum[lp] = true; } } } ProcessVisibleLeaf(node, camera, onlyShadowCasters); if(showNodeAABs) AddBoundingBox(node.BoundingBox, true); } } p++; } return cameraNode; }