Page 1 of 1

Some tips for SetMeshData() and OGRE

Posted: Fri Jul 02, 2004 12:21 pm
by dige
The following information is a summary of different individual posting
and my own experiences. Special thanks goes to Danilo!

Hope that helps someone to get light into the dark mysterious OGRE/PB world ;-)

Code: Select all

SetMeshData () – Tutorial ( DiGe 06/2994 German Forum )
http://robsite.de/php/pureboard/viewtopic.php?t=4924

------------------------------
 Technical background
------------------------------
Maxium Vertices pro Mesh: 65.000
127 x 127 = 16.129
            16.129 * 4 corners = 64.516 vertices ( Posting from Danilo )

SetMeshData () copies the Data and + Structures to OGRE’s memory. You can do this several times for the same mesh and the entity will changed ... useful for animations and deformations. 


------------------------------
 Vertices ( Corner points )
------------------------------
Vertices define points in a 3d area and contents 3 floats ( x.f; y.f; z.f )
This is the first step to create a 3d model. 
 

------------------------------
 Faces ( areas )
------------------------------
The second step is connect the vertices to faces. PureBasic only supports triangular faces. ( other faces could be: lines, polygons, quads ... )
The sequence (direction) of definition will specify the back or front of each face. It is necessary to work clockwise or against the clock. If you want to have both sides of a face visible, you’ll have to define 2 faces in clockwise and opposite direction.

1 Faces contains 3 words ( v1.w, v2.w, v3.w )


------------------------------
 Quad faces
------------------------------
As I wrote already, PB supports only triangular faces. So if you need lines or quads you’ll have to build it from two triangles.

(-1,1,0)     (1,1,0)
Vertex 3      Vertex 2
      O-------O
      |      /|
      | II  / |
      |    /  |
      |   x   |
      |  /    |
      | /  I  |
      |/      |
      O-------O
Vertex 0    Vertex 1
(-1,-1,0)   (1,-1,0)

x  = center (0,0,0)  I = 1. Triangle  II = 2. Triangle
4 Vertics: 0, 1, 2, 3 and two triangular faces: I (2, 1, 0), II(0, 3, 2)



------------------------------
 Textures UV
------------------------------

The Texturcoordinates for each face are 8 floats ( 4 x 2 ), witch define a rectangle inside the texture-bitmap.

  1 +   
    |
    |
0.5 +    [Textur]
    |
    |
    +-------+-------+
    0      0.5      1 

If you want to use the whole bitmap: 0.0,0.0, 1.0,0.0, 1.0,1.0, 0.0,1.0
Values > 1 causes that the texture is represented several times.


------------------------------
 Meshes
------------------------------
A mesh contains vertices, faces, colors, texturecoordinates and normals.
Meshes will filled up with SetMeshData (). The following overview shows the needed data, types und values:

 #PB_Mesh_Vertices      1 Vertex = 3 Floats x, y, z
 #PB_Mesh_Triangles     1 Face   = 3 Words  0-2-1
 #PB_Mesh_UVCoordinates 1 UV     = 2 Floats x, y      1 Face -> 8 Floats
 #PB_Mesh_Normals       1 Nrm    = 3 Floats x, y, z   1 Face -> 9 Floats
 #PB_Mesh_Colors        1 Col    = 3 Floats x, y, z 

From my point of view it is useful to create the biggest meshes first. Another speed improvement is to divide big meshes into smaller parts. It seems that OGRE can calculate it better.


------------------------------
 Enitiys
------------------------------
You can add materials to meshes -> called entity. The pivot point ( for rotation etc. ) is always 0, 0, 0. So if you want to rotated an entity around itself you have to create it at the coordinates origin and the center of your mesh must be located at 0, 0, 0. And then move the object to its target position.
If you create Meshes with PB-Arrays, remind that Dim(10) means 11 Elements!


------------------------------
 OGRE-PB Coordinate-System
------------------------------

   +Y
    |
    |
    |
    +------ +X
   / 
  /  
 /   
+Z


------------------------------
 Light and Normal-Vectors
------------------------------

To render lights, shadows and reflections its necessary to calculate the normal vector from each face and all connected vertices. 
1 Normal-Vector needs 3 floats.

plan view:             side view:

