Beispiel #1
0
        protected internal void updateBounds()
        {
            var p  = _transform.DerivedPosition;
            var hs = getHalfSize();

            _bounds.SetExtents(p - hs, p + hs);
            _needsUpdate = false;
        }
        private void transformupdate()
        {
            var p     = gameObject.transform.DerivedPosition;
            var min   = size * -origin + p;
            var max   = size * (-origin + Vector2.One) + p;
            var pivot = p;

            aabb.SetExtents(min, max);
            aabb.RotateAndContain(pivot, gameObject.transform.DerivedOrientation);
        }
        /// <summary>
        ///		Utility method for extruding a bounding box.
        /// </summary>
        /// <param name="box">Original bounding box, will be updated in-place.</param>
        /// <param name="lightPosition">4D light position in object space, when w=0.0f this
        /// represents a directional light</param>
        /// <param name="extrudeDistance">The distance to extrude.</param>
        protected virtual void ExtrudeBounds(AxisAlignedBox box, Vector4 lightPosition, float extrudeDistance)
        {
            Vector3 extrusionDir = Vector3.Zero;

            if (lightPosition.w == 0)
            {
                extrusionDir.x = -lightPosition.x;
                extrusionDir.y = -lightPosition.y;
                extrusionDir.z = -lightPosition.z;
                extrusionDir.Normalize();
                extrusionDir *= extrudeDistance;
                box.SetExtents(box.Minimum + extrusionDir, box.Maximum + extrusionDir);
            }
            else
            {
                Vector3[] corners = box.Corners;
                Vector3   vmin    = new Vector3();
                Vector3   vmax    = new Vector3();

                for (int i = 0; i < 8; i++)
                {
                    extrusionDir.x = corners[i].x - lightPosition.x;
                    extrusionDir.y = corners[i].y - lightPosition.y;
                    extrusionDir.z = corners[i].z - lightPosition.z;
                    extrusionDir.Normalize();
                    extrusionDir *= extrudeDistance;
                    Vector3 res = corners[i] + extrusionDir;

                    if (i == 0)
                    {
                        vmin = res;
                        vmax = res;
                    }
                    else
                    {
                        vmin.Floor(res);
                        vmax.Ceil(res);
                    }
                }

                box.SetExtents(vmin, vmax);
            }
        }
Beispiel #4
0
        public void Init(ref SceneNode ParentSceneNode, int tableX, int tableZ, int tileX, int tileZ)
        {
            init = true;

            Vector3 ParentPos = ParentSceneNode.DerivedPosition;

            info.PageX = tableX;
            info.PageZ = tableZ;
            info.TileX = tileX;
            info.TileZ = tileZ;
            // Calculate the offset from the parent for this tile

            Vector3 scale = Options.Instance.Scale;
            float   endx  = Options.Instance.TileSize * scale.x;
            float   endz  = Options.Instance.TileSize * scale.z;

            info.PosX = info.TileX * endx;
            info.PosZ = info.TileZ * endz;

            name          = String.Format("tile[{0},{1}][{2},{3}]", info.PageX, info.PageZ, info.TileX, info.TileZ);
            tileSceneNode = (SceneNode)ParentSceneNode.CreateChild(name);

            // figure out scene node position within parent
            tileSceneNode.Position = new Vector3(info.PosX, 0, info.PosZ);

            tileSceneNode.AttachObject(this);

            float MaxHeight = Data2DManager.Instance.GetMaxHeight(info.PageX, info.PageZ);

            bounds.SetExtents(new Vector3(0, 0, 0), new Vector3((float)(endx), MaxHeight, (float)(endz)));

            //Change Zone of this page
            boundsExt.SetExtents(new Vector3(-endx * 0.5f, -MaxHeight * 0.5f, -endz * 0.5f), new Vector3(endx * 1.5f, MaxHeight * 1.5f, endz * 1.5f));

            //Change Zone of this page

            this.worldAABB.SetExtents(new Vector3(info.PosX + ParentPos.x, 0, info.PosZ + ParentPos.z), new Vector3((float)(info.PosX + ParentPos.x + endx), MaxHeight, (float)(info.PosZ + ParentPos.z + endz)));
            //this.worldBounds.SetExtents( new Vector3(info.PosX + ParentPos.x ,0, info.PosZ + ParentPos.z), new Vector3((float)( info.PosX + ParentPos.x + endx), MaxHeight, (float)( info.PosZ + ParentPos.z + endz) ));

            for (long i = 0; i < 4; i++)
            {
                neighbors[i] = null;
            }
            //force update in scene node
            //tileSceneNode.update( true, true );
            tileSceneNode.NeedUpdate();
            loaded = false;
        }
Beispiel #5
0
        public Page(long TableX, long TableZ)

        {
            isLoaded    = false;
            isPreLoaded = false;

            tableX = TableX;
            tableZ = TableZ;

            numTiles = (long)((float)Options.Instance.PageSize / Options.Instance.TileSize);
            pageNode = null;

            long size = Options.Instance.PageSize - 1;
            // Boundaries of this page
            // the middle page is at world coordinates 0,0
            float factorX = size * Options.Instance.Scale.x;
            float factorZ = size * Options.Instance.Scale.z;

            iniX = (tableX + tableX - Options.Instance.World_Width) / 2.0f * factorX;
            iniZ = (tableZ + tableZ - Options.Instance.World_Height) / 2.0f * factorZ;
            float EndX      = iniX + factorX;
            float EndZ      = iniZ + factorZ;
            float MaxHeight = Data2DManager.Instance.GetMaxHeight(tableX, tableZ);
            float chgfactor = Options.Instance.Change_Factor;

            boundsExt = new AxisAlignedBox();
            boundsExt.SetExtents(new Vector3(( float )(iniX),
                                             0,
                                             ( float )(iniZ)),
                                 new Vector3(( float )(EndX),
                                             MaxHeight,
                                             ( float )(EndZ)));
            //Change Zone of this page
            boundsInt = new AxisAlignedBox();
            boundsInt.SetExtents(new Vector3(( float )(iniX + chgfactor),
                                             0,
                                             ( float )(iniZ + chgfactor)),
                                 new Vector3(( float )(EndX - chgfactor),
                                             MaxHeight,
                                             ( float )(EndZ - chgfactor)));

            neighbors = new Page[4];
            for (long i = 0; i < 4; i++)
            {
                neighbors[i] = null;
            }
        }
        /// <summary>
        ///		Sets the corners of the rectangle, in relative coordinates.
        /// </summary>
        /// <param name="left">Left position in screen relative coordinates, -1 = left edge, 1.0 = right edge.</param>
        /// <param name="top">Top position in screen relative coordinates, 1 = top edge, -1 = bottom edge.</param>
        /// <param name="right">Position in screen relative coordinates.</param>
        /// <param name="bottom">Position in screen relative coordinates.</param>
        public void SetCorners(float left, float top, float right, float bottom)
        {
            float[] data = new float[] {
                left, top, -1,
                left, bottom, -1,
                right, top, -1,
                right, bottom, -1
            };

            HardwareVertexBuffer buffer =
                vertexData.vertexBufferBinding.GetBuffer(POSITION);

            buffer.WriteData(0, buffer.Size, data, true);

            box = new AxisAlignedBox();
            box.SetExtents(new Vector3(left, top, 0), new Vector3(right, bottom, 0));
        }
Beispiel #7
0
        /// <summary>
        ///		Sets the corners of the rectangle, in relative coordinates.
        /// </summary>
        /// <param name="left">Left position in screen relative coordinates, -1 = left edge, 1.0 = right edge.</param>
        /// <param name="top">Top position in screen relative coordinates, 1 = top edge, -1 = bottom edge.</param>
        /// <param name="right">Position in screen relative coordinates.</param>
        /// <param name="bottom">Position in screen relative coordinates.</param>
        /// <param name="updateAABB"></param>
        public void SetCorners(float left, float top, float right, float bottom, bool updateAABB)
        {
            var data = new float[]
            {
                left, top, -1, left, bottom, -1, right, top, -1,            // Fix for Issue #1187096
                right, bottom, -1
            };

            var buffer = vertexData.vertexBufferBinding.GetBuffer(POSITION);

            buffer.WriteData(0, buffer.Size, data, true);

            if (updateAABB)
            {
                box = new AxisAlignedBox();
                box.SetExtents(new Vector3(left, top, 0), new Vector3(right, bottom, 0));
            }
        }
