Click here to Skip to main content
15,892,746 members
Articles / Programming Languages / Visual Basic

Mathemathics Framework

Rate me:
Please Sign up or sign in to vote.
4.76/5 (56 votes)
16 Sep 2008CPOL6 min read 75.4K   6.2K   171  
.NET Mathematical Framework
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports Microsoft.DirectX
Imports Microsoft.DirectX.Direct3D

Public Class Terrain

    Private device As Device
    Private decl As VertexDeclaration
    Private vb As VertexBuffer
    Private ib As IndexBuffer
    Private numvertices As Integer, numindices As Integer, numtriangles As Integer
    Private heights(,) As Single
    Private dx As Single, dy As Single
    Private Created As Boolean = False
    Private numWidth As Integer, numHeight As Integer
    Public Shared size As Single = 150.0F
    Private normallist As Vector3()
    Public renderNormals As Boolean = False

    'public unsafe Visor( Device d, float Min, float Max)
    Public Sub New(ByVal d As Device, ByVal Min As Single, ByVal Max As Single)
        device = d
        ' Load the heightmap
        Dim b As Bitmap = New Bitmap("..\..\heightmap.bmp")
        ' Store the number of pixels 
        Dim numWidth As Integer = b.Width
        Dim numHeight As Integer = b.Height
        ' Create an array of floats
        ReDim heights(numWidth, numHeight)

        ' Lock the data from the bitmap so it can be accessed unsafely
        Dim data As BitmapData
        data = b.LockBits(New Rectangle(0, 0, numWidth, numHeight), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb)
        ' Assigh the address of the first pixel to the pointer
        Dim i, j As Integer

        Dim p As IntPtr
        p = data.Scan0
        Dim Arr(0) As Byte
        Dim lowest As Integer = 255
        Dim highest As Integer
        For i = 0 To numWidth - 1
            For j = 0 To numHeight - 1
                System.Runtime.InteropServices.Marshal.Copy(p, Arr, 0, 1)
                If Arr(0) < lowest Then
                    lowest = Arr(0)
                End If
                If Arr(0) > highest Then
                    highest = Arr(0)
                End If
                p = New IntPtr(p.ToInt32 + 3)
            Next
        Next

        p = data.Scan0
        For i = 0 To numWidth - 1
            For j = 0 To numHeight - 1
                System.Runtime.InteropServices.Marshal.Copy(p, Arr, 0, 1)
                heights(i, j) = CType((Arr(0) - lowest) / ((highest - lowest)) * (Max - Min) + Min, Single)
                p = New IntPtr(p.ToInt32 + 3)
            Next
        Next
        b.UnlockBits(data)

        numvertices = numWidth * numHeight
        numindices = 6 * (numWidth - 1) * (numHeight - 1)
        numtriangles = 2 * (numWidth - 1) * (numHeight - 1)

        ' Create on array of vertices
        Dim verts() As Vertex
        ReDim verts(numvertices)

        ' Create on array of indices
        Dim ind() As Integer
        ReDim ind(numindices)

        Dim n, x As Integer
        dx = size / numWidth
        dy = size / numWidth

        For i = 0 To numHeight - 1

            For j = 0 To numWidth - 1

                ' Calculate the blend value by dividing the height by the maximal height
                Dim Blend As Single = (heights(j, i) - Min) / (Max - Min)
                ' Normals will be calculated after this so assign a upward normal for now
                verts(i * numWidth + j) = New Vertex(New Vector3(j * dx - size / 2.0F, _
                                                        heights(j, i), _
                                                        i * dy - size / 2.0F), _
                                                        New Vector3(0, 1, 0), _
                                                        CType(j / numWidth * size / 16.0F, Single), _
                                                        CType(i / numHeight * size / 16.0F, Single), _
                                                        1 - Blend, Blend, 0, 0, True)
            Next
        Next

        Dim x2, Normal, z As Vector3
        For i = 1 To numHeight - 2
            For j = 1 To numWidth - 2

                ' Calculate the real normals by using the cross product of the vertex' neighbours
                x2 = Vector3.Subtract(verts(i * numWidth + j + 1).Position, verts(i * numWidth + j - 1).Position)
                z = Vector3.Subtract(verts((i + 1) * numWidth + j).Position, verts((i - 1) * numWidth + j).Position)
                Normal = Vector3.Cross(z, x2)
                Normal.Normalize()
                verts(i * numWidth + j).Normal = Normal
            Next
        Next

        ' Create on array of Vector3's for each vertex storing the position and the normal added to the position so the normals can be rendered 
        ReDim normallist(numvertices * 2)

        For i = 0 To numvertices - 1
            normallist(2 * i) = verts(i).Position
            normallist(2 * i + 1) = Vector3.Add(verts(i).Position, Vector3.Multiply(verts(i).Normal, 3))
        Next

        ' Fill the array of indices
        For i = 0 To numWidth - 2
            For j = 0 To numHeight - 2
                x = i * numWidth + j
                n += 1
                ind(n) = x
                ind(n) = x + 1
                ind(n) = x
                ind(n) = x + numWidth + 1
                ind(n) = x
                ind(n) = x
                ind(n) = x
                ind(n) = x + numWidth
                ind(n) = x
                ind(n) = x + numWidth + 1
            Next
        Next

        ' Create the vertex- and indexbuffer and set their data
        vb = New VertexBuffer(GetType(Vertex), numvertices, device, Usage.None, Vertex.Format, Pool.Default)
        vb.SetData(verts, 0, 0)
        ib = New IndexBuffer(GetType(Integer), numindices, device, 0, 0)
        ib.SetData(ind, 0, 0)

        ' Create the vertexdeclaration
        Dim v() As VertexElement = {New VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), _
                                    New VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0), _
                                    New VertexElement(0, 24, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0), _
                                    New VertexElement(0, 32, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 1), _
                                    VertexElement.VertexDeclarationEnd}
        decl = New VertexDeclaration(device, v)

    End Sub

    Public Sub Draw()
        ' Set the VertexDeclaration, StreamSource and Indices 
        device.VertexDeclaration = decl
        device.SetStreamSource(0, vb, 0)
        device.Indices = ib
        ' Draw the terrain
        device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, numvertices, 0, numtriangles)
        If Not renderNormals Then
            Return
        End If
        ' Render the normal list
        Using l As New Line(device)
            l.Antialias = True
            l.Width = 2
            l.Begin()
            For i As Integer = 0 To normallist.Length - 2 Step 2
                l.DrawTransform(New Vector3() {normallist(i), normallist(i + 1)}, Form1.viewMatrix * Form1.projMatrix, Color.Red)
            Next
            l.End()
        End Using
    End Sub

End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer Universidad Tecnológica Nacional
Argentina Argentina
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions