Marching cubes (metaball/3D contouring)

Everything related to 3D programming
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Marching cubes (metaball/3D contouring)

Post by djes »

The marching function with boolean calculus seems doubtful to me. Could you share the original version, please ?
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Marching cubes (metaball/3D contouring)

Post by djes »

I've not found any bug yet, and it will be hard to debunk !
DarkDragon
Addict
Addict
Posts: 2348
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Marching cubes (metaball/3D contouring)

Post by DarkDragon »

Alexi wrote:Any idea? I actually wrote dual marching cubes for volume terrain, ironically the author of the articles i used has written the volume terrain of the OGRE component itself.

Everything seems fine so far, just the marching lookup seems to go wrong.
Hahaha, I was reading the same source a few months ago for a project about tree root modeling.
bye,
Daniel
DarkDragon
Addict
Addict
Posts: 2348
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Marching cubes (metaball/3D contouring)

Post by DarkDragon »

Sorry for double posting, but I found an old implementation on my backup drives:

Code: Select all

OnErrorGoto(?ERROR)

Structure SVector
  x.f
  y.f
  z.f
EndStructure

Structure STriangle
  p.SVector[3]
EndStructure

Structure SGridCell
  p.SVector[8]
  n.SVector[8]
  val.f[8]
EndStructure

Macro P2D(Pointer, X, Y, Width, DataType)
  Pointer + ((X * Width + Y) * SizeOf(DataType))
EndMacro

Procedure VertexInterp(isolevel.f, *p1.SVector, *p2.SVector, *n1.SVector, *n2.SVector, valp1.f, valp2.f, *vert.SVector, *norm.SVector)
  mu.f = 0.0

  If (Abs(isolevel-valp1) < 0.000001)
    CopyMemory(*p1, *vert, SizeOf(SVector))
    CopyMemory(*n1, *norm, SizeOf(SVector))
    ProcedureReturn 1
  EndIf
  If (Abs(isolevel-valp2) < 0.000001)
    CopyMemory(*p2, *vert, SizeOf(SVector))
    CopyMemory(*n2, *norm, SizeOf(SVector))
    ProcedureReturn 1
  EndIf
  If (Abs(valp1-valp2) < 0.000001)
    CopyMemory(*p1, *vert, SizeOf(SVector))
    CopyMemory(*n1, *norm, SizeOf(SVector))
    ProcedureReturn 1
  EndIf

  mu = (isolevel - valp1) / (valp2 - valp1)
  *vert\x = *p1\x + mu * (*p2\x - *p1\x)
  *vert\y = *p1\y + mu * (*p2\y - *p1\y)
  *vert\z = *p1\z + mu * (*p2\z - *p1\z)

  *norm\x = *n1\x + mu * (*n2\x - *n1\x)
  *norm\y = *n1\y + mu * (*n2\y - *n1\y)
  *norm\z = *n1\z + mu * (*n2\z - *n1\z)
EndProcedure

Procedure Polygonise(*grid.SGridCell, isolevel.f, *tris.STriangle, *norm.STriangle)

  Protected i.l, ntriang.l
  Protected cubeindex.l
  Protected *v.SVector
  Protected check.l
  Dim vertlist.SVector(12)
  Dim normlist.SVector(12)

  cubeindex = 0
  If *grid\val[0] < isolevel : cubeindex + 1   : EndIf
  If *grid\val[1] < isolevel : cubeindex + 2   : EndIf
  If *grid\val[2] < isolevel : cubeindex + 4   : EndIf
  If *grid\val[3] < isolevel : cubeindex + 8   : EndIf
  If *grid\val[4] < isolevel : cubeindex + 16  : EndIf
  If *grid\val[5] < isolevel : cubeindex + 32  : EndIf
  If *grid\val[6] < isolevel : cubeindex + 64  : EndIf
  If *grid\val[7] < isolevel : cubeindex + 128 : EndIf

  check = PeekL(?EdgeTable + cubeindex * SizeOf(LONG))

  If check = 0 : ProcedureReturn 0 : EndIf

  If (check & 1)
    VertexInterp(isolevel, *grid\p[0], *grid\p[1], *grid\n[0], *grid\n[1], *grid\val[0], *grid\val[1], @vertlist(0)\x, @normlist(0)\x)
  EndIf
  If (check & 2)
    VertexInterp(isolevel, *grid\p[1], *grid\p[2], *grid\n[1], *grid\n[2], *grid\val[1], *grid\val[2], @vertlist(1)\x, @normlist(1)\x)
  EndIf
  If (check & 4)
    VertexInterp(isolevel, *grid\p[2], *grid\p[3], *grid\n[2], *grid\n[3], *grid\val[2], *grid\val[3], @vertlist(2)\x, @normlist(2)\x)
  EndIf
  If (check & 8)
    VertexInterp(isolevel, *grid\p[3], *grid\p[0], *grid\n[3], *grid\n[0], *grid\val[3], *grid\val[0], @vertlist(3)\x, @normlist(3)\x)
  EndIf
  If (check & 16)
    VertexInterp(isolevel, *grid\p[4], *grid\p[5], *grid\n[4], *grid\n[5], *grid\val[4], *grid\val[5], @vertlist(4)\x, @normlist(4)\x)
  EndIf
  If (check & 32)
    VertexInterp(isolevel, *grid\p[5], *grid\p[6], *grid\n[5], *grid\n[6], *grid\val[5], *grid\val[6], @vertlist(5)\x, @normlist(5)\x)
  EndIf
  If (check & 64)
    VertexInterp(isolevel, *grid\p[6], *grid\p[7], *grid\n[6], *grid\n[7], *grid\val[6], *grid\val[7], @vertlist(6)\x, @normlist(6)\x)
  EndIf
  If (check & 128)
    VertexInterp(isolevel, *grid\p[7], *grid\p[4], *grid\n[7], *grid\n[4], *grid\val[7], *grid\val[4], @vertlist(7)\x, @normlist(7)\x)
  EndIf
  If (check & 256)
    VertexInterp(isolevel, *grid\p[0], *grid\p[4], *grid\n[0], *grid\n[4], *grid\val[0], *grid\val[4], @vertlist(8)\x, @normlist(8)\x)
  EndIf
  If (check & 512)
    VertexInterp(isolevel, *grid\p[1], *grid\p[5], *grid\n[1], *grid\n[5], *grid\val[1], *grid\val[5], @vertlist(9)\x, @normlist(9)\x)
  EndIf
  If (check & 1024)
    VertexInterp(isolevel, *grid\p[2], *grid\p[6], *grid\n[2], *grid\n[6], *grid\val[2], *grid\val[6], @vertlist(10)\x, @normlist(10)\x)
  EndIf
  If (check & 2048)
    VertexInterp(isolevel, *grid\p[3], *grid\p[7], *grid\n[3], *grid\n[7], *grid\val[3], *grid\val[7], @vertlist(11)\x, @normlist(11)\x)
  EndIf

  ntriang = 0

  *tritab.LONG = P2D(?TriangleTable, cubeindex, 0, 16, LONG)
  While *tritab\l <> -1
    CopyMemory(@vertlist(*tritab\l), @*tris\p[2], SizeOf(SVector)) : CopyMemory(@normlist(*tritab\l), @*norm\p[2], SizeOf(SVector)) : *tritab + SizeOf(LONG)
    CopyMemory(@vertlist(*tritab\l), @*tris\p[1], SizeOf(SVector)) : CopyMemory(@normlist(*tritab\l), @*norm\p[1], SizeOf(SVector)) : *tritab + SizeOf(LONG)
    CopyMemory(@vertlist(*tritab\l), @*tris\p[0], SizeOf(SVector)) : CopyMemory(@normlist(*tritab\l), @*norm\p[0], SizeOf(SVector)) : *tritab + SizeOf(LONG)

    *tris + SizeOf(STriangle)
    *norm + SizeOf(STriangle)
    ntriang + 1
  Wend

  ProcedureReturn ntriang

  DataSection
    EdgeTable:
    Data.l $0  , $109, $203, $30a, $406, $50f, $605, $70c
    Data.l $80c, $905, $a0f, $b06, $c0a, $d03, $e09, $f00
    Data.l $190, $99 , $393, $29a, $596, $49f, $795, $69c
    Data.l $99c, $895, $b9f, $a96, $d9a, $c93, $f99, $e90
    Data.l $230, $339, $33 , $13a, $636, $73f, $435, $53c
    Data.l $a3c, $b35, $83f, $936, $e3a, $f33, $c39, $d30
    Data.l $3a0, $2a9, $1a3, $aa , $7a6, $6af, $5a5, $4ac
    Data.l $bac, $aa5, $9af, $8a6, $faa, $ea3, $da9, $ca0
    Data.l $460, $569, $663, $76a, $66 , $16f, $265, $36c
    Data.l $c6c, $d65, $e6f, $f66, $86a, $963, $a69, $b60
    Data.l $5f0, $4f9, $7f3, $6fa, $1f6, $ff , $3f5, $2fc
    Data.l $dfc, $cf5, $fff, $ef6, $9fa, $8f3, $bf9, $af0
    Data.l $650, $759, $453, $55a, $256, $35f, $55 , $15c
    Data.l $e5c, $f55, $c5f, $d56, $a5a, $b53, $859, $950
    Data.l $7c0, $6c9, $5c3, $4ca, $3c6, $2cf, $1c5, $cc
    Data.l $fcc, $ec5, $dcf, $cc6, $bca, $ac3, $9c9, $8c0
    Data.l $8c0, $9c9, $ac3, $bca, $cc6, $dcf, $ec5, $fcc
    Data.l $cc , $1c5, $2cf, $3c6, $4ca, $5c3, $6c9, $7c0
    Data.l $950, $859, $b53, $a5a, $d56, $c5f, $f55, $e5c
    Data.l $15c, $55 , $35f, $256, $55a, $453, $759, $650
    Data.l $af0, $bf9, $8f3, $9fa, $ef6, $fff, $cf5, $dfc
    Data.l $2fc, $3f5, $ff , $1f6, $6fa, $7f3, $4f9, $5f0
    Data.l $b60, $a69, $963, $86a, $f66, $e6f, $d65, $c6c
    Data.l $36c, $265, $16f, $66 , $76a, $663, $569, $460
    Data.l $ca0, $da9, $ea3, $faa, $8a6, $9af, $aa5, $bac
    Data.l $4ac, $5a5, $6af, $7a6, $aa , $1a3, $2a9, $3a0
    Data.l $d30, $c39, $f33, $e3a, $936, $83f, $b35, $a3c
    Data.l $53c, $435, $73f, $636, $13a, $33 , $339, $230
    Data.l $e90, $f99, $c93, $d9a, $a96, $b9f, $895, $99c
    Data.l $69c, $795, $49f, $596, $29a, $393, $99 , $190
    Data.l $f00, $e09, $d03, $c0a, $b06, $a0f, $905, $80c
    Data.l $70c, $605, $50f, $406, $30a, $203, $109, $0

    TriangleTable:
    Data.l -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1
    Data.l 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1
    Data.l 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1
    Data.l 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1
    Data.l 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1
    Data.l 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1
    Data.l 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1
    Data.l 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1
    Data.l 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1
    Data.l 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1
    Data.l 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1
    Data.l 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1
    Data.l 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1
    Data.l 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1
    Data.l 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1
    Data.l 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1
    Data.l 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1
    Data.l 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1
    Data.l 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1
    Data.l 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1
    Data.l 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1
    Data.l 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1
    Data.l 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1
    Data.l 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1
    Data.l 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1
    Data.l 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1
    Data.l 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1
    Data.l 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1
    Data.l 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1
    Data.l 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1
    Data.l 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1
    Data.l 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1
    Data.l 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1
    Data.l 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1
    Data.l 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1
    Data.l 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1
    Data.l 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1
    Data.l 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1
    Data.l 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1
    Data.l 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1
    Data.l 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1
    Data.l 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1
    Data.l 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1
    Data.l 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1
    Data.l 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1
    Data.l 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1
    Data.l 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1
    Data.l 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1
    Data.l 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1
    Data.l 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1
    Data.l 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1
    Data.l 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1
    Data.l 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1
    Data.l 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1
    Data.l 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1
    Data.l 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1
    Data.l 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1
    Data.l 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1
    Data.l 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1
    Data.l 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1
    Data.l 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1
    Data.l 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1
    Data.l 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1
    Data.l 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1
    Data.l 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1
    Data.l 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1
    Data.l 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1
    Data.l 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1
    Data.l 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1
    Data.l 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1
    Data.l 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1
    Data.l 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1
    Data.l 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1
    Data.l 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1
    Data.l 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1
    Data.l 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1
    Data.l 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1
    Data.l 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1
    Data.l 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1
    Data.l 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1
    Data.l 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1
    Data.l 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1
    Data.l 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1
    Data.l 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1
    Data.l 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1
    Data.l 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1
    Data.l 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1
    Data.l 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1
    Data.l 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1
    Data.l 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1
    Data.l 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1
    Data.l 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1
    Data.l 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1
    Data.l 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1
    Data.l 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1
    Data.l 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1
    Data.l 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1
    Data.l 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1
    Data.l 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1
    Data.l 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1
    Data.l 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1
    Data.l 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1
    Data.l 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1
    Data.l 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1
    Data.l 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1
    Data.l 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1
    Data.l 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1
    Data.l 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1
    Data.l 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1
    Data.l 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1
    Data.l 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1
    Data.l 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1
    Data.l 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1
    Data.l 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1
    Data.l 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1
    Data.l 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    Data.l -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
  EndDataSection