Beispiel #8
0
        public bool buttonold(int renderQueue, float scale, AxisAlignedBox rect, BmFont font, float depth, string text)
        {
            rect.SetExtents(rect.minVector + groupOffset, rect.maxVector + groupOffset + buttonPadding + buttonPadding);
            var mp = Root.instance.input.MousePosition;
            var gp = screenToGUI(mp);

            var isOver = rect.Contains(gp);

            var bg     = isOver ? skin.button.hover.texture : skin.button.normal.texture;
            var border = isOver ? buttonBorderHover : buttonBorder;
            var color  = isOver ? buttonTextColorHover : buttonTextColor;

            //Root.instance.graphics.beginScissor(rect);
            Root.instance.graphics.Draw(renderQueue, rect, buttonBackground, depth);
            Root.instance.graphics.DrawRect(renderQueue, rect, buttonBorder);
            Root.instance.graphics.DrawText(renderQueue, font, scale, rect.minVector + buttonPadding, text, color, depth);
            //Root.instance.graphics.endScissor();

            return(Root.instance.input.IsLeftMouseDown && isOver);

            return(false);
        }
Beispiel #9
0
        /// <summary>
        ///     IsObjectVisible() function for portals.
        /// </summary>
        /// <remarks>
        ///     Everything needs to be updated spatially before this function is
        ///     called including portal corners, frustum planes, etc.
        /// </remarks>
        /// <param name="portal">
        ///     The <see cref="Portal"/> to check visibility against.
        /// </param>
        /// <returns>
        ///     true if the Portal is visible.
        /// </returns>
        public bool IsObjectVisible(Portal portal)
        {
            // if portal isn't open, it's not visible
            if (!portal.IsOpen)
            {
                return(false);
            }

            // if the frustum has no planes, just return true
            if (this.mActiveCullingPlanes.Count == 0)
            {
                return(true);
            }
            // check if this portal is already in the list of active culling planes (avoid
            // infinite recursion case)
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                if (plane.Portal == portal)
                {
                    return(false);
                }
            }

            // if portal is of type AABB or Sphere, then use simple bound check against planes
            if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_AABB)
            {
                var aabb = new AxisAlignedBox();
                aabb.SetExtents(portal.getDerivedCorner(0), portal.getDerivedCorner(1));
                return(IsObjectVisible(aabb));
            }
            else if (portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE)
            {
                return(IsObjectVisible(portal.getDerivedSphere()));
            }

            // check if the portal norm is facing the frustum
            Vector3 frustumToPortal = portal.getDerivedCP() - this.mOrigin;
            Vector3 portalDirection = portal.getDerivedDirection();
            Real    dotProduct      = frustumToPortal.Dot(portalDirection);

            if (dotProduct > 0)
            {
                // portal is faced away from Frustum
                return(false);
            }

            // check against frustum culling planes
            bool visible_flag;

            // Check originPlane if told to
            if (this.mUseOriginPlane)
            {
                // set the visible flag to false
                visible_flag = false;
                // we have to check each corner of the portal
                for (int corner = 0; corner < 4; corner++)
                {
                    PlaneSide side = this.mOriginPlane.GetSide(portal.getDerivedCorner(corner));
                    if (side != PlaneSide.Negative)
                    {
                        visible_flag = true;
                    }
                }
                // if the visible_flag is still false, then the origin plane
                // culled all the portal points
                if (visible_flag == false)
                {
                    // ALL corners on negative side therefore out of view
                    return(false);
                }
            }

            // For each active culling plane, see if all portal points are on the negative
            // side. If so, the portal is not visible
            foreach (PCPlane plane in this.mActiveCullingPlanes)
            {
                visible_flag = false;
                // we have to check each corner of the portal
                for (int corner = 0; corner < 4; corner++)
                {
                    PlaneSide side = plane.GetSide(portal.getDerivedCorner(corner));
                    if (side != PlaneSide.Negative)
                    {
                        visible_flag = true;
                    }
                }
                // if the visible_flag is still false, then this plane
                // culled all the portal points
                if (visible_flag == false)
                {
                    // ALL corners on negative side therefore out of view
                    return(false);
                }
            }

            // no plane culled all the portal points and the norm
            // was facing the frustum, so this portal is visible
            return(true);
        }