+----------------X     +----------------X
|    2                 |   0    1
|    +                 |   +----+
|    | \               |      |
|    |  \              |      |
|    | S + 1           |      N ( 0, 1, 0 )
|    |  /              | 
|    | /               |
|    +                 |
|    0                 |
Z                      Y


We have only triangular faces ... so it is very easy to calculate the normals:	

    Norm_x1 = (y1 - y2) * (z2 - z3) - (z1 - z2) * (y2 - y3)
    Norm_y1 = (z1 - z2) * (x2 - x3) - (x1 - x2) * (z2 - z3)
    Norm_z1 = (x1 - x2) * (y2 - y3) - (y1 - y2) * (x2 - x3)
  
    Length = Sqr( Norm_x1² + Norm_y1² + Norm_z1² )
    If Length = 0 : Length = 1 : EndIf

    Norm_x1 / Length
    Norm_y1 / Length
    Norm_z1 / Length
  

And here a working example for demonstration:

Code: Select all

; SetMeshData / Normals Example by DiGe 07/2004

Structure _Vertices
  x1.f ; Vertex 1
  y1.f
  z1.f
  x2.f ; Vertex 2
  y2.f
  z2.f
  x3.f ; Vertex 3
  y3.f
  z3.f
EndStructure

Structure _Triangles
  TriangleF_a.w
  TriangleF_b.w
  TriangleF_c.w
 
  TriangleB_a.w
  TriangleB_b.w
  TriangleB_c.w
EndStructure

Structure _TextureCoordinates
  Vertex1_a.f ; Vertex 1
  Vertex1_b.f
  Vertex2_a.f ; Vertex 2
  Vertex2_b.f
  Vertex3_a.f ; Vertex 3
  Vertex3_b.f
  Vertex4_a.f ; Vertex 4
  Vertex4_b.f
EndStructure

Structure _Normals
  x1.f ; Normals Vertex 1
  y1.f
  z1.f
  x2.f ; Normals Vertex 2
  y2.f
  z2.f
  x3.f ; Normals Vertex 3
  y3.f
  z3.f
EndStructure

Structure _Colors
  ; Farben für jede Seite des Dreieckes
  col_a.l
  col_b.l
  col_c.l
EndStructure

Procedure GetNormals ( *Vertics, *Normals, Negativ.b )
 
  *TEMP._Vertices = *Vertics
  *NRML._Normals  = *Normals
 
  If Negativ
    *NRML\x1 = ((*TEMP\y3 - *TEMP\y2) * (*TEMP\z2 - *TEMP\z1)) - ((*TEMP\z3 - *TEMP\z2) * (*TEMP\y2 - *TEMP\y1))
    *NRML\y1 = ((*TEMP\z3 - *TEMP\z2) * (*TEMP\x2 - *TEMP\x1)) - ((*TEMP\x3 - *TEMP\x2) * (*TEMP\z2 - *TEMP\z1))
    *NRML\z1 = ((*TEMP\x3 - *TEMP\x2) * (*TEMP\y2 - *TEMP\y1)) - ((*TEMP\y3 - *TEMP\y2) * (*TEMP\x2 - *TEMP\x1))
  Else
    *NRML\x1 = ((*TEMP\y1 - *TEMP\y2) * (*TEMP\z2 - *TEMP\z3)) - ((*TEMP\z1 - *TEMP\z2) * (*TEMP\y2 - *TEMP\y3))
    *NRML\y1 = ((*TEMP\z1 - *TEMP\z2) * (*TEMP\x2 - *TEMP\x3)) - ((*TEMP\x1 - *TEMP\x2) * (*TEMP\z2 - *TEMP\z3))
    *NRML\z1 = ((*TEMP\x1 - *TEMP\x2) * (*TEMP\y2 - *TEMP\y3)) - ((*TEMP\y1 - *TEMP\y2) * (*TEMP\x2 - *TEMP\x3))
  EndIf
 
  Length.f = Sqr( *NRML\x1 * *NRML\x1 + *NRML\y1 * *NRML\y1 + *NRML\z1 * *NRML\z1)
  If Length = 0 : Length = 1 : EndIf
 
  *NRML\x1 / Length
  *NRML\y1 / Length
  *NRML\z1 / Length
 
  *NRML\x2 = *NRML\x1
  *NRML\y2 = *NRML\y1
  *NRML\z2 = *NRML\z1
 
  *NRML\x3 = *NRML\x1
  *NRML\y3 = *NRML\y1
  *NRML\z3 = *NRML\z1
 