EndProcedure

Procedure.f Isnan(float.f)
  ; check float for NaN
  ; return: 1 = NaN
  ;         0 = no NaN
  DisableDebugger
  !FLD dword [esp]
  !FXAM
  !FSTSW AX
  !FFREE ST0 ;!FSTP dword [esp]
  !FINCSTP   ;<- auch ersetzen

  !AND dword EAX,100h
  !SHR dword EAX,8
  ProcedureReturn
  EnableDebugger
EndProcedure

Macro Magnitude(pos)
  Sqr(pos\X*pos\X + pos\Y*pos\Y + pos\Z*pos\Z)
EndMacro

Macro Middle(p1, p2, p3, m)
  m\x = (p1\x + p2\x + p3\x) * 0.333333
  m\y = (p1\y + p2\y + p3\y) * 0.333333
  m\z = (p1\z + p2\z + p3\z) * 0.333333
EndMacro

Procedure.l Normal(*Pos1.SVector, *Pos2.SVector, *Pos3.SVector, *vNormal1.SVector);, *vNormal2.SVector, *vNormal3.SVector)

  vVector1.SVector
  vVector1\X = *Pos1\X - *Pos2\X
  vVector1\Y = *Pos1\Y - *Pos2\Y
  vVector1\Z = *Pos1\Z - *Pos2\Z

  vVector2.SVector
  vVector2\X = *Pos1\X - *Pos3\X
  vVector2\Y = *Pos1\Y - *Pos3\Y
  vVector2\Z = *Pos1\Z - *Pos3\Z

  *vNormal1\X = ((vVector1\Y * vVector2\Z) - (vVector1\Z * vVector2\Y))
  *vNormal1\Y = ((vVector1\Z * vVector2\X) - (vVector1\X * vVector2\Z))
  *vNormal1\Z = ((vVector1\X * vVector2\Y) - (vVector1\Y * vVector2\X))

  ;   vMiddle.SVector
  ;
  ;   Middle(*Pos1, *Pos2, *Pos3, vMiddle)
  ;
  ;   *vNormal2\x = *vNormal1\x + (*Pos2\x - vMiddle\x) * 0.05
  ;   *vNormal3\x = *vNormal1\x + (*Pos3\x - vMiddle\x) * 0.05
  ;   *vNormal1\x = *vNormal1\x + (*Pos1\x - vMiddle\x) * 0.05
  ;
  ;   *vNormal2\y = *vNormal1\y + (*Pos2\y - vMiddle\y) * 0.05
  ;   *vNormal3\y = *vNormal1\y + (*Pos3\y - vMiddle\y) * 0.05
  ;   *vNormal1\y = *vNormal1\y + (*Pos1\y - vMiddle\y) * 0.05
  ;
  ;   *vNormal2\z = *vNormal1\z + (*Pos2\z - vMiddle\z) * 0.05
  ;   *vNormal3\z = *vNormal1\z + (*Pos3\z - vMiddle\z) * 0.05
  ;   *vNormal1\z = *vNormal1\z + (*Pos1\z - vMiddle\z) * 0.05

  magnitude.f = 1.0/Magnitude(*vNormal1)
  If Isnan(magnitude) = 0
    *vNormal1\X * magnitude
    *vNormal1\Y * magnitude
    *vNormal1\Z * magnitude
  EndIf

  ;   *vNormal2\X = *vNormal1\X
  ;   *vNormal2\Y = *vNormal1\Y
  ;   *vNormal2\Z = *vNormal1\Z
  ;
  ;   *vNormal3\X = *vNormal1\X
  ;   *vNormal3\Y = *vNormal1\Y
  ;   *vNormal3\Z = *vNormal1\Z

  ;   magnitude.f = 1.0/Magnitude(*vNormal2)
  ;   If Isnan(magnitude) = 0
  ;     *vNormal2\X * magnitude
  ;     *vNormal2\Y * magnitude
  ;     *vNormal2\Z * magnitude
  ;   EndIf
  ;
  ;   magnitude.f = 1.0/Magnitude(*vNormal3)
  ;   If Isnan(magnitude) = 0
  ;     *vNormal3\X * magnitude
  ;     *vNormal3\Y * magnitude
  ;     *vNormal3\Z * magnitude
  ;   EndIf

EndProcedure

Structure SVertex Extends SVector
  normal.SVector
  *addr.SVector[15]
EndStructure