Beispiel #10
0
 public AxisAlignedBox GetBoundingBox()
 {
     aabb.SetExtents(new Vector3(position.x - radius, position.y - radius, position.z - radius), new Vector3(position.x + radius, position.y + radius, position.z + radius));
     return(aabb);
 }
        public void Init(TerrainOptions options)
        {
            this.options = options;

            numMipMaps = options.maxMipmap;
            size       = options.size;

            terrain             = new VertexData();
            terrain.vertexStart = 0;
            // Turbo: appended factor 3
            //        Not sure about that, but without that the terrain manager seems
            //        to mess up memory because of buffer overruns
            //terrain.vertexCount = options.size * options.size;
            terrain.vertexCount = options.size * options.size * 3;

            VertexDeclaration   decl    = terrain.vertexDeclaration;
            VertexBufferBinding binding = terrain.vertexBufferBinding;

            int offset = 0;

            // Position/Normal
            decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position);
            decl.AddElement(NORMAL, 0, VertexElementType.Float3, VertexElementSemantic.Normal);

            // TexCoords
            decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0);
            offset += VertexElement.GetTypeSize(VertexElementType.Float2);
            decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1);
            offset += VertexElement.GetTypeSize(VertexElementType.Float2);
            // TODO: Color

            HardwareVertexBuffer buffer =
                HardwareBufferManager.Instance.CreateVertexBuffer(
                    decl.GetVertexSize(POSITION),
                    terrain.vertexCount,
                    BufferUsage.StaticWriteOnly, true);

            binding.SetBinding(POSITION, buffer);


            buffer =
                HardwareBufferManager.Instance.CreateVertexBuffer(
                    decl.GetVertexSize(NORMAL),
                    terrain.vertexCount,
                    BufferUsage.StaticWriteOnly, true);

            binding.SetBinding(NORMAL, buffer);

            buffer =
                HardwareBufferManager.Instance.CreateVertexBuffer(
                    offset,
                    terrain.vertexCount,
                    BufferUsage.StaticWriteOnly, true);

            binding.SetBinding(TEXCOORD, buffer);

            minLevelDistSqr = new float[numMipMaps];

            int endx = options.startx + options.size;
            int endz = options.startz + options.size;

            // TODO: name buffers different so we can unlock
            HardwareVertexBuffer posBuffer = binding.GetBuffer(POSITION);
            IntPtr pos = posBuffer.Lock(BufferLocking.Discard);

            HardwareVertexBuffer texBuffer = binding.GetBuffer(TEXCOORD);
            IntPtr tex = texBuffer.Lock(BufferLocking.Discard);

            float min = 99999999, max = 0;

            unsafe {
                float *posPtr = (float *)pos.ToPointer();
                float *texPtr = (float *)tex.ToPointer();

                int posCount = 0;
                int texCount = 0;

                for (int j = options.startz; j < endz; j++)
                {
                    for (int i = options.startx; i < endx; i++)
                    {
                        float height = options.GetWorldHeight(i, j) * options.scaley;

                        posPtr[posCount++] = (float)i * options.scalex;
                        posPtr[posCount++] = height;
                        posPtr[posCount++] = (float)j * options.scalez;

                        texPtr[texCount++] = (float)i / (float)options.worldSize;
                        texPtr[texCount++] = (float)j / (float)options.worldSize;

                        texPtr[texCount++] = ((float)i / (float)options.size) * (float)options.detailTile;
                        texPtr[texCount++] = ((float)j / (float)options.size) * (float)options.detailTile;

                        if (height < min)
                        {
                            min = height;
                        }

                        if (height > max)
                        {
                            max = height;
                        }
                    } // for i
                }     // for j
            }         // unsafe

            // unlock the buffers
            posBuffer.Unlock();
            texBuffer.Unlock();

            box.SetExtents(
                new Vector3((float)options.startx * options.scalex, min, (float)options.startz * options.scalez),
                new Vector3((float)(endx - 1) * options.scalex, max, (float)(endz - 1) * options.scalez));


            center = new Vector3((options.startx * options.scalex + endx - 1) / 2,
                                 (min + max) / 2,
                                 (options.startz * options.scalez + endz - 1) / 2);

            float C = CalculateCFactor();

            CalculateMinLevelDist2(C);
        }