EndProcedure

Procedure InitGameTimer()
  ; initialize highres timing function TimeGetTime_()
  Shared _GT_DevCaps.TIMECAPS
  timeGetDevCaps_(_GT_DevCaps,SizeOf(TIMECAPS))
  timeBeginPeriod_(_GT_DevCaps\wPeriodMin)
EndProcedure

Procedure StopGameTimer()
  ; de-initialize highres timing function TimeGetTime_()
  Shared _GT_DevCaps.TIMECAPS
  timeEndPeriod_(_GT_DevCaps\wPeriodMin)
EndProcedure

Procedure ShowError(error$)
  #ERR_1 = "Cant create "
  #ERR_2 = " !"+Chr(13)+"(out of memory?)"
  MessageRequester("ERROR",#ERR_1+error$+#ERR_2,#MB_ICONERROR)
  End
EndProcedure

;{ Initialisierung
If InitEngine3D() And InitSprite() And InitKeyboard() And InitMouse()
 
  #LOOPTIME   = 1000/60  ; 60 Frames in 1000ms (1second)
  SmallFont = LoadFont(0,"Tahoma", 10, #PB_Font_Bold)
 
  If OpenWindow(0, 0, 0, 800, 600, #PB_Window_SystemMenu|#PB_Window_ScreenCentered, "OGRE Rocks")
    If OpenWindowedScreen(WindowID(),0, 0, 800, 600, 0, 0, 0)=0
      MessageRequester("ERROR","Cant open DirectX screen !",#MB_ICONERROR):End
    EndIf
  EndIf
 
  Dim TextureCoordinates._TextureCoordinates (3)
  Dim Triangles._Triangles(3)
  Dim Vertices._Vertices  (3)
  Dim Normals._Normals    (3)
 
; Pyramide
  Restore Pyramide_Vertics
  For a = 0 To 3
    Read Vertices(a)\x1
    Read Vertices(a)\y1
    Read Vertices(a)\z1
   
    Read Vertices(a)\x2
    Read Vertices(a)\y2
    Read Vertices(a)\z2
   
    Read Vertices(a)\x3
    Read Vertices(a)\y3
    Read Vertices(a)\z3
   
    Vertices(a)\x1 - 1
    Vertices(a)\x2 - 1
    Vertices(a)\x3 - 1
   
    Vertices(a)\z1 - 1
    Vertices(a)\z2 - 1
    Vertices(a)\z3 - 1
   
    GetNormals(@Vertices(a), @Normals(a), 0 )
  Next
 
  Restore Pyramide_Faces
  For a = 0 To 3
    Read Triangles(a)\TriangleF_a
    Read Triangles(a)\TriangleF_b
    Read Triangles(a)\TriangleF_c
   
    Read Triangles(a)\TriangleB_a
    Read Triangles(a)\TriangleB_b
    Read Triangles(a)\TriangleB_c
  Next 
 
  For a = 0 To 3
    Restore Pyramide_UV
    Read TextureCoordinates(a)\Vertex1_a
    Read TextureCoordinates(a)\Vertex1_b
   
    Read TextureCoordinates(a)\Vertex2_a
    Read TextureCoordinates(a)\Vertex2_b
   
    Read TextureCoordinates(a)\Vertex3_a
    Read TextureCoordinates(a)\Vertex3_b
   
    Read TextureCoordinates(a)\Vertex4_a
    Read TextureCoordinates(a)\Vertex4_b
  Next

  If CreateMesh(0)
    SetMeshData( 0, #PB_Mesh_Vertices     ,@Vertices()          , 12 * 3 )
    SetMeshData( 0, #PB_Mesh_Triangles    ,@Triangles()         , 4  * 2 )
    SetMeshData( 0, #PB_Mesh_UVCoordinates,@TextureCoordinates(), 4  * 2 )
    SetMeshData( 0, #PB_Mesh_Normals      ,@Normals()           , 4  * 3 )
 
    If CreateTexture(0, 64, 64)
      If StartDrawing(TextureOutput(0))
        Box(0,0,64,64,$FF0000)
        Box(1,1,62,62,$00FFFF)
        FrontColor( 0, 0, 0 )
        DrawingMode(1)
        Locate ( 3, 5 ) : DrawText( "LiGHT" )
        StopDrawing()
      EndIf
 
      CreateMaterial(0,TextureID(0))
 
      If CreateEntity(0, MeshID(0),MaterialID(0))
        MaterialShadingMode  (0, #PB_Material_Flat )
        MaterialDiffuseColor (0, RGB($FF,$FF,$FF))
        MaterialAmbientColor (0, RGB($90,$90,$90))
        MaterialSpecularColor(0, RGB($F0,$F0,$F0))
        MaterialFilteringMode(0, #PB_Material_Trilinear )
      EndIf
     
      CopyEntity ( 0, 1 ) : ResizeEntity( 1, 0.5, 0.5, 0.5 )
      CopyEntity ( 1, 2 ) : ResizeEntity( 2, 0.25, 0.25, 0.25 )
      CopyEntity ( 1, 3 ) : ResizeEntity( 3, 0.75, 0.75, 0.75 )
      CopyEntity ( 1, 4 ) : ResizeEntity( 4, 1.25, 1.25, 1.25 )
     
      EntityLocate( 1, -2, 0, 2 )
      EntityLocate( 2,  2, 0, 2 )
      EntityLocate( 3, -2, 0, -2 )
      EntityLocate( 4,  2, 0, -2 )
     
    EndIf
  EndIf
 
  CreateCamera (0, 0, 0, 100, 100)
  CameraRange  (0, 0.1, 400 )
  CameraLookAt (0, 0, 0, 0 )
  CameraLocate (0, 0, 1, 5 )
 
  If CreateLight(1,RGB($FF,$FF,$FF))=0:ShowError("light"):Else:LightLocate(1, 0, 1, 2):EndIf
 
  ; start game timer
  InitGameTimer()
  LoopTimer = timeGetTime_()
  ;}
;{ Schleife, Abfrage
Repeat
  If fullscreen
    While ( timeGetTime_()-LoopTimer )<#LOOPTIME : Delay(1) : Wend
    LoopTimer = timeGetTime_()
  Else
    Repeat
      Event=WindowEvent()
      If Event=#PB_Event_CloseWindow
        Quit = #True
      ElseIf Event=0
        While ( timeGetTime_()-LoopTimer )<#LOOPTIME : Delay(1) : Wend
        LoopTimer = timeGetTime_()
      EndIf
    Until Event=0
  EndIf
 
  ; check keys
  If ExamineKeyboard()
    If KeyboardPushed(#PB_Key_Right)
    MoveCamera(0, 1,0,0):EndIf
    If KeyboardPushed(#PB_Key_Left)
    MoveCamera(0,-1,0,0):EndIf
    If KeyboardPushed(#PB_Key_Up)
    MoveCamera(0,0,0,-1):EndIf
    If KeyboardPushed(#PB_Key_Down)
    MoveCamera(0,0,0, 1):EndIf
    If KeyboardPushed(#PB_Key_F3)
      FOV - 1 : If FOV < 40:FOV=40:EndIf
    CameraFOV(0,FOV):EndIf
    If KeyboardPushed(#PB_Key_F4)
      FOV + 1 : If FOV > 120:FOV=120:EndIf
    CameraFOV(0,FOV):EndIf
   
    If keypressed=0
      If KeyboardPushed(#PB_Key_F1)
      HideText!1 : keypressed=20 : EndIf
      If KeyboardPushed(#PB_Key_F2)
        RenderMode+1 : If RenderMode=3:RenderMode=0:EndIf
      CameraRenderMode(0,RenderMode):keypressed=20:EndIf
      If KeyboardPushed(#PB_Key_F5)
        ScaleEntity(enti, 1.1, 1.1, 1.1)
      EndIf
    Else
      keypressed-1
    EndIf
  EndIf
 
  ; mouse freelook
  If ExamineMouse()
    RotateCamera(0,-MouseDeltaX(),-MouseDeltaY(),0)
  EndIf
 
  RotateEntity( 0, 1, 0, 0 )
 
  ; info text
  If HideText=0
    If StartDrawing(ScreenOutput())
      DrawingMode(1):FrontColor($40,$FF,$00):DrawingFont(SmallFont)
      Locate( 15,15):DrawText("F2     : RenderMode")
      Locate( 15,30):DrawText("Count  : "+Str( CountRenderedTriangles() ))
      Locate( 15,45):DrawText("FPS    : "+Str( Engine3DFrameRate(#PB_Engine3D_Current)))
     
      Locate(250,15):DrawText("CameraX: "+RSet(StrF(CameraX(0),2),4,"0"))
      Locate(250,30):DrawText("CameraY: "+RSet(StrF(CameraY(0),2),4,"0"))
      Locate(250,45):DrawText("CameraZ: "+RSet(StrF(CameraZ(0),2),4,"0"))
     
      StopDrawing()
    EndIf
  EndIf
 
  FlipBuffers()
  RenderWorld()
 
Until KeyboardPushed(#PB_Key_Escape) Or Quit
StopGameTimer()
Else
  MessageRequester("Error", "Cant init DirectX 3D Engine",0)
EndIf
;} 
End

;{ Daten-Sektion
DataSection

Pyramide_Vertics:
  Data.f 0,0,0 ; Vertex0
  Data.f 1,2,1 ; Vertex1
  Data.f 2,0,0 ; Vertex2
 
  Data.f 2,0,0 ; Vertex3
  Data.f 1,2,1 ; Vertex4
  Data.f 2,0,2 ; Vertex5
 
  Data.f 2,0,2 ; Vertex6
  Data.f 1,2,1 ; Vertex7
  Data.f 0,0,2 ; Vertex8
 
  Data.f 0,0,2 ; Vertex9
  Data.f 1,2,1 ; Vertex10
  Data.f 0,0,0 ; Vertex11

Pyramide_Faces:
  Data.w 0, 1, 2 ; Face 1
  Data.w 0, 2, 1 ; Face 2
 
  Data.w 3, 4, 5 ; Face 3
  Data.w 3, 5, 4 ; Face 4
 
  Data.w 6, 7, 8 ; Face 5
  Data.w 6, 8, 7 ; Face 6
 
  Data.w 9, 10, 11 ; Face 7
  Data.w 9, 11, 10 ; Face 8

Pyramide_UV:
  Data.f 0.0, 0.0
  Data.f 0.0, 3.0
  Data.f 3.0, 3.0
  Data.f 3.0, 0.0

EndDataSection
;} 

Posted: Mon Jul 07, 2008 11:47 am
by Ollivier
Hi Dige !

I updated your example for PB last versions.

Thanks for this old but interesting help !

Code: Select all

; SetMeshData / Normals Example by DiGe 07/2004 

Structure _Vertices 
  x1.f ; Vertex 1 
  y1.f 
  z1.f 
  x2.f ; Vertex 2 
  y2.f 
  z2.f 
  x3.f ; Vertex 3 
  y3.f 
  z3.f 
EndStructure 

Structure _Triangles 
  TriangleF_a.w 
  TriangleF_b.w 
  TriangleF_c.w 
  
  TriangleB_a.w 
  TriangleB_b.w 
  TriangleB_c.w 
EndStructure 

Structure _TextureCoordinates 
  Vertex1_a.f ; Vertex 1 
  Vertex1_b.f 
  Vertex2_a.f ; Vertex 2 
  Vertex2_b.f 
  Vertex3_a.f ; Vertex 3 
  Vertex3_b.f 
  Vertex4_a.f ; Vertex 4 
  Vertex4_b.f 
EndStructure 

Structure _Normals 
  x1.f ; Normals Vertex 1 
  y1.f 
  z1.f 
  x2.f ; Normals Vertex 2 
  y2.f 
  z2.f 
  x3.f ; Normals Vertex 3 
  y3.f 
  z3.f 
EndStructure 

Structure _Colors 
  ; Farben für jede Seite des Dreieckes 
  col_a.l 
  col_b.l 
  col_c.l 
EndStructure 

Procedure GetNormals ( *Vertics, *Normals, Negativ.b ) 
  
  *TEMP._Vertices = *Vertics 
  *NRML._Normals  = *Normals 
  
  If Negativ 
    *NRML\x1 = ((*TEMP\y3 - *TEMP\y2) * (*TEMP\z2 - *TEMP\z1)) - ((*TEMP\z3 - *TEMP\z2) * (*TEMP\y2 - *TEMP\y1)) 
    *NRML\y1 = ((*TEMP\z3 - *TEMP\z2) * (*TEMP\x2 - *TEMP\x1)) - ((*TEMP\x3 - *TEMP\x2) * (*TEMP\z2 - *TEMP\z1)) 
    *NRML\z1 = ((*TEMP\x3 - *TEMP\x2) * (*TEMP\y2 - *TEMP\y1)) - ((*TEMP\y3 - *TEMP\y2) * (*TEMP\x2 - *TEMP\x1)) 
  Else 
    *NRML\x1 = ((*TEMP\y1 - *TEMP\y2) * (*TEMP\z2 - *TEMP\z3)) - ((*TEMP\z1 - *TEMP\z2) * (*TEMP\y2 - *TEMP\y3)) 
    *NRML\y1 = ((*TEMP\z1 - *TEMP\z2) * (*TEMP\x2 - *TEMP\x3)) - ((*TEMP\x1 - *TEMP\x2) * (*TEMP\z2 - *TEMP\z3)) 
    *NRML\z1 = ((*TEMP\x1 - *TEMP\x2) * (*TEMP\y2 - *TEMP\y3)) - ((*TEMP\y1 - *TEMP\y2) * (*TEMP\x2 - *TEMP\x3)) 
  EndIf 
  
  Length.f = Sqr( *NRML\x1 * *NRML\x1 + *NRML\y1 * *NRML\y1 + *NRML\z1 * *NRML\z1) 
  If Length = 0 : Length = 1 : EndIf 
  
  *NRML\x1 / Length 
  *NRML\y1 / Length 
  *NRML\z1 / Length 
  
  *NRML\x2 = *NRML\x1 
  *NRML\y2 = *NRML\y1 
  *NRML\z2 = *NRML\z1 
  
  *NRML\x3 = *NRML\x1 
  *NRML\y3 = *NRML\y1 
  *NRML\z3 = *NRML\z1 
  
EndProcedure 

Procedure InitGameTimer() 
  ; initialize highres timing function TimeGetTime_() 
  Shared _GT_DevCaps.TIMECAPS 
  timeGetDevCaps_(_GT_DevCaps,SizeOf(TIMECAPS)) 
  timeBeginPeriod_(_GT_DevCaps\wPeriodMin) 
EndProcedure 

Procedure StopGameTimer() 
  ; de-initialize highres timing function TimeGetTime_() 
  Shared _GT_DevCaps.TIMECAPS 
  timeEndPeriod_(_GT_DevCaps\wPeriodMin) 
EndProcedure 

Procedure ShowError(error$) 
  #ERR_1 = "Cant create " 
  #ERR_2 = " !"+Chr(13)+"(out of memory?)" 
  MessageRequester("ERROR",#ERR_1+error$+#ERR_2,#MB_ICONERROR) 
  End 
EndProcedure 

;{ Initialisierung 
If InitEngine3D() And InitSprite() And InitKeyboard() And InitMouse() 
  
  #LOOPTIME   = 1000/60  ; 60 Frames in 1000ms (1second) 
  SmallFont = LoadFont(0,"Tahoma", 10, #PB_Font_Bold) 
  
  If OpenWindow(0, 0, 0, 800, 600, "OGRE Rocks", #PB_Window_SystemMenu|#PB_Window_ScreenCentered) 
    If OpenWindowedScreen(WindowID(0),0, 0, 800, 600, 0, 0, 0)=0 
      MessageRequester("ERROR","Cant open DirectX screen !",#MB_ICONERROR):End 
    EndIf 
  EndIf 
  
  Dim TextureCoordinates._TextureCoordinates (3) 
  Dim Triangles._Triangles(3) 
  Dim Vertices._Vertices  (3) 
  Dim Normals._Normals    (3) 
  
; Pyramide 
  Restore Pyramide_Vertics 
  For a = 0 To 3 
    Read Vertices(a)\x1 
    Read Vertices(a)\y1 
    Read Vertices(a)\z1 
    
    Read Vertices(a)\x2 
    Read Vertices(a)\y2 
    Read Vertices(a)\z2 
    
    Read Vertices(a)\x3 
    Read Vertices(a)\y3 
    Read Vertices(a)\z3 
    
    Vertices(a)\x1 - 1 
    Vertices(a)\x2 - 1 
    Vertices(a)\x3 - 1 
    
    Vertices(a)\z1 - 1 
    Vertices(a)\z2 - 1 
    Vertices(a)\z3 - 1 
    
    GetNormals(@Vertices(a), @Normals(a), 0 ) 
  Next 
  
  Restore Pyramide_Faces 
  For a = 0 To 3 
    Read Triangles(a)\TriangleF_a 
    Read Triangles(a)\TriangleF_b 
    Read Triangles(a)\TriangleF_c 
    
    Read Triangles(a)\TriangleB_a 
    Read Triangles(a)\TriangleB_b 
    Read Triangles(a)\TriangleB_c 
  Next 
  
  For a = 0 To 3 
    Restore Pyramide_UV 
    Read TextureCoordinates(a)\Vertex1_a 
    Read TextureCoordinates(a)\Vertex1_b 
    
    Read TextureCoordinates(a)\Vertex2_a 
    Read TextureCoordinates(a)\Vertex2_b 
    
    Read TextureCoordinates(a)\Vertex3_a 
    Read TextureCoordinates(a)\Vertex3_b 
    
    Read TextureCoordinates(a)\Vertex4_a 
    Read TextureCoordinates(a)\Vertex4_b 
  Next 

  If CreateMesh(0, 256) 
    SetMeshData( 0, #PB_Mesh_Vertex     ,@Vertices()          , 12 * 3 ) 
    SetMeshData( 0, #PB_Mesh_Face    ,@Triangles()         , 4  * 2 ) 
    SetMeshData( 0, #PB_Mesh_UVCoordinate,@TextureCoordinates(), 4  * 2 ) 
    SetMeshData( 0, #PB_Mesh_Normal      ,@Normals()           , 4  * 3 ) 
  
    If CreateTexture(0, 64, 64) 
      If StartDrawing(TextureOutput(0)) 
        Box(0,0,64,64,$FF0000) 
        Box(1,1,62,62,$00FFFF) 
        FrontColor( 0 ) 
        DrawingMode(1) 
        DrawText(3,5, "LiGHT" ) 
        StopDrawing() 
      EndIf 
  
      CreateMaterial(0,TextureID(0)) 
  
      If CreateEntity(0, MeshID(0),MaterialID(0)) 
        MaterialShadingMode  (0, #PB_Material_Flat ) 
        MaterialDiffuseColor (0, RGB($FF,$FF,$FF)) 
        MaterialAmbientColor (0, RGB($90,$90,$90)) 
        MaterialSpecularColor(0, RGB($F0,$F0,$F0)) 
        MaterialFilteringMode(0, #PB_Material_Trilinear ) 
      EndIf 
      
      CopyEntity ( 0, 1 ) : ResizeEntity( 1, 0.5, 0.5, 0.5 ) 
      CopyEntity ( 1, 2 ) : ResizeEntity( 2, 0.25, 0.25, 0.25 ) 
      CopyEntity ( 1, 3 ) : ResizeEntity( 3, 0.75, 0.75, 0.75 ) 
      CopyEntity ( 1, 4 ) : ResizeEntity( 4, 1.25, 1.25, 1.25 ) 
      
      EntityLocate( 1, -2, 0, 2 ) 
      EntityLocate( 2,  2, 0, 2 ) 
      EntityLocate( 3, -2, 0, -2 ) 
      EntityLocate( 4,  2, 0, -2 ) 
      
    EndIf 
  EndIf 
  
  CreateCamera (0, 0, 0, 100, 100) 
  CameraRange  (0, 0.1, 400 ) 
  CameraLookAt (0, 0, 0, 0 ) 
  CameraLocate (0, 0, 1, 5 ) 
  
  If CreateLight(1,RGB($FF,$FF,$FF))=0:ShowError("light"):Else:LightLocate(1, 0, 1, 2):EndIf 
  
  ; start game timer 
  InitGameTimer() 
  LoopTimer = timeGetTime_() 
  ;} 
;{ Schleife, Abfrage 
Repeat 
  If fullscreen 
    While ( timeGetTime_()-LoopTimer )<#LOOPTIME : Delay(1) : Wend 
    LoopTimer = timeGetTime_() 
  Else 
    Repeat 
      Event=WindowEvent() 
      If Event=#PB_Event_CloseWindow 
        Quit = #True 
      ElseIf Event=0 
        While ( timeGetTime_()-LoopTimer )<#LOOPTIME : Delay(1) : Wend 
        LoopTimer = timeGetTime_() 
      EndIf 
    Until Event=0 
  EndIf 
  
  ; check keys 
  If ExamineKeyboard() 
    If KeyboardPushed(#PB_Key_Right) 
    MoveCamera(0, 1,0,0):EndIf 
    If KeyboardPushed(#PB_Key_Left) 
    MoveCamera(0,-1,0,0):EndIf 
    If KeyboardPushed(#PB_Key_Up) 
    MoveCamera(0,0,0,-1):EndIf 
    If KeyboardPushed(#PB_Key_Down) 
    MoveCamera(0,0,0, 1):EndIf 
    If KeyboardPushed(#PB_Key_F3) 
      FOV - 1 : If FOV < 40:FOV=40:EndIf 
    CameraFOV(0,FOV):EndIf 
    If KeyboardPushed(#PB_Key_F4) 
      FOV + 1 : If FOV > 120:FOV=120:EndIf 
    CameraFOV(0,FOV):EndIf 
    
    If keypressed=0 
      If KeyboardPushed(#PB_Key_F1) 
      HideText!1 : keypressed=20 : EndIf 
      If KeyboardPushed(#PB_Key_F2) 
        RenderMode+1 : If RenderMode=3:RenderMode=0:EndIf 
      CameraRenderMode(0,RenderMode):keypressed=20:EndIf 
      If KeyboardPushed(#PB_Key_F5) 
        ScaleEntity(enti, 1.1, 1.1, 1.1) 
      EndIf 
    Else 
      keypressed-1 
    EndIf 
  EndIf 
  
  ; mouse freelook 
  If ExamineMouse() 
    RotateCamera(0,-MouseDeltaX(),-MouseDeltaY(),0) 
  EndIf 
  
  RotateEntity( 0, 1, 0, 0 ) 
  
  ; info text 
  If HideText=0 
    If StartDrawing(ScreenOutput()) 
      DrawingMode(1):FrontColor(RGB($40,$FF,$00) ):DrawingFont(SmallFont) 
      DrawText(15, 15, "F2     : RenderMode") 
      DrawText(15, 30, "Count  : "+Str( CountRenderedTriangles() )) 
      DrawText(15, 45, "FPS    : "+Str( Engine3DFrameRate(#PB_Engine3D_Current))) 
      
      DrawText(250, 15, "CameraX: "+RSet(StrF(CameraX(0),2),4,"0")) 
      DrawText(250, 30, "CameraY: "+RSet(StrF(CameraY(0),2),4,"0")) 
      DrawText(250, 45, "CameraZ: "+RSet(StrF(CameraZ(0),2),4,"0")) 
      
      StopDrawing() 
    EndIf 
  EndIf 
  
  FlipBuffers() 
  RenderWorld() 
  
Until KeyboardPushed(#PB_Key_Escape) Or Quit 
StopGameTimer() 
Else 
  MessageRequester("Error", "Cant init DirectX 3D Engine",0) 
EndIf 
;} 
End 

;{ Daten-Sektion 
DataSection 

Pyramide_Vertics: 
  Data.f 0,0,0 ; Vertex0 
  Data.f 1,2,1 ; Vertex1 
  Data.f 2,0,0 ; Vertex2 
  
  Data.f 2,0,0 ; Vertex3 
  Data.f 1,2,1 ; Vertex4 
  Data.f 2,0,2 ; Vertex5 
  
  Data.f 2,0,2 ; Vertex6 
  Data.f 1,2,1 ; Vertex7 
  Data.f 0,0,2 ; Vertex8 
  
  Data.f 0,0,2 ; Vertex9 
  Data.f 1,2,1 ; Vertex10 
  Data.f 0,0,0 ; Vertex11 

Pyramide_Faces: 
  Data.w 0, 1, 2 ; Face 1 
  Data.w 0, 2, 1 ; Face 2 
  
  Data.w 3, 4, 5 ; Face 3 
  Data.w 3, 5, 4 ; Face 4 
  
  Data.w 6, 7, 8 ; Face 5 
  Data.w 6, 8, 7 ; Face 6 
  
  Data.w 9, 10, 11 ; Face 7 
  Data.w 9, 11, 10 ; Face 8 

Pyramide_UV: 
  Data.f 0.0, 0.0 
  Data.f 0.0, 3.0 
  Data.f 3.0, 3.0 
  Data.f 3.0, 0.0 

EndDataSection 
;}