Procedure GenerateNormals(*VBuffer, *NBuffer, Size)
  Protected NewList vertex.SVertex()
  Protected *tempV.STriangle
  Protected *tempN.STriangle
  Protected normal.SVector
  Protected *found.SVector

  ClearList(vertex())

  *tempV = *VBuffer
  *tempN = *NBuffer
  While (*tempV - *VBuffer) < Size
    Normal(@*tempV\p[0], @*tempV\p[1], @*tempV\p[2], *tempN)

    *tempV + SizeOf(STriangle)
    *tempN + SizeOf(STriangle)
  Wend

  *tempV = *VBuffer
  *tempN = *NBuffer
  While (*tempV - *VBuffer) < Size
    CopyMemory(*tempN, @normal, SizeOf(SVector))

    For k=0 To 2
      *found = 0
      ForEach vertex()
        If CompareMemory(@*tempV\p[k], @vertex()\x, SizeOf(SVector))
          *found = *NBuffer + (@*tempV\p[k] - *VBuffer)
          Break
        EndIf
      Next

      If *found = 0
        AddElement(vertex())
        vertex()\x = *tempV\p[k]\x
        vertex()\y = *tempV\p[k]\y
        vertex()\z = *tempV\p[k]\z

        vertex()\normal\x = normal\x
        vertex()\normal\y = normal\y
        vertex()\normal\z = normal\z
      Else
        vertex()\normal\x = (vertex()\normal\x + normal\x) * 0.5
        vertex()\normal\y = (vertex()\normal\y + normal\y) * 0.5
        vertex()\normal\z = (vertex()\normal\z + normal\z) * 0.5
      EndIf

      For i=0 To 14
        If vertex()\addr[i] = 0
          vertex()\addr[i] = *found
          Break
        EndIf
      Next
    Next

    *tempV + SizeOf(STriangle)
    *tempN + SizeOf(STriangle)
  Wend

  ForEach vertex()
    For i=0 To 14
      If vertex()\addr[i] <> 0
        CopyMemory(@vertex()\normal, vertex()\addr[i], SizeOf(SVector))
      EndIf
    Next i
  Next
EndProcedure

XIncludeFile "GL.pbi"
XIncludeFile "GLEXT.pbi"

Import "OpenGL32.lib"
  glClearDepth    (depth.d)                                             As "_glClearDepth@8"
  glClipPlane     (plane.l, equation.d)                                 As "_glClipPlane@12"
  glDepthRange    (near.d, far.d)                                       As "_glDepthRange@16"
  glFrustum       (left.d, right.d, bottom.d, top.d, znear.d, zfar.d)   As "_glFrustum@48"
  glGetClipPlane  (plane.l, equation.d)                                 As "_glGetClipPlane@8"
  glOrtho         (left.d, right.d, bottom.d, top.d, znear.d, zfar.d)   As "_glOrtho@48"
EndImport

Import "Glu32.lib"
  gluCylinder     (*qobj, baseRadius.d, topRadius.d, height.d, slices.l, stacks.l)                      As "_gluCylinder@36"
  gluDisk         (*qobj, innerRadius.d, outerRadius.d, slices.l, loops.l)                              As "_gluDisk@28"
  gluLookAt       (eyex.d, eyey.d, eyez.d, centerx.d, centery.d, centerz.d, upx.d, upy.d, upz.d)        As "_gluLookAt@72"
  gluOrtho2D      (left.d, right.d, bottom.d, top.d)                                                    As "_gluOrtho2D@32"
  gluPartialDisk  (*qobj, innerRadius.d, outerRadius.d, slices.l, loops.l, startAngle.d, sweepAngle.d)  As "_gluPartialDisk@44"
  gluPerspective  (fovy.d, aspect.d, zNear.d, zFar.d)                                                   As "_gluPerspective@32"
  gluPickMatrix   (x.d, y.d, width.d, height.d, *viewport)                                              As "_gluPickMatrix@36"
  gluProject      (objx.d, objy.d, objz.d, *modelMatrix, *projMatrix, *viewport, *winx, *winy, *winz)   As "_gluProject@48"
  gluSphere       (*qobj, radius.d, slices.l, stacks.l)                                                 As "_gluSphere@20"
  gluTessNormal   (*tess, x.d, y.d, z.d)                                                                As "_gluTessNormal@28"
  gluTessProperty (*tess, which.l, value.l)                                                             As "_gluTessProperty@12"
  gluUnProject    (winx.d, winy.d, winz.d, *modelMatrix, *projMatrix, *viewport, *objx, *objy, *objz)   As "_gluUnProject@48"
EndImport

Structure GLSLLight
  glslLightColor.l
  glslLightPos.l

  x.f
  y.f
  z.f

  color.f[3]
  id.l
EndStructure

Global NewList Lights.GLSLLight()

Global glslCreateProgramObjectARB.l
Global glslCreateShaderObjectARB.l
Global glslLinkProgramARB.l
Global glslCompileShaderARB.l
Global glslGetInfoLogARB.l
Global glslDeleteObjectARB.l
Global glslUseProgramObjectARB.l
Global glslShaderSourceARB.l
Global glslAttachObjectARB.l
Global glslGetObjectParameterivARB.l
Global glslGetUniformLocationARB.l
Global glDisableVertexAttribArrayARB.l
Global glEnableVertexAttribArrayARB.l
Global glslUniform4fARB.l
Global glslUniform2fARB.l
Global glslUniform1fARB.l
Global glslUniform1iARB.l
Global glslUniform4fvARB.l

; GLSlang objects
Global glslContext.l
Global glslVertexShader.l
Global glslPixelShader.l

; Shader parameters
Global glslTexture.l ;unsigned
Global glslAmbientColor.l
Global glslMatAmbient.l
Global glslMatDiffuse.l
Global glslMatSpecular.l
Global glslEmissive.l
Global glslShininess.l
Global glslCameraPos.l

#WindowWidth = 640
#WindowHeight = 480
#WindowFlags = #PB_Window_TitleBar | #PB_Window_MaximizeGadget | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
Version.f = 1.0