Beispiel #12
0
        public void drawLines()
        {
            //resizeing code adapted from
            //http://www.ogre3d.org/wiki/index.php/DynamicGrowingBuffers
            HardwareVertexBufferSharedPtr vbuf;
            uint newVertCapacity = mVertexBufferCapacity;

            if (!mDrawn)
            {
                mDrawn = true;
                mVertexBufferCapacity = 0;
                newVertCapacity       = 1;

                // Make capacity the next power of two
                while (newVertCapacity < mPoints.Count)
                {
                    newVertCapacity <<= 1;
                }
                mVertexBufferCapacity = newVertCapacity;

                // Initialization stuff
                this.RO_IndexData  = null;
                this.RO_UseIndexes = false;

                mVD.vertexCount       = (uint)mPoints.Count;
                mVD.vertexStart       = 0;
                this.RO_OperationType = OperationType.OT_LINE_STRIP;                 // OT_LINE_LIST, OT_LINE_STRIP

                offPos = mVD.vertexDeclaration.addElement(
                    POSITION_BINDING, 0, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION).getOffset();

                mVertexSize = VertexElement.getTypeSize(VertexElementType.VET_FLOAT3);

                vbuf = HardwareBufferManager.getSingleton().createVertexBuffer(
                    mVD.vertexDeclaration.getVertexSize(POSITION_BINDING),
                    mVertexBufferCapacity,
                    HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);

                mVD.vertexBufferBinding.setBinding(POSITION_BINDING, vbuf);
            }


            if ((mPoints.Count > mVertexBufferCapacity) ||
                (mVertexBufferCapacity == 0))
            {
                // vertexCount exceeds current capacity!
                // It is necessary to reallocate the buffer.

                // Check if this is the first call... should never happen(we have mDrawn flag check)
                if (newVertCapacity == 0)
                {
                    newVertCapacity = 1;
                }

                // Make capacity the next power of two
                while (newVertCapacity < mPoints.Count)
                {
                    newVertCapacity <<= 1;
                }
            }
            else if (mPoints.Count < (mVertexBufferCapacity >> 1))
            {
                // Make capacity the previous power of two
                while (mPoints.Count < (newVertCapacity >> 1))
                {
                    newVertCapacity >>= 1;
                }
            }
            if (newVertCapacity != mVertexBufferCapacity)
            {
                mVertexBufferCapacity = newVertCapacity;
                mVD.vertexCount       = mVertexBufferCapacity;

                // Create new vertex buffer
                vbuf = HardwareBufferManager.getSingleton().createVertexBuffer(
                    mVD.vertexDeclaration.getVertexSize(POSITION_BINDING),
                    mVertexBufferCapacity,
                    HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);

                //the old buffer will automatically be deleted once no more references to it exist
                //http://www.ogre3d.org/phpBB2/viewtopic.php?t=13058&highlight=vertexbuffer+update

                // Bind buffer
                mVD.vertexBufferBinding.setBinding(POSITION_BINDING, vbuf);
            }
            else
            {                   //we need to set vbuf
                vbuf = mVD.vertexBufferBinding.getBuffer(POSITION_BINDING);
            }
            // Update vertex count in the render operation
            mVD.vertexCount = (uint)mPoints.Count;


            // Drawing stuff
            int     size    = mPoints.Count;
            Vector3 vaabMin = (Math3D.Vector3)mPoints[0];
            Vector3 vaabMax = (Math3D.Vector3)mPoints[0];

            IntPtr ptrBuff = vbuf.Get().Lock(HardwareBuffer.LockOptions.HBL_DISCARD);

            for (int i = 0; i < size; i++)
            {
                MeshBuilderHelper.SetVertexFloat(ptrBuff, mVertexSize, (uint)i, offPos,
                                                 ((Math3D.Vector3)mPoints[i]).x,
                                                 ((Math3D.Vector3)mPoints[i]).y,
                                                 ((Math3D.Vector3)mPoints[i]).z);


                if (((Math3D.Vector3)mPoints[i]).x < vaabMin.x)
                {
                    vaabMin.x = ((Math3D.Vector3)mPoints[i]).x;
                }
                if (((Math3D.Vector3)mPoints[i]).y < vaabMin.y)
                {
                    vaabMin.y = ((Math3D.Vector3)mPoints[i]).y;
                }
                if (((Math3D.Vector3)mPoints[i]).z < vaabMin.z)
                {
                    vaabMin.z = ((Math3D.Vector3)mPoints[i]).z;
                }

                if (((Math3D.Vector3)mPoints[i]).x > vaabMax.x)
                {
                    vaabMax.x = ((Math3D.Vector3)mPoints[i]).x;
                }
                if (((Math3D.Vector3)mPoints[i]).y > vaabMax.y)
                {
                    vaabMax.y = ((Math3D.Vector3)mPoints[i]).y;
                }
                if (((Math3D.Vector3)mPoints[i]).z > vaabMax.z)
                {
                    vaabMax.z = ((Math3D.Vector3)mPoints[i]).z;
                }
            }

            vbuf.Get().Unlock();

            AxisAlignedBox box = this.CallBase_getBoundingBox();

            box.SetExtents(vaabMin, vaabMax);
        }
