/// <summary>
        /// Adds RDB flat to scene node.
        /// </summary>
        /// <param name="obj">RdbObject.</param>
        /// <param name="blockNode">BlockNode.</param>
        private void AddRDBFlat(DFBlock.RdbObject obj, BlockNode blockNode)
        {
            // Get flat type
            BillboardNode.BillboardType billboardType =
                GetFlatType(obj.Resources.FlatResource.TextureArchive);

            // Add light if needed

            // Load flat
            int     textureKey;
            Vector2 startSize;
            Vector2 finalSize;

            if (true == LoadDaggerfallFlat(
                    obj.Resources.FlatResource.TextureArchive,
                    obj.Resources.FlatResource.TextureRecord,
                    TextureManager.TextureCreateFlags.Dilate |
                    TextureManager.TextureCreateFlags.PreMultiplyAlpha,
                    out textureKey,
                    out startSize,
                    out finalSize))
            {
                // Foliage (TEXTURE.500 and up) do not seem to use scaling
                // in dungeons. Revert scaling.
                if (obj.Resources.FlatResource.TextureArchive > 499)
                {
                    finalSize = startSize;
                }

                // Calcuate position
                Vector3 position = new Vector3(
                    obj.XPos,
                    -obj.YPos,
                    -obj.ZPos);

                // Create billboard node
                BillboardNode billboardNode = new BillboardNode(
                    billboardType,
                    textureKey,
                    finalSize);
                billboardNode.Position = position;
                blockNode.Add(billboardNode);

                // Add point light node
                if (billboardType == BillboardNode.BillboardType.Light)
                {
                    AddPointLight(position, PointLightNode.DungeonRadius, blockNode);
                }
            }
        }
        /// <summary>
        /// Constructs a scene node from the specified RMB block.
        /// </summary>
        /// <param name="block">DFBlock.</param>
        /// <param name="climate">Climate settings.</param>
        /// <returns>BlockNode.</returns>
        private BlockNode BuildRMBNode(ref DFBlock block, DFLocation.ClimateSettings climate)
        {
            // Create parent block node
            BlockNode blockNode = new BlockNode(block);

            // Add child nodes
            AddRMBModels(ref block, blockNode);
            AddRMBMiscModels(ref block, blockNode);
            AddRMBGroundPlane(ref block, blockNode, climate);
            AddRMBMiscFlats(ref block, blockNode);
            AddRMBSceneryFlats(ref block, blockNode, climate.SceneryArchive);

            return(blockNode);
        }
        /// <summary>
        /// Constructs a scene node from the specified RDB block.
        /// </summary>
        /// <param name="block">DFBlock.</param>
        /// <returns>BlockNode.</returns>
        private BlockNode BuildRDBNode(ref DFBlock block)
        {
            // Create parent block node
            BlockNode blockNode = new BlockNode(block);

            // Clear action link dictionary
            actionLinkDict.Clear();

            // Iterate through object groups
            int groupIndex = 0;

            foreach (DFBlock.RdbObjectRoot group in block.RdbBlock.ObjectRootList)
            {
                // Skip empty object groups
                if (null == group.RdbObjects)
                {
                    groupIndex++;
                    continue;
                }

                // Iterate through objects in this group
                foreach (DFBlock.RdbObject obj in group.RdbObjects)
                {
                    // Filter by type
                    switch (obj.Type)
                    {
                    case DFBlock.RdbResourceTypes.Model:
                        AddRDBModel(ref block, obj, blockNode, groupIndex);
                        break;

                    case DFBlock.RdbResourceTypes.Flat:
                        AddRDBFlat(obj, blockNode);
                        break;

                    default:
                        // Only drawing models and flats for now
                        break;
                    }
                }

                // Increment group index
                groupIndex++;
            }

            // Link action nodes
            LinkActionNodes();

            return(blockNode);
        }
        /// <summary>
        /// Adds miscellaneous RMB models to block node.
        /// </summary>
        /// <param name="block">DFBlock</param>
        /// <param name="blockNode">BlockNode.</param>
        private void AddRMBMiscModels(ref DFBlock block, BlockNode blockNode)
        {
            // Iterate through all misc records
            float degrees;

            foreach (DFBlock.RmbBlock3dObjectRecord obj in block.RmbBlock.Misc3dObjectRecords)
            {
                // Create misc record node
                SceneNode miscNode = CreateModelNode(obj.ModelIdNum);
                degrees           = obj.YRotation / rotationDivisor;
                miscNode.Position = new Vector3(obj.XPos, -obj.YPos, -rmbSide + -obj.ZPos);
                miscNode.Rotation = new Vector3(0f, MathHelper.ToRadians(degrees), 0f);
                blockNode.Add(miscNode);
            }
        }
        /// <summary>
        /// Creates a new block node.
        /// </summary>
        /// <param name="name">Block name.</param>
        /// <param name="climate">Climate settings.</param>
        /// <param name="clearGroundTextures">Clear ground plane texture dictionary.</param>
        /// <returns>BlockNode.</returns>
        public BlockNode CreateBlockNode(string name, DFLocation.ClimateSettings?climate, bool clearGroundTextures)
        {
            // Load block
            DFBlock block;

            if (!LoadDaggerfallBlock(name, out block))
            {
                return(null);
            }

            // Set default world climate
            if (climate == null)
            {
                climate = MapsFile.GetWorldClimateSettings(defaultWorldClimate);
            }

            // Reset ground plane texture cache
            if (clearGroundTextures)
            {
                textureManager.ClearGroundTextures();
            }

            // Build node
            BlockNode node = null;

            switch (block.Type)
            {
            case DFBlock.BlockTypes.Rmb:
                textureManager.ClimateType = climate.Value.ClimateType;
                node = BuildRMBNode(ref block, climate.Value);
                break;

            case DFBlock.BlockTypes.Rdb:
                textureManager.ClimateType = DFLocation.ClimateBaseType.None;
                node = BuildRDBNode(ref block);
                break;
            }

            return(node);
        }
        /// <summary>
        /// Adds RDB model to block node.
        /// </summary>
        /// <param name="block">DFBlock.</param>
        /// <param name="obj">RdbObject.</param>
        /// <param name="blockNode">BlockNode.</param>
        /// <param name="groupIndex">Group index.</param>
        private void AddRDBModel(ref DFBlock block, DFBlock.RdbObject obj, BlockNode blockNode, int groupIndex)
        {
            // Get model reference index, desc, and id
            int    modelReference   = obj.Resources.ModelResource.ModelIndex;
            string modelDescription = block.RdbBlock.ModelReferenceList[modelReference].Description;
            uint   modelId          = block.RdbBlock.ModelReferenceList[modelReference].ModelIdNum;

            // Get rotation angle for each axis
            float degreesX = obj.Resources.ModelResource.XRotation / rotationDivisor;
            float degreesY = obj.Resources.ModelResource.YRotation / rotationDivisor;
            float degreesZ = -obj.Resources.ModelResource.ZRotation / rotationDivisor;

            // Calcuate position
            Vector3 position = new Vector3(
                obj.XPos,
                -obj.YPos,
                -obj.ZPos);

            // Calculate rotation
            Vector3 rotation = new Vector3(
                MathHelper.ToRadians(degreesX),
                MathHelper.ToRadians(degreesY),
                MathHelper.ToRadians(degreesZ));

            // Create model node
            ModelNode modelNode = CreateModelNode(modelId);

            modelNode.Position = position;
            modelNode.Rotation = rotation;
            blockNode.Add(modelNode);

            // Setup actions for this node
            CreateModelAction(
                obj.Resources.ModelResource.ActionResource,
                modelNode,
                modelDescription,
                groupIndex,
                obj.Index);
        }