Global hWnd.l, Event

Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
  Result = #PB_ProcessPureBasicEvents
  If Message = #WM_SIZE
    glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
    Result = 1
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure SetCamera(Window, FOV.f, X.f, Y.f, Z.f, AngleX.f, AngleY.f, AngleZ.f, Near.f = 0.1, Far.f = 100.0) ;Sets the cameraposition and the FOV
  glMatrixMode_(#GL_PROJECTION)
  glLoadIdentity_()
  gluPerspective(FOV, WindowWidth(Window)/WindowHeight(Window), Near.f, Far.f)
  glRotatef_(AngleX, 1.0, 0.0, 0.0)
  glRotatef_(AngleY, 0.0, 1.0, 0.0)
  glRotatef_(AngleZ, 0.0, 0.0, 1.0)
  glTranslatef_(X, Y, Z)
  glMatrixMode_(#GL_MODELVIEW)

  glDepthRange(Near.f, Far.f)
EndProcedure

Procedure.f FunktionsWert(x.f, y.f, z.f)
  Protected u.f, v.f, w.f
  Shared rotation.f

;   metax1 = Sin(rotation) * 4.5 + 7.0
;   metay1 = Cos(rotation) * 2.5 + 5.0
;   metaz1 = 5.0;Cos(rotation) * 2.5 + 5.0

  ;   v = (Pow(x - metax1, 2) + Pow(y - metay1, 2) + Pow(z - metaz1, 2))
  ;
  ;   If v <> 0.0
  ;     v = 1.0 / v
  ;   Else
  ;     v = 1.0
  ;   EndIf
  ;
  ;   w = (Pow(x - 10.0, 2) + Pow(y - 5.0, 2) + Pow(z - 5.0, 2))
  ;
  ;   If w <> 0.0
  ;     w = 1.0 / w
  ;   Else
  ;     w = 1.0
  ;   EndIf
  
  metay1.f = Cos(rotation) * 2.0 + 5.0
  metay2.f = Sin(rotation) * 2.0 + 5.0
  
  v = (Pow(x - 4.0, 2) + Pow(y - metay1, 2) + Pow(z - 2.0, 2))
  
  If v <> 0.0
    v = 1.0 / v
  Else
    v = 1.0
  EndIf
  
  w = (Pow(x - 9.0, 2) + Pow(y - metay2, 2) + Pow(z - 2.0, 2))
  
  If w <> 0.0
    w = 1.0 / w
  Else
    w = 1.0
  EndIf
  
  u = v + w
  
  v = (Pow(x - 4.0, 2) + Pow(y - metay1, 2) + Pow(z - 7.0, 2))
  
  If v > 0.1
    v = 0.0
  Else
    u = 0.0
  EndIf
  
  w = (Pow(x - 9.0, 2) + Pow(y - metay2, 2) + Pow(z - 7.0, 2))
  
  If w > 0.1
    w = 0.0
  Else
    u = 0.0
  EndIf
  
  ProcedureReturn u
EndProcedure

Procedure DrawMetaballs(PacketSize.l, BlockSizeX.l, BlockSizeY.l, BlockSizeZ.l)
  Protected *tris.STriangle
  Protected *norm.STriangle
  Protected grid.SGridCell
  Static size.l
  Shared *VertexBuffer, *NormalBuffer
  Global Dim VoxelMap.f(BlockSizeX, BlockSizeY, BlockSizeZ)

  If PacketSize < SizeOf(STriangle) * 5 : PacketSize = SizeOf(STriangle) * 5 : EndIf

  If *VertexBuffer = 0
    *VertexBuffer = AllocateMemory(PacketSize)
    *NormalBuffer = AllocateMemory(PacketSize)
    size = PacketSize
  EndIf

  *tris = *VertexBuffer
  *norm = *NormalBuffer

  For kz = 0 To BlockSizeZ - 1
    For ky = 0 To BlockSizeY - 1
      For kx = 0 To BlockSizeX - 1
        VoxelMap(kx, ky, kz) = FunktionsWert(kx, ky, kz)
      Next kx
    Next ky
  Next kz

  mz.f = 0.0
  While mz < BlockSizeZ - 1
    my.f = 0.0
    nz.f = mz + 1.0
    While my < BlockSizeY - 1
      mx.f = 0.0
      ny.f = my + 1.0
      While mx < BlockSizeX - 1
        nx.f = mx + 1.0

        grid\p[0]\x = mx
        grid\p[0]\y = my
        grid\p[0]\z = mz

        grid\val[0] = VoxelMap(Int(grid\p[0]\x), Int(grid\p[0]\y), Int(grid\p[0]\z))

        grid\p[1]\x = nx
        grid\p[1]\y = my
        grid\p[1]\z = mz

        grid\val[1] = VoxelMap(Int(grid\p[1]\x), Int(grid\p[1]\y), Int(grid\p[1]\z))

        grid\p[2]\x = nx
        grid\p[2]\y = my
        grid\p[2]\z = nz

        grid\val[2] = VoxelMap(Int(grid\p[2]\x), Int(grid\p[2]\y), Int(grid\p[2]\z))

        grid\p[3]\x = mx
        grid\p[3]\y = my
        grid\p[3]\z = nz

        grid\val[3] = VoxelMap(Int(grid\p[3]\x), Int(grid\p[3]\y), Int(grid\p[3]\z))

        grid\p[4]\x = mx
        grid\p[4]\y = ny
        grid\p[4]\z = mz

        grid\val[4] = VoxelMap(Int(grid\p[4]\x), Int(grid\p[4]\y), Int(grid\p[4]\z))

        grid\p[5]\x = nx
        grid\p[5]\y = ny
        grid\p[5]\z = mz

        grid\val[5] = VoxelMap(Int(grid\p[5]\x), Int(grid\p[5]\y), Int(grid\p[5]\z))

        grid\p[6]\x = nx
        grid\p[6]\y = ny
        grid\p[6]\z = nz

        grid\val[6] = VoxelMap(Int(grid\p[6]\x), Int(grid\p[6]\y), Int(grid\p[6]\z))

        grid\p[7]\x = mx
        grid\p[7]\y = ny
        grid\p[7]\z = nz

        grid\val[7] = VoxelMap(Int(grid\p[7]\x), Int(grid\p[7]\y), Int(grid\p[7]\z))

        For i=0 To 7
          grid\n[i]\x = grid\val[i] - VoxelMap(Int(grid\p[i]\x) + 1, Int(grid\p[i]\y), Int(grid\p[i]\z))
          grid\n[i]\y = grid\val[i] - VoxelMap(Int(grid\p[i]\x), Int(grid\p[i]\y) + 1, Int(grid\p[i]\z))
          grid\n[i]\z = grid\val[i] - VoxelMap(Int(grid\p[i]\x), Int(grid\p[i]\y), Int(grid\p[i]\z) + 1)
        Next

        currentPos = *tris - *VertexBuffer
        If currentPos > size - SizeOf(STriangle) * 5
          size + PacketSize
          *VertexBuffer = ReAllocateMemory(*VertexBuffer, size)
          *NormalBuffer = ReAllocateMemory(*NormalBuffer, size)
          *tris = *VertexBuffer + currentPos
          *norm = *NormalBuffer + currentPos
        EndIf

        Count = Polygonise(@grid, 0.06, *tris, *norm)

        *tris + SizeOf(STriangle) * Count
        *norm + SizeOf(STriangle) * Count

        mx + 1.0
      Wend
      my + 1.0
    Wend
    mz + 1.0
  Wend

  poly = (*tris - *VertexBuffer)

  ;   GenerateNormals(*VertexBuffer, *NormalBuffer, poly)
  ;
  ;   *tris = *VertexBuffer
  ;   *norm = *NormalBuffer
  ;   While (*norm - *NormalBuffer) < poly
  ;     Normal(@*tris\p[0], @*tris\p[1], @*tris\p[2], @*norm\p[0]);, @*norm\p[1], @*norm\p[2])
  ;
  ;     *tris2 = *VertexBuffer
  ;     *norm2 = *NormalBuffer
  ;     While
  ;
  ;     Wend
  ;
  ;     *tris + SizeOf(STriangle)
  ;     *norm + SizeOf(STriangle)
  ;   Wend

  glEnableClientState_(#GL_VERTEX_ARRAY)
  glEnableClientState_(#GL_NORMAL_ARRAY)

  ;   glEnable_(#GL_BLEND)
  ;   glBlendFunc_(#GL_ONE, #GL_ONE)

  glNormalPointer_(#GL_FLOAT, 0, *NormalBuffer)
  glVertexPointer_(3, #GL_FLOAT, 0, *VertexBuffer)
  glDrawArrays_(#GL_TRIANGLES, 0, poly / SizeOf(SVector))

  ;   glDisable_(#GL_BLEND)

  glDisableClientState_(#GL_VERTEX_ARRAY)
  glDisableClientState_(#GL_NORMAL_ARRAY)

  ;   FreeMemory(*NormalBuffer)
  ;   FreeMemory(*VertexBuffer)
EndProcedure

Procedure Light_(Light, X.f, Y.f, Z.f, R.f, G.f, B.f)
  Dim LPos.f(3)
  Dim LCol.f(3)

  LPos(0) = X.f
  LPos(1) = Y.f
  LPos(2) = Z.f
  LPos(3) = 1.0
  
  LCol(0) = R
  LCol(1) = G
  LCol(2) = B
  LCol(3) = 1.0

  lid = #GL_LIGHT0+Light
  glLoadIdentity_()
  glEnable_(lid)

  glLightfv_(lid, #GL_AMBIENT, @LCol())
  glLightfv_(lid, #GL_POSITION, @LPos())
EndProcedure

Procedure RecompileLights()
  If CountList(Lights()) = 0 : ProcedureReturn 0 : EndIf

  If glslContext = 0
    ForEach Lights()
      Light_(ListIndex(Lights()), Lights()\x, Lights()\y, Lights()\z, Lights()\color[0], Lights()\color[1], Lights()\color[2])
    Next
  Else
    error.s = Space(4096)

    If glslContext <> 0
      CallFunctionFast(glslDeleteObjectARB, glslContext)
    EndIf
    glslContext = CallFunctionFast(glslCreateProgramObjectARB)

    If glslContext = 0 : ProcedureReturn 0 : EndIf

    If glslVertexShader <> 0
      CallFunctionFast(glslDeleteObjectARB, glslVertexShader)
    EndIf
    If glslPixelShader <> 0
      CallFunctionFast(glslDeleteObjectARB, glslPixelShader)
    EndIf

    Pixel.s = ReplaceString(PeekS(?Shader_Pixel, ?EndShader_Pixel - ?Shader_Pixel), "lightCount", Str(CountList(Lights())))
    Vertex.s = PeekS(?Shader_Vertex, ?EndShader_Vertex - ?Shader_Vertex)

    ; Compile vertex shader
    result = 0
    *ShaderCode = @Vertex
    Size.l = Len(Vertex)
    glslVertexShader = CallFunctionFast(glslCreateShaderObjectARB, #GL_VERTEX_SHADER_ARB)
    CallFunctionFast(glslShaderSourceARB, glslVertexShader, 1, @*ShaderCode, @Size)
    CallFunctionFast(glslCompileShaderARB, glslVertexShader)
    CallFunctionFast(glslGetObjectParameterivARB, glslVertexShader, #GL_OBJECT_COMPILE_STATUS_ARB, @result)
    CallFunctionFast(glslAttachObjectARB, glslContext, glslVertexShader)
    *ShaderCode = 0

    If result = 0
      CallFunctionFast(glslGetInfoLogARB, glslVertexShader, Len(error), 0, error)

      MessageRequester("Error", "VertexShader" + Chr(10) + error)

      ProcedureReturn 0
    EndIf

    ; Compile pixel shader.
    result = 0
    *ShaderCode = @Pixel
    Size.l = Len(Pixel)
    glslPixelShader = CallFunctionFast(glslCreateShaderObjectARB, #GL_FRAGMENT_SHADER_ARB)
    CallFunctionFast(glslShaderSourceARB, glslPixelShader, 1, @*ShaderCode, @Size)
    CallFunctionFast(glslCompileShaderARB, glslPixelShader)
    CallFunctionFast(glslGetObjectParameterivARB, glslPixelShader, #GL_OBJECT_COMPILE_STATUS_ARB, @result)
    CallFunctionFast(glslAttachObjectARB, glslContext, glslPixelShader)
    *ShaderCode = 0

    If result = 0
      CallFunctionFast(glslGetInfoLogARB, glslPixelShader, Len(error), 0, error)

      MessageRequester("Error", "PixelShader" + Chr(10) + error)

      ProcedureReturn 0
    EndIf

    result = 0
    CallFunctionFast(glslLinkProgramARB, glslContext)
    CallFunctionFast(glslGetObjectParameterivARB, glslContext, #GL_OBJECT_LINK_STATUS_ARB, @result)

    If result = 0
      CallFunctionFast(glslGetInfoLogARB, glslContext, Len(error), 0, error)

      MessageRequester("Error", "Linker" + Chr(10) + error)

      ProcedureReturn 0
    EndIf

    CallFunctionFast(glslUseProgramObjectARB, glslContext)

    glslAmbientColor = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"ambientColor")
    glslMatAmbient = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"mat.matAmbient")
    glslMatDiffuse = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"mat.matDiffuse")
    glslMatSpecular = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"mat.matSpecular")
    glslEmissive = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"mat.emissive")
    glslShininess = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"mat.shininess")
    glslCameraPos = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"cameraPos")
    glslTexture = CallFunctionFast(glslGetUniformLocationARB, glslContext, @"decal")

    If glslTexture <> 0
      CallFunctionFast(glslUniform1iARB, glslTexture, 0)
    EndIf

    ForEach Lights()
      Lights()\glslLightColor = CallFunctionFast(glslGetUniformLocationARB, glslContext, "light["+Str(ListIndex(Lights()))+"].lightColor")
      Lights()\glslLightPos = CallFunctionFast(glslGetUniformLocationARB, glslContext, "light["+Str(ListIndex(Lights()))+"].lightPos")

      If Lights()\glslLightPos <> 0 And Lights()\glslLightColor <> 0
        CallFunctionFast(glslUniform4fARB, Lights()\glslLightPos, Lights()\x, Lights()\y, Lights()\z, 1.0)
        CallFunctionFast(glslUniform4fARB, Lights()\glslLightColor, Lights()\color[0], Lights()\color[1], Lights()\color[2], 1.0)
      EndIf
    Next

    CallFunctionFast(glslUniform4fARB, glslAmbientColor, 0.8, 0.8, 0.8, 1.0)
    CallFunctionFast(glslUniform4fARB, glslMatAmbient, 0.25, 0.25, 0.25, 1.0)
    CallFunctionFast(glslUniform4fARB, glslMatDiffuse, 0.5, 0.5, 0.5, 1.0)
    CallFunctionFast(glslUniform4fARB, glslMatSpecular, 1.0, 1.0, 1.0, 1.0)
    CallFunctionFast(glslUniform4fARB, glslEmissive, 0.1, 0.1, 0.1, 1.0)
    CallFunctionFast(glslUniform1fARB, glslShininess, 20.0)
    CallFunctionFast(glslUniform4fARB, glslCameraPos, 0.0, 0.0, 30.0, 1.0)
  EndIf

  ProcedureReturn 1

  DataSection
    Shader_Pixel:
    IncludeBinary "pixelshader.txt"
    EndShader_Pixel:

    Shader_Vertex:
    IncludeBinary "vertexshader.txt"
    EndShader_Vertex:
  EndDataSection
EndProcedure

Procedure Create3DLight(ID.l, x.f, y.f, z.f, r.f, g.f, b.f)
  AddElement(Lights())
  Lights()\ID = ID
  Lights()\x = x
  Lights()\y = y
  Lights()\z = z

  Lights()\color[0] = r
  Lights()\color[1] = g
  Lights()\color[2] = b

  RecompileLights()
EndProcedure

Procedure Delete3DLight(ID.l)
  ForEach Lights()
    If Lights()\ID = ID
      DeleteElement(Lights())
    EndIf
  Next

  ProcedureReturn RecompileLights()
EndProcedure

If OpenWindow(0, 0, 0, #WindowWidth, #WindowHeight, "OpenGL Scene "+StrF(Version, 1), #WindowFlags)

  SetWindowCallback(@MyWindowCallback())

  hWnd = WindowID(0)
  hDC = GetDC_(hWnd)

  ;Initialize OpenGL
  pfd.PIXELFORMATDESCRIPTOR
  pfd\nSize        = SizeOf(PIXELFORMATDESCRIPTOR)
  pfd\nVersion     = 1
  pfd\dwFlags      = #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER | #PFD_DRAW_TO_WINDOW
  pfd\iLayerType   = #PFD_MAIN_PLANE
  pfd\iPixelType   = #PFD_TYPE_RGBA
  pfd\cColorBits   = 32
  pfd\cDepthBits   = 16
  pixformat = ChoosePixelFormat_(hDC, pfd)
  SetPixelFormat_(hDC, pixformat, pfd)
  hrc = wglCreateContext_(hDC)
  wglMakeCurrent_(hDC, hrc)

  glslCreateProgramObjectARB = wglGetProcAddress_("glCreateProgramObjectARB")
  glslCreateShaderObjectARB = wglGetProcAddress_("glCreateShaderObjectARB")
  glslCompileShaderARB = wglGetProcAddress_("glCompileShaderARB")
  glslLinkProgramARB = wglGetProcAddress_("glLinkProgramARB")
  glslGetInfoLogARB = wglGetProcAddress_("glGetInfoLogARB")
  glslDeleteObjectARB  = wglGetProcAddress_("glDeleteObjectARB")
  glslUseProgramObjectARB = wglGetProcAddress_("glUseProgramObjectARB")
  glslShaderSourceARB = wglGetProcAddress_("glShaderSourceARB")
  glslAttachObjectARB = wglGetProcAddress_("glAttachObjectARB")
  glslGetObjectParameterivARB = wglGetProcAddress_("glGetObjectParameterivARB")
  glslGetUniformLocationARB = wglGetProcAddress_("glGetUniformLocationARB")
  glslUniform4fvARB = wglGetProcAddress_("glUniform4fvARB")
  glslUniform4fARB = wglGetProcAddress_("glUniform4fARB")
  glslUniform2fARB = wglGetProcAddress_("glUniform2fARB")
  glslUniform1fARB = wglGetProcAddress_("glUniform1fARB")
  glslUniform1iARB = wglGetProcAddress_("glUniform1iARB")

  Extensions.s = PeekS(glGetString_(#GL_EXTENSIONS))
  If FindString(Extensions, "WGL_EXT_swap_control", 0)
    wglSwapIntervalEXT = wglGetProcAddress_("wglSwapIntervalEXT")
    If wglSwapIntervalEXT
      CallFunctionFast(wglSwapIntervalEXT, 0)
    EndIf
  EndIf

  If glslCreateProgramObjectARB <> 0 And FindString(Extensions, "GL_ARB_shading_language_100", 1) <> 0 And FindString(Extensions, "GL_ARB_shader_objects", 1) <> 0
    glslContext = CallFunctionFast(glslCreateProgramObjectARB)
  Else
    glEnable_(#GL_LIGHTING)
  EndIf

  glEnable_(#GL_DEPTH_TEST)
  glEnable_(#GL_CULL_FACE)
  glEnable_(#GL_NORMALIZE)

  Create3DLight(0, 15.0, 20.0, 10.0, 0.0, 0.0, 1.0)
  Create3DLight(1, 0.0, 0.0, 15.0, 1.0, 0.0, 0.0)
  Create3DLight(2, 15.0, 0.0, 5.0, 1.0, 1.0, 0.0)
  Create3DLight(3, 0.0, 20.0, 15.0, 0.0, 1.0, 0.0)

  Time = ElapsedMilliseconds() - 1000
  Counter = 0
  FPS_Avg = 0

  Repeat
    If WindowEvent() = #PB_Event_CloseWindow
      Quit = 1
    EndIf

    timeResult = (ElapsedMilliseconds() - Time)
    If timeResult > 0
      FPS = 1000 / timeResult
    EndIf
    Time = ElapsedMilliseconds()
    Counter + 1

    If FPS_Avg = 0
      FPS_Avg = FPS
    Else
      FPS_Avg = (FPS_Avg + FPS) * 0.5
    EndIf

    If Counter > 50
      SetWindowTitle(0, "FPS: "+Str(FPS_Avg))
      FPS_Avg = 0
      Counter = 0
    EndIf

    rotation + 0.1

    SetCamera(0, 45.0, 0.0, 0.0, -30.0, 0.0, 0.0, 0.0, 0.1, 1000.0)

    glLoadIdentity_()
    glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)

    glTranslatef_(-10.0, -5.0, -5.0)
    glColor3f_(1.0, 1.0, 1.0)
    
    DrawMetaballs(Pow(2, 12), 15, 11, 9)
    
    SwapBuffers_(hDC)
    
    ;If FPS > 50
    Delay(1)
    ;EndIf
  Until Quit = 1

  FreeMemory(*VertexBuffer)
  FreeMemory(*NormalBuffer)

  ReleaseDC_(hWnd, hDC)

  If glslVertexShader <> 0
    CallFunctionFast(glslDeleteObjectARB, glslVertexShader)
  EndIf
  If glslPixelShader <> 0
    CallFunctionFast(glslDeleteObjectARB, glslPixelShader)
  EndIf

  If glslContext <> 0
    CallFunctionFast(glslDeleteObjectARB, glslContext)
  EndIf

EndIf

End

ERROR:
MessageRequester("ERROR", "In line "+Str(GetErrorLineNR())+Chr(10)+Chr(10)+GetErrorDescription())
; IDE Options = PureBasic v4.02 (Windows - x86)
; CursorPosition = 1175
; FirstLine = 1059
; Folding = ---
; EnableOnError
; Executable = Metaballs.exe
; DisableDebugger
pixelshader.txt:

Code: Select all

struct Light
{
   vec4 lightColor;
   vec4 lightPos;
};


struct Material
{
   vec4 matAmbient;
   vec4 matDiffuse;
   vec4 matSpecular;
   vec4 emissive;
   float shininess;
};


varying vec3 normal;
varying vec4 pos;


uniform sampler2D decal;
uniform Light light[lightCount];
uniform Material mat;
uniform vec4 ambientColor;
uniform vec4 cameraPos;


void calDiffuseSpecular(Light theLight, vec4 position, vec3 norm, vec4 camPos, float shininess, out vec4 diffuseOut, out vec4 specularOut)
{
   vec4 lightVec = normalize(theLight.lightPos - position);
   float diffuseLight = max(dot(norm, vec3(lightVec)), 0.0);
   diffuseOut = theLight.lightColor * diffuseLight;
   
   vec4 eyeVec = normalize(camPos - position);
   vec4 halfVec = normalize(lightVec + eyeVec);
   float specularLight = pow(max(dot(norm, vec3(halfVec)), 0.0), shininess);
   
   if(diffuseLight <= 0.0) {
     specularLight = 0.0;
   }
   
   specularOut = theLight.lightColor * specularLight;
}


void main()
{
   vec3 n = normalize(normal);
   
   vec4 ambient = mat.matAmbient * ambientColor;

   vec4 diffuseLight;
   vec4 specularLight;
   vec4 diffuseSum = vec4(0.0, 0.0, 0.0, 0.0);
   vec4 specularSum = vec4(0.0, 0.0, 0.0, 0.0);
   
   for(int k=0; k < lightCount; k++) {
     Light theLight = light[k];
     calDiffuseSpecular(theLight, pos, n, cameraPos, mat.shininess, diffuseLight, specularLight);
     diffuseSum += diffuseLight;
     specularSum += specularLight;
   }
   
   vec4 diffuse = mat.matDiffuse * diffuseSum;
   vec4 specular = mat.matSpecular * specularSum;
   
   gl_FragColor = (mat.emissive + ambient + diffuse + specular);
   gl_FragColor.a = 1.0;
}
vertexshader.txt:

Code: Select all

varying vec2 texCoord0;
varying vec3 normal;
varying vec4 pos;


void main()
{
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
   
   texCoord0 = gl_MultiTexCoord0.st;
   
   normal = gl_NormalMatrix * gl_Normal;
   pos = gl_Vertex;
}
Caution: this is very old.
bye,
Daniel
Post Reply