Beispiel #13
0
        /// <summary>
        ///     Sets up the surface by defining it's control points, type and initial subdivision level.
        /// </summary>
        /// <remarks>
        ///     This method initialises the surface by passing it a set of control points. The type of curves to be used
        ///     are also defined here, although the only supported option currently is a bezier patch. You can also
        ///     specify a global subdivision level here if you like, although it is recommended that the parameter
        ///     is left as AUTO_LEVEL, which means the system decides how much subdivision is required (based on the
        ///     curvature of the surface).
        /// </remarks>
        /// <param name="controlPoints">
        ///     A pointer to a buffer containing the vertex data which defines control points
        ///     of the curves rather than actual vertices. Note that you are expected to provide not
        ///     just position information, but potentially normals and texture coordinates too. The
        ///     format of the buffer is defined in the VertexDeclaration parameter.
        /// </param>
        /// <param name="decl">
        ///     VertexDeclaration describing the contents of the buffer.
        ///     Note this declaration must _only_ draw on buffer source 0!
        /// </param>
        /// <param name="width">Specifies the width of the patch in control points.</param>
        /// <param name="height">Specifies the height of the patch in control points.</param>
        /// <param name="type">The type of surface.</param>
        /// <param name="uMaxSubdivisionLevel">
        ///     If you want to manually set the top level of subdivision,
        ///     do it here, otherwise let the system decide.
        /// </param>
        /// <param name="vMaxSubdivisionLevel">
        ///     If you want to manually set the top level of subdivision,
        ///     do it here, otherwise let the system decide.
        /// </param>
        /// <param name="side">Determines which side of the patch (or both) triangles are generated for.</param>
        public unsafe void DefineSurface(System.Array controlPointBuffer, VertexDeclaration declaration, int width, int height,
                                         PatchSurfaceType type, int uMaxSubdivisionLevel, int vMaxSubdivisionLevel, VisibleSide visibleSide)
        {
            if (height == 0 || width == 0)
            {
                return; // Do nothing - garbage
            }

            this.type               = type;
            this.controlWidth       = width;
            this.controlHeight      = height;
            this.controlCount       = width * height;
            this.controlPointBuffer = controlPointBuffer;
            this.declaration        = declaration;

            // Copy positions into Vector3 vector
            controlPoints.Clear();
            VertexElement elem     = declaration.FindElementBySemantic(VertexElementSemantic.Position);
            int           vertSize = declaration.GetVertexSize(0);
            byte *        pVert    = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(controlPointBuffer, 0);
            float *       pReal    = null;

            for (int i = 0; i < controlCount; i++)
            {
                pReal = (float *)(pVert + elem.Offset);
                controlPoints.Add(new Vector3(pReal[0], pReal[1], pReal[2]));
                pVert += vertSize;
            }

            this.side = visibleSide;

            // Determine max level
            // Initialise to 100% detail
            subdivisionFactor = 1.0f;

            if (uMaxSubdivisionLevel == AUTO_LEVEL)
            {
                uLevel = maxULevel = GetAutoULevel();
            }
            else
            {
                uLevel = maxULevel = uMaxSubdivisionLevel;
            }

            if (vMaxSubdivisionLevel == AUTO_LEVEL)
            {
                vLevel = maxVLevel = GetAutoVLevel();
            }
            else
            {
                vLevel = maxVLevel = vMaxSubdivisionLevel;
            }

            // Derive mesh width / height
            meshWidth  = (LevelWidth(maxULevel) - 1) * ((controlWidth - 1) / 2) + 1;
            meshHeight = (LevelWidth(maxVLevel) - 1) * ((controlHeight - 1) / 2) + 1;

            // Calculate number of required vertices / indexes at max resolution
            requiredVertexCount = meshWidth * meshHeight;
            int iterations = (side == VisibleSide.Both)? 2 : 1;

            requiredIndexCount = (meshWidth - 1) * (meshHeight - 1) * 2 * iterations * 3;

            // Calculate bounds based on control points
            Vector3 min         = Vector3.Zero;
            Vector3 max         = Vector3.Zero;
            float   maxSqRadius = 0.0f;
            bool    first       = true;

            for (int i = 0; i < controlPoints.Count; i++)
            {
                Vector3 vec = controlPoints[i];
                if (first)
                {
                    min         = max = vec;
                    maxSqRadius = vec.LengthSquared;
                    first       = false;
                }
                else
                {
                    min.Floor(vec);
                    max.Ceil(vec);
                    maxSqRadius = MathUtil.Max(vec.LengthSquared, maxSqRadius);
                }
            }

            // set the bounds of the patch
            aabb.SetExtents(min, max);
            boundingSphereRadius = MathUtil.Sqrt(maxSqRadius);
        }