March 20, 2019, 03:55:09 AM

Author Topic: OpenB3D Questions  (Read 2763 times)

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
OpenB3D Questions
« on: January 04, 2019, 11:33:07 PM »
Hi there. I've stopped working with Blitzmax and OpenB3D a few months ago due to a great showstopper problem with OpenB3D. Now I started to work on it again and came across new topics. I modified one of my techdemos so that you can play around with it. Maybe Mark or someone else can help here.

Background: OpenB3D should be mostly syntax compatible to MiniB3D. So I wrote the same demo once in the latest MiniB3D version and once parallel in the newest OpenB3D release from Github. Actually these source codes should be almost the same in syntax, but I noticed different results in some parts in OpenB3D and had to code some workarounds. I'm still using BlitzmaxOS, BLIDE and a BMK.exe from October 2017 (because of BLIDE). MinGW is gcc.exe (tdm64-1) 5.1.0 here.

The demo is visually quite simple, but has - as always - a complex sourcecode. I tried to stay below 1000 lines - I've attached both sources and the compiled executables here to this post. The demo shows an endless star field, which consists of 6.250.000 single stars (yes, correctly read). The star texture is generated procedurally by the code so no external media is needed. You can move around with WASD, QE and RF - hold TAB for Turbo. I've added three Debug stages which you can enable by changing the DEBUGLEVEL variable at the top of the source, together with other variables there. Level 1 disables Instancing and calculates a limited starfield using the TQuad rotations only for ALL stars, which is very slow. Level 2 disables textures and shows the 125 clusters colored, visualizing the teleport effect. And Level 3 makes it possible to leave the Cube to see the whole structure.

To make the demo still run with 60FPS I use Instancing with CopyEntity. First, a single star cluster with 50,000 stars is calculated, which is then duplicated in a 5x5x5 matrix in a cube. The camera only moves around in the innermost cube and is teleported to the opposite side of the inner cluster when reaching the edge. Since all clusters are visually identical, this teleporting is nearly not noticeable and the impression of an infinite star field is created.

Now to the problems / questions regarding OpenB3D: ???

1) Line 99: I must add "SetBlend ALPHABLEND" here or the initialization in OpenB3D looks very strange - MiniB3D doesn't have this problem. Generally the blending seems to work differently than in MiniB3D. Comment this line and see yourself :-)

2) Line 111 / 257 / TQuad Type: why are the vertex coordinate changes in CopyEntity not copied to all children meshes live like in MiniB3D? I manipulate the quads only in the source mesh, but the copies are ignored? Is it a bug? Or still not implemented? This is IMHO a very important feature of 3D graphics.

3) Line 102-185: why does the initialization take much longer with OpenB3D than with MiniB3D? MiniB3D: 1250ms vs. OpenB3D: 3000ms

4) Line 739: why do I must calculate the Cameraviewport Y value from the bottom left? In MiniB3D I use "CameraViewport tempcam, 0, 0, size, size" (top left) and in OpenB3D I must use "GraphicsHeight() - size" for the Y-coordinate to get the same result. I know that OpenGL calculates this way, but it is confusing compared to Blitz3D/MiniB3D

5) Line 205-206: in OpenB3D the mouse pointer moves slightly after initialization, this can only be fixed by NOT subtracting -1 in GraphicsHeight() - in MiniB3D it works (and would also be mathematically correct) - is it a rounding bug?

6) Line 279-285: I must use my own Begin2D/End2D functions here instead of the BeginMax2D/EndMax2D, or all vertex colors vanish and the universe is grey (replace my Commands with the default ones and see yourself). But why is this? It could be connected to the first problem noticed here.

7) Line 846: in MiniB3D I could access a Texture's pixmap directly by using the "glBindTexture (GL_TEXTURE_2D, tex.gltex[0])" command. How do I access the Pixmap of a Texture in OpenB3D? Is it only possible with the "BufferToTex tex, PixmapPixelPtr(pixmap, 0, 0)" command I've used instead?

8. @Mark: has OpenB3D development stopped four months ago or did you just not have time for it anymore? Am I the only one still using it? :o

Oh, and even if you can't help - have fun with the demo ;D It was a hard piece of work to get BOTH versions running.

MiniB3D Version:
Code: BlitzMax
  1. SuperStrict
  2.  
  3. Import sidesign.minib3d
  4.  
  5. Graphics3D DesktopWidth() / 1.5, DesktopHeight() / 1.5, 32, 2
  6.  
  7. ClearTextureFilters()
  8.  
  9. Global STARS:Int = 50000        ' number of stars per cluster part
  10. Global DIMENSION:Int = 2000     ' cluster dimension
  11. Global DISTRIBUTION:Float = 0.99' star distribution (0...1 = random...clustered)
  12. Global SPEED:Float = 1.0        ' overall move speed multiplicator
  13. Global BRAKE:Float = 0.95       ' brake multiplicator
  14. Global VSYNC:Int = False        ' Vertical Sync
  15. Global HOMING:Int = True        ' turn homing on/off
  16. Global COLORED:Int = False      ' colorize clusters
  17. Global TEXTURED:Int = True      ' use star texture
  18. Global Scale:Float = 0.5        ' star scale factor
  19. Global FADE:Int = True          ' fade distant clusters
  20. Global INSTANCING:Int = True    ' duplicate source mesh
  21.  
  22. Global DEBUGLEVEL:Int = 0       ' 0=off, 1=no instancing, 2=colored, 3=scene
  23.  
  24. If DEBUGLEVEL > 0 Then
  25.  
  26.         STARS = 1000
  27.         Scale = 1.6
  28.         DISTRIBUTION = 0.5
  29.         INSTANCING = False
  30.  
  31.         If DEBUGLEVEL > 1 Then
  32.  
  33.                 COLORED = True
  34.                 TEXTURED = False
  35.  
  36.                 If DEBUGLEVEL > 2 Then
  37.  
  38.                         HOMING = False
  39.                         FADE = False
  40.  
  41.                 EndIf
  42.  
  43.         EndIf
  44.  
  45. EndIf
  46.  
  47. ' ----------------------------------------------------------------------------
  48. ' Global variables
  49. ' ----------------------------------------------------------------------------
  50. Global localx:Float, localy:Float, localz:Float
  51. Global globalx:Float, globaly:Float, globalz:Float
  52. Global simx:Float, simy:Float, simz:Float
  53. Global xspeed:Float, yspeed:Float, zspeed:Float, rspeed:Float
  54. Global xadd:Float, yadd:Float, zadd:Float, radd:Float, tadd:Float
  55.  
  56. Global FPS:TFPS = New TFPS
  57. Global MS:Int = MilliSecs()
  58.  
  59. ' ----------------------------------------------------------------------------
  60. ' Init scene
  61. ' ----------------------------------------------------------------------------
  62. Global masterpivot:TPivot = CreatePivot()
  63.  
  64. Global cam:TCamera = CreateCamera()
  65. CameraRange cam, 1, DIMENSION * 8
  66. PositionEntity cam, 0, 0, 0
  67.  
  68. Local tex:TTexture = CreateSunTexture(512, 128, 128, 128)
  69. TextureBlend tex, 3
  70.  
  71. ' ----------------------------------------------------------------------------
  72. ' Duplicate Quad mesh in a 9x9x9 matrix
  73. ' ----------------------------------------------------------------------------
  74. Global meshlist:TList = CreateList()
  75. Global quadlist:TList = CreateList()
  76. Global quadsourcelist:TList = CreateList()
  77. Global lx:Float, ly:Float, lz:Float
  78.  
  79. Local entities:TEntity[9, 9, 9]
  80. Local meshes:TMesh[9, 9, 9]
  81.  
  82. Local mesh:TMesh
  83.  
  84. ' star cluster properties
  85. mesh = CreateMesh()
  86. EntityFX mesh, 1 + 2
  87. EntityBlend mesh, 3
  88. If TEXTURED Then EntityTexture mesh, tex
  89. HideEntity mesh
  90.  
  91. ' create blueprint star cluster
  92. For Local i:Int = 1 To STARS
  93.        
  94.         CreateStar(mesh)
  95.        
  96. Next
  97.  
  98. ' fix for OpenB3D to enable Texture Blending and Alpha?
  99. SetBlend ALPHABLEND
  100.  
  101. ' create 5x5x5 = 125 cluster
  102. For Local x:Int = 0 To 4 Step 1
  103.        
  104.         For Local y:Int = 0 To 4 Step 1
  105.  
  106.                 For Local z:Int = 0 To 4 Step 1
  107.  
  108.                         ' create a mesh and duplicate its properties = FAST
  109.                         If INSTANCING Then
  110.  
  111.                                 entities[x, y, z] = CopyEntity(mesh)
  112.  
  113.                                 PositionEntity entities[x, y, z], (x - 2) * DIMENSION, (y - 2) * DIMENSION, (z - 2) * DIMENSION
  114.  
  115.                                 If COLORED Then
  116.  
  117.                                         EntityColor entities[x, y, z], Rand(64, 255), Rand(64, 255), Rand(64, 255)
  118.  
  119.                                 Else
  120.  
  121.                                         EntityColor entities[x, y, z], 255, 255, 255
  122.  
  123.                                 EndIf
  124.  
  125.                                 ListAddLast(meshlist, entities[x, y, z])
  126.  
  127.                         ' create many unique meshes without instancing = SLOW
  128.                         Else
  129.  
  130.                                 ' new mesh
  131.                                 meshes[x, y, z] = CreateMesh()
  132.                                 EntityFX meshes[x, y, z], 1
  133.                                 EntityBlend meshes[x, y, z], 3
  134.                                 If TEXTURED Then
  135.                                
  136.                                         EntityTexture meshes[x, y, z], tex
  137.                                         EntityFX meshes[x, y, z], 1 + 2
  138.                                        
  139.                                 EndIf
  140.        
  141.                                 ' duplicate blueprint cluster
  142.                                 For Local s:TQuad = EachIn quadsourcelist
  143.  
  144.                                         Local q:TQuad = New TQuad
  145.  
  146.                                         q.mesh = meshes[x, y, z]
  147.                                         q.x = s.x
  148.                                         q.y = s.y
  149.                                         q.z = s.z
  150.                                         q.scalex = s.scalex
  151.                                         q.scaley = s.scaley
  152.                                         q.RGB = s.RGB
  153.                                        
  154.                                         q.Add()
  155.                                         q.Update(cam)
  156.  
  157.                                         ListAddLast(quadlist, q)
  158.                                        
  159.                                 Next
  160.                                
  161.                                 PositionEntity meshes[x, y, z], (x - 2) * DIMENSION, (y - 2) * DIMENSION, (z - 2) * DIMENSION
  162.  
  163.                                 If COLORED Then
  164.  
  165.                                         EntityColor meshes[x, y, z], Rand(128, 255), Rand(128, 255), Rand(128, 255)
  166.  
  167.                                 Else
  168.  
  169.                                         EntityColor meshes[x, y, z], 255, 255, 255
  170.  
  171.                                 EndIf
  172.  
  173.                                 ListAddLast(meshlist, meshes[x, y, z])
  174.  
  175.                         EndIf
  176.  
  177.                         RenderWorld
  178.                        
  179.                         Flip False
  180.  
  181.                 Next
  182.  
  183.         Next
  184.  
  185. Next
  186.  
  187. ' Fix to really center the mouse (otherwise it "jumps" a little bit initially)
  188. MoveMouse(GraphicsWidth() / 2, GraphicsHeight() / 2) ; Flip
  189. MouseX()
  190. MouseY()
  191. MouseXSpeed()
  192. MouseYSpeed()
  193. Flip
  194.  
  195. MS = MilliSecs() - MS
  196.  
  197. ' ----------------------------------------------------------------------------
  198. ' Main Loop
  199. ' ----------------------------------------------------------------------------
  200. While Not AppTerminate()
  201.  
  202.         If KeyHit(KEY_ESCAPE) Then End
  203.  
  204.         ' axis rotation
  205.         Local pitch:Float = Normalize(MouseY(), 0, GraphicsHeight() - 1, -2, 2)
  206.         Local yaw:Float = Normalize(MouseX(), 0, GraphicsWidth() - 1, 2, -2)
  207.         Local roll:Int = KeyDown(KEY_Q) - KeyDown(KEY_E)
  208.  
  209.         ' XYZ movement
  210.         Local xmove:Int = KeyDown(KEY_D) - KeyDown(KEY_A)
  211.         Local ymove:Int = KeyDown(KEY_R) - KeyDown(KEY_F)
  212.         Local zmove:Int = KeyDown(KEY_W) - KeyDown(KEY_S)
  213.         Local turbo:Int = KeyDown(KEY_TAB)
  214.  
  215.         If xmove = 0 And xadd <> 0 Then xadd = 0 Else If xmove And xadd = 0 Then xadd = 0.001
  216.         If ymove = 0 And yadd <> 0 Then yadd = 0 Else If ymove And yadd = 0 Then yadd = 0.001
  217.         If zmove = 0 And zadd <> 0 Then zadd = 0 Else If zmove And zadd = 0 Then zadd = 0.001
  218.         If roll = 0 And radd <> 0 Then radd = 0 Else If roll And radd = 0 Then radd = 0.01
  219.         If turbo = 0 And tadd <> 0 Then tadd:*0.9 Else If turbo And tadd = 0 Then tadd = 0.1
  220.  
  221.         If tadd < 0.01 Then tadd = 0.0
  222.  
  223.         If Abs(xmove) Then xadd:+0.01
  224.         If Abs(ymove) Then yadd:+0.01
  225.         If Abs(zmove) Then zadd:+0.01
  226.         If Abs(roll) Then radd:+0.025
  227.         If Abs(turbo) Then tadd:+0.05
  228.  
  229.         xadd:*1.025
  230.         yadd:*1.025
  231.         zadd:*1.025
  232.         radd:*1.025
  233.         tadd:*1.025
  234.  
  235.         If xadd > 2.0 Then xadd = 2.0
  236.         If yadd > 2.0 Then yadd = 2.0
  237.         If zadd > 2.0 Then zadd = 2.0
  238.         If radd > 1.5 Then radd = 1.5
  239.         If tadd > 25.0 Then tadd = 25.0
  240.  
  241.         ' calculate movespeed/rollspeed
  242.         If Abs(xmove) Then xspeed = xadd * SPEED * Sgn(xmove) * (1.0 + tadd)
  243.         If Abs(ymove) Then yspeed = yadd * SPEED * Sgn(ymove) * (1.0 + tadd)
  244.         If Abs(zmove) Then zspeed = zadd * SPEED * Sgn(zmove) * (1.0 + tadd)
  245.         If Abs(roll) Then rspeed = radd * Sgn(roll)
  246.        
  247.         ' perform rotation and motion
  248.         Turn(cam, pitch, yaw, rspeed)
  249.         MoveEntity cam, xspeed, yspeed, zspeed
  250.  
  251.         ' keep camera at home
  252.         If HOMING Then Home(cam, masterpivot, DIMENSION)
  253.  
  254.         ' only the master instance quads are facing to the camera
  255.         For Local q:TQuad = EachIn quadlist
  256.  
  257.                 q.Update(cam)
  258.  
  259.         Next
  260.  
  261.         ' fade mesh according to its distance
  262.         If FADE Then
  263.  
  264.                 For Local e:TEntity = EachIn meshlist
  265.  
  266.                         Local d:Float = EntityDistance(cam, e)
  267.                         Local a:Float = Normalize(d, DIMENSION * 1.0, DIMENSION * 2.0, 1.0, 0.0)
  268.                         EntityAlpha e, a
  269.  
  270.                 Next
  271.  
  272.         EndIf
  273.  
  274.         RenderWorld
  275.  
  276.         FPS.Update()
  277.  
  278.         ' fix for OpenB3D to have vertex colors enabled (otherwise its greyscale)
  279.         Begin2D()
  280.  
  281.                 DrawText("FPS [Init]..: " + FPS.FPS + " [" + MS + "ms]", 0, 0)
  282.                 DrawText("Star Cluster: " + STARS, 0, 15)
  283.                 DrawText("Stars Total.: " + (STARS * 5 * 5 * 5), 0, 30)
  284.  
  285.         End2D()
  286.  
  287.         Flip VSYNC
  288.  
  289.         ' decrease speed
  290.         xspeed:*BRAKE
  291.         yspeed:*BRAKE
  292.         zspeed:*BRAKE
  293.         rspeed:*BRAKE
  294.  
  295. Wend
  296.  
  297. End
  298.  
  299. ' creates a single star quad
  300. Function CreateStar(mesh:TMesh, surf:TSurface = Null, xoff:Float = 0.0:Float, yoff:Float = 0.0, zoff:Float = 0.0)
  301.  
  302.         Local q:TQuad = New TQuad
  303.  
  304.         q.mesh = mesh
  305.         q.surf = surf
  306.  
  307.         q.x = Rnd(-DIMENSION / 2, DIMENSION / 2) + xoff
  308.         q.y = Rnd(-DIMENSION / 2, DIMENSION / 2) + yoff
  309.         q.z = Rnd(-DIMENSION / 2, DIMENSION / 2) + zoff
  310.        
  311.         ' randomized clustering
  312.         If Rnd(1) > 1 - DISTRIBUTION Then
  313.  
  314.                 Local d:Float = Rnd(0.0001, 0.05)
  315.  
  316.                 q.x = lx + Rnd(-DIMENSION * d, DIMENSION * d) + xoff
  317.                 q.y = ly + Rnd(-DIMENSION * d, DIMENSION * d) + yoff
  318.                 q.z = lz + Rnd(-DIMENSION * d, DIMENSION * d) + zoff
  319.  
  320.         EndIf
  321.  
  322.         q.scalex = Rnd(1, Rnd(2, Rnd(4, Rnd(8, Rnd(16, 32))))) * Scale
  323.         q.scaley = q.scalex
  324.  
  325.         Local c:Float = (1.0 / q.scalex)
  326.         If Rnd(1) > 0.9 And c < 0.70 Then c = 1 - c             ' 10% Giants
  327.         If c >= 0.0 And c < 0.35 Then q.RGB = [255, 64, 0]      ' 35% Class M
  328.         If c >= 0.35 And c < 0.50 Then q.RGB = [255, 128, 32]   ' 15% Class K
  329.         If c >= 0.50 And c < 0.60 Then q.RGB = [255, 255, 64]   ' 10% Class G
  330.         If c >= 0.60 And c < 0.70 Then q.RGB = [255, 255, 128]  ' 10% Class F
  331.         If c >= 0.70 And c < 0.80 Then q.RGB = [255, 255, 255]  ' 10% Class A
  332.         If c >= 0.80 And c < 0.90 Then q.RGB = [0, 64, 255]     ' 10% Class B
  333.         If c >= 0.90 And c <= 1.00 Then q.RGB = [0, 0, 255]     ' 10% Class O
  334.  
  335.         q.Add()
  336.         q.Update(cam)
  337.  
  338.         ListAddLast(quadlist, q)
  339.         ListAddLast(quadsourcelist, q)
  340.        
  341.         lx = q.x
  342.         ly = q.y
  343.         lz = q.z
  344.  
  345. End Function
  346.  
  347. ' keeps the player in a predefined cubic area
  348. Function Home(target:TEntity, world:TEntity, homesize:Int = 100)
  349.  
  350.         ' store Local player Position
  351.         Local localx:Double = EntityX(target)
  352.         Local localy:Double = EntityY(target)
  353.         Local localz:Double = EntityZ(target)
  354.  
  355.         ' Check X axis
  356.         While localx > homesize
  357.  
  358.                 globalx:+homesize
  359.                 localx:-homesize
  360.                 PositionEntity target, localx, localy, localz
  361.                 MoveEntity world, -homesize, 0, 0
  362.                
  363.         Wend
  364.  
  365.         While localx < - homesize
  366.  
  367.                 globalx:-homesize
  368.                 localx:+homesize
  369.                 PositionEntity target, localx, localy, localz
  370.                 MoveEntity world, homesize, 0, 0
  371.  
  372.         Wend
  373.  
  374.         ' Check Y axis
  375.         While localy > homesize
  376.  
  377.                 globaly:+homesize
  378.                 localy:-homesize
  379.                 PositionEntity target, localx, localy, localz
  380.                 MoveEntity world, 0, -homesize, 0
  381.  
  382.         Wend
  383.  
  384.         While localy < - homesize
  385.  
  386.                 globaly:-homesize
  387.                 localy:+homesize
  388.                 PositionEntity target, localx, localy, localz
  389.                 MoveEntity world, 0, homesize, 0
  390.  
  391.         Wend
  392.  
  393.         ' Check Z axis
  394.         While localz > homesize
  395.  
  396.                 globalz:+homesize
  397.                 localz:-homesize
  398.                 PositionEntity target, localx, localy, localz
  399.                 MoveEntity world, 0, 0, -homesize
  400.  
  401.         Wend
  402.  
  403.         While localz < - homesize
  404.  
  405.                 globalz:-homesize
  406.                 localz:+homesize
  407.                 PositionEntity target, localx, localy, localz
  408.                 MoveEntity world, 0, 0, homesize
  409.  
  410.         Wend
  411.  
  412.         ' store simulated player Position
  413.         simx = localx + globalx
  414.         simy = localy + globaly
  415.         simz = localz + globalz
  416.  
  417. End Function
  418.  
  419. ' ----------------------------------------------------------------------------
  420. ' Normalizes a value to given range
  421. ' ----------------------------------------------------------------------------
  422. Function Normalize:Float(value:Float, vmin:Float, vmax:Float, nmin:Float, nmax:Float)
  423.  
  424.         Return((value - vmin) / (vmax - vmin)) * (nmax - nmin) + nmin
  425.  
  426. End Function
  427.  
  428. ' ----------------------------------------------------------------------------
  429. ' Turn Entity using Quaternions
  430. ' ----------------------------------------------------------------------------
  431. Function Turn(Ent:TEntity, X:Float = 0.0, Y:Float = 0.0, Z:Float = 0.0, Glob:Int = False)
  432.  
  433.         Local Pitch:Float = 0.0
  434.         Local Yaw:Float = 0.0
  435.         Local Roll:Float = 0.0
  436.  
  437.         Local Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  438.         Local Turn_Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  439.  
  440.         If Glob = False
  441.  
  442.                 Quat = EulerToQuat(EntityPitch(ent, True), EntityYaw(ent, True), EntityRoll(ent, True))
  443.                 Turn_Quat = EulerToQuat(X, Y, Z)
  444.                 Quat = MultiplyQuats(Quat, Turn_Quat)
  445.                 Quat = NormalizeQuat(Quat)
  446.                 QuatToEuler2(Quat.X, Quat.Y, Quat.Z, Quat.w, Pitch, Yaw, Roll)
  447.                 RotateEntity Ent, Pitch, Yaw, Roll
  448.  
  449.         Else
  450.  
  451.                 RotateEntity Ent, EntityPitch(Ent) + X, EntityYaw(Ent) + Y, EntityRoll(Ent) + Z
  452.  
  453.         EndIf
  454.  
  455. End Function
  456.  
  457. ' ----------------------------------------------------------------------------
  458. ' Euler to Quaternion
  459. ' ----------------------------------------------------------------------------
  460. Function EulerToQuat:TQuaternion(pitch:Float, yaw:Float, roll:Float)
  461.  
  462.         Local cr:Float = Cos(-roll / 2.0)
  463.         Local cp:Float = Cos(pitch / 2.0)
  464.         Local cy:Float = Cos(yaw / 2.0)
  465.         Local sr:Float = Sin(-roll / 2.0)
  466.         Local sp:Float = Sin(pitch / 2.0)
  467.         Local sy:Float = Sin(yaw / 2.0)
  468.         Local cpcy:Float = cp * cy
  469.         Local spsy:Float = sp * sy
  470.         Local spcy:Float = sp * cy
  471.         Local cpsy:Float = cp * sy
  472.  
  473.         Local q:TQuaternion = New TQuaternion
  474.  
  475.         q.w = cr * cpcy + sr * spsy
  476.         q.x = sr * cpcy - cr * spsy
  477.         q.y = cr * spcy + sr * cpsy
  478.         q.z = cr * cpsy - sr * spcy
  479.  
  480.         Return q
  481.  
  482. End Function
  483.  
  484. ' ----------------------------------------------------------------------------
  485. ' Quaternion to Euler
  486. ' ----------------------------------------------------------------------------
  487. Function QuatToEuler2(x:Float, y:Float, z:Float, w:Float, pitch:Float Var, yaw:Float Var, roll:Float Var)
  488.  
  489.         Local QuatToEulerAccuracy:Double = 1.0 / 2 ^ 31
  490.  
  491.         Local sint:Float = (2.0 * w * y) - (2.0 * x * z)
  492.         Local cost_temp:Float = 1.0 - (sint * sint)
  493.         Local cost:Float
  494.  
  495.         If Abs(cost_temp) > QuatToEulerAccuracy
  496.  
  497.                 cost = Sqr(cost_temp)
  498.  
  499.         Else
  500.  
  501.                 cost = 0.0
  502.  
  503.         EndIf
  504.  
  505.         Local sinv:Float, cosv:Float, sinf:Float, cosf:Float
  506.  
  507.         If Abs(cost) > QuatToEulerAccuracy
  508.  
  509.                 sinv = ((2.0 * y * z) + (2.0 * w * x)) / cost
  510.                 cosv = (1.0 - (2.0 * x * x) - (2.0 * y * y)) / cost
  511.                 sinf = ((2.0 * x * y) + (2.0 * w * z)) / cost
  512.                 cosf = (1.0 - (2.0 * y * y) - (2.0 * z * z)) / cost
  513.  
  514.         Else
  515.  
  516.                 sinv = (2.0 * w * x) - (2.0 * y * z)
  517.                 cosv = 1.0 - (2.0 * x * x) - (2.0 * z * z)
  518.                 sinf = 0.0
  519.                 cosf = 1.0
  520.  
  521.         EndIf
  522.  
  523.         pitch = ATan2(sint, cost)
  524.         yaw = ATan2(sinf, cosf)
  525.         roll = -ATan2(sinv, cosv)
  526.  
  527. End Function
  528.  
  529. ' ----------------------------------------------------------------------------
  530. ' Multiply Quaternion
  531. ' ----------------------------------------------------------------------------
  532. Function MultiplyQuats:TQuaternion(q1:TQuaternion, q2:TQuaternion)
  533.  
  534.         Local q:TQuaternion = New TQuaternion
  535.        
  536.         q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
  537.         q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
  538.         q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
  539.         q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
  540.  
  541.         Return q
  542.  
  543. End Function
  544.  
  545. ' ----------------------------------------------------------------------------
  546. ' Normalize Quaternion
  547. ' ----------------------------------------------------------------------------
  548. Function NormalizeQuat:TQuaternion(q:TQuaternion)
  549.  
  550.         Local uv:Float = Sqr(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z)
  551.  
  552.         q.w = q.w / uv
  553.         q.x = q.x / uv
  554.         q.y = q.y / uv
  555.         q.z = q.z / uv
  556.  
  557.         Return q
  558.  
  559. End Function
  560.  
  561. ' ------------------------------------------------------------------------------------------------
  562. ' Quad Type
  563. ' ------------------------------------------------------------------------------------------------
  564. Type TQuad
  565.  
  566.         Field x:Float = 0.0                                                                             ' position x
  567.         Field y:Float = 0.0                                                                             ' position y
  568.         Field z:Float = 0.0                                                                             ' position z
  569.  
  570.         Field row:Int = 0                                                                               ' texture row
  571.         Field col:Int = 0                                                                               ' texture column
  572.  
  573.         Field scalex:Float = 1.0                                                                ' current size X
  574.         Field scaley:Float = 1.0                                                                ' current size Y
  575.  
  576.         Field RGB:Int[] = [255, 255, 255]                                               ' Vertex Color
  577.         Field Alpha:Float = 1.0                                                                 ' Vertex Alpha
  578.  
  579.         Field v:Int = 0                                                                                 ' vertex counter
  580.         Field mesh:TMesh = Null                                                                 ' mesh pointer
  581.         Field surf:TSurface = Null                                                              ' surface pointer
  582.  
  583.         ' --------------------------------------------------------------------------------------------
  584.         ' METHOD: Add new Quad
  585.         ' --------------------------------------------------------------------------------------------
  586.         Method Add(col:Int = 0, row:Int = 0)
  587.  
  588.                 Local s:Int = CountSurfaces(mesh)
  589.                 If s = 0 Then
  590.                
  591.                         surf = CreateSurface(mesh)
  592.                        
  593.                 Else
  594.                
  595.                         surf = GetSurface(mesh, s)
  596.                        
  597.                 EndIf
  598.                
  599.                 Local i:Int = CountVertices(surf)
  600.                 If i + 4 > 32768 Then
  601.  
  602.                         surf = CreateSurface(mesh)
  603.                         v = 0
  604.  
  605.                 EndIf
  606.  
  607.                 ' add Vertices
  608.                 Local V0:Int = AddVertex(surf, 0, 0, 0, 1, 0)
  609.                 Local V1:Int = AddVertex(surf, 0, 0, 0, 1, 1)
  610.                 Local V2:Int = AddVertex(surf, 0, 0, 0, 0, 1)
  611.                 Local V3:Int = AddVertex(surf, 0, 0, 0, 0, 0)
  612.  
  613.                 ' color vertices
  614.                 VertexColor surf, V0, RGB[0], RGB[1], RGB[2], Alpha
  615.                 VertexColor surf, V1, RGB[0], RGB[1], RGB[2], Alpha
  616.                 VertexColor surf, V2, RGB[0], RGB[1], RGB[2], Alpha
  617.                 VertexColor surf, V3, RGB[0], RGB[1], RGB[2], Alpha
  618.  
  619.                 ' connect triangles
  620.                 AddTriangle surf, V0, V1, V2
  621.                 AddTriangle surf, V0, V2, V3
  622.  
  623.                 VertexTexCoords surf, V0, col + 1, row
  624.                 VertexTexCoords surf, V1, col + 1, row + 1
  625.                 VertexTexCoords surf, V2, col, row + 1
  626.                 VertexTexCoords surf, V3, col, row
  627.  
  628.                 ' increase vertex counter
  629.                 If v >= 4 Then v = V0 + 4 Else v = V0
  630.  
  631.         End Method
  632.  
  633.         ' --------------------------------------------------------------------------------------------
  634.         ' METHOD: Update a Quad
  635.         ' --------------------------------------------------------------------------------------------
  636.         Method Update(target:TEntity)
  637.  
  638.                 TFormVector scalex, 0, 0, target, Null
  639.                 Local X1:Float = TFormedX()
  640.                 Local Y1:Float = TFormedY()
  641.                 Local Z1:Float = TFormedZ()
  642.  
  643.                 TFormVector 0, scaley, 0, target, Null
  644.                 Local X2:Float = TFormedX()
  645.                 Local Y2:Float = TFormedY()
  646.                 Local Z2:Float = TFormedZ()
  647.                
  648.                 ' set vertices
  649.                 VertexCoords surf, v + 0, x - x1 - x2, y - y1 - y2, z - z1 - z2
  650.                 VertexCoords surf, v + 1, x - x1 + x2, y - y1 + y2, z - z1 + z2
  651.                 VertexCoords surf, v + 2, x + x1 + x2, y + y1 + y2, z + z1 + z2
  652.                 VertexCoords surf, v + 3, x + x1 - x2, y + y1 - y2, z + z1 - z2
  653.  
  654.         End Method
  655.  
  656. End Type
  657.  
  658. ' ------------------------------------------------------------------------------------------------
  659. ' Exact FPS counter
  660. ' ------------------------------------------------------------------------------------------------
  661.  
  662. Type TFPS
  663.  
  664.         Global renders:Int = 0
  665.  
  666.         Field FPS:Int = 60                                                                              ' current FPS value
  667.         Field interval:Int = 999
  668.         Field averagefps:Int = 60                                                               ' average FPS value
  669.         Field framedrops:Int = 0                                                                ' dropped frames
  670.         Field oldlooptime:Int = 0
  671.         Field looptime:Int = 0
  672.         Field multi:Float                                                                               ' main loop multiplicator
  673.  
  674.         Field old:Int = MilliSecs()
  675.         Field totalfps:Int = 30
  676.         Field Ticks:Int
  677.  
  678.         ' --------------------------------------------------------------------------------------------
  679.         ' METHOD: Update FPS counter
  680.         ' --------------------------------------------------------------------------------------------
  681.         Method Update()
  682.  
  683.                 renders:+1
  684.  
  685.                 looptime = MilliSecs() - oldlooptime
  686.                 oldlooptime = MilliSecs()
  687.  
  688.                 If MilliSecs() - old >= interval Then
  689.  
  690.                         old = MilliSecs()
  691.  
  692.                         FPS = renders * (1000 / interval)
  693.                         renders = 0
  694.                         totalfps:+FPS
  695.                         Ticks:+1
  696.                        
  697.                         averagefps = totalfps / Ticks
  698.  
  699.                 EndIf
  700.  
  701.         End Method
  702.  
  703. End Type
  704.  
  705. ' Create a stunning star texture
  706. Function CreateSunTexture:TTexture(size:Int = 512, r:Int = 255, g:Int = 255, b:Int = 255)
  707.  
  708.         Local i:Float, j:Int, col:Int, rgb:Int
  709.         Local x:Int, y:Int
  710.        
  711.         Local w:Int = GraphicsWidth()
  712.  
  713.         Local tempcam:TCamera, tempsun:TPivot
  714.         Local pixmap:TPixmap = CreatePixmap(size, size, PF_RGBA8888)
  715.         Local tex:TTexture = CreateTexture(size, size, 1 + 8)
  716.  
  717.         For j = 0 To (size / 2) - 1
  718.  
  719.                 col = 255 - Normalize(j, 0, (size / 2.0) - 1, 0, 255)
  720.                 If col > 255 Then col = 255
  721.                 rgb = col * $1000000 + col * $10000 + col * $100 + col
  722.  
  723.                 For i = 0 To 360 Step 0.1
  724.  
  725.                         WritePixel(pixmap, (size / 2) + (Sin(i) * j), (size / 2) + (Cos(i) * j), rgb)
  726.  
  727.                 Next
  728.  
  729.         Next
  730.        
  731.         PixmapToTexture(pixmap, tex)
  732.         'SavePixmapPNG(pixmap, "proceduralstar1.png", 0)
  733.  
  734.         ' temp camera
  735.         tempcam = CreateCamera()
  736.         CameraRange tempcam, 1, w * 2
  737.  
  738.         ' no fix needed compared to OpenB3D
  739.         CameraViewport tempcam, 0, 0, size, size
  740.  
  741.         ' temp pivot
  742.         tempsun = CreatePivot()
  743.  
  744.         ' Create 4 body quads
  745.         CreateQuad(tempsun, size * 1.0, tex, 3, 1 + 8 + 16, r * 1.00, g * 1.00, b * 1.00, 1.00)
  746.         CreateQuad(tempsun, size * 1.5, tex, 3, 1 + 8 + 16, r * 1.00, g * 1.00, b * 1.00, 1.00)
  747.         CreateQuad(tempsun, size * 2.0, tex, 3, 1 + 8 + 16, r * 0.75, g * 0.75, b * 0.50, 0.75)
  748.         CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, r * 0.50, g * 0.50, b * 0.50, 0.50)
  749.  
  750.         ' create 4 ray quads
  751.         Local ray1:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 1)
  752.         Local ray2:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 1)
  753.         Local ray3:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 0.5)
  754.         Local ray4:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 0.5)
  755.  
  756.         ' rescale and rotate rays
  757.         ScaleEntity ray1, size * 2, size / 32, size
  758.         ScaleEntity ray2, size / 32, size * 2, size
  759.         ScaleEntity ray3, size, size / 32, size
  760.         ScaleEntity ray4, size, size / 32, size
  761.         RotateEntity ray3, 0, 0, 45
  762.         RotateEntity ray4, 0, 0, 135
  763.        
  764.         PositionEntity tempsun, 0, 0, w
  765.  
  766.         ' render star
  767.         RenderWorld
  768.         RenderWorld
  769.  
  770.         ' grab image
  771.         pixmap = GrabPixmap(0, 0, size, size)
  772.         For x = 0 To size - 1
  773.  
  774.                 For y = 0 To size - 1
  775.  
  776.                         rgb = ReadPixel(pixmap, x, y)
  777.  
  778.                         r = (rgb & $ff0000) / $10000
  779.                         g = (rgb & $ff00) / $100
  780.                         b = (rgb & $ff)
  781.  
  782.                         ' rgb
  783.                         rgb = (r + g + b) / 3 * $1000000 + r * $10000 + g * $100 + b
  784.  
  785.                         WritePixel(pixmap, x, y, rgb)
  786.  
  787.                 Next
  788.  
  789.         Next
  790.        
  791.         PixmapToTexture(pixmap, tex)
  792.         'SavePixmapPNG(pixmap, "proceduralstar2.png", 0)
  793.  
  794.         ' Delete pixmap, pivot and temp cam
  795.         pixmap = Null
  796.         FreeEntity tempsun
  797.         FreeEntity tempcam
  798.  
  799.         Return tex
  800.  
  801. End Function
  802.  
  803. ' custom quad creation
  804. Function CreateQuad:Tmesh(parent:TEntity, scale:Float = 1.0, tex:TTexture = Null, blend:Int = False, fx:Int = False, r:Int = 255, g:Int = 255, b:Int = 255, a:Float = 1.0)
  805.  
  806.         Local mesh:TMesh = CreateMesh()
  807.         Local surf:TSurface = CreateSurface(mesh)
  808.         Local v0:Int, v1:Int, v2:Int, v3:Int
  809.  
  810.         v0 = AddVertex(surf, 1, 1, 0, 0, 0)
  811.         v1 = AddVertex(surf, -1, 1, 0, 1, 0)
  812.         v2 = AddVertex(surf, -1, -1, 0, 1, 1)
  813.         v3 = AddVertex(surf, 1, -1, 0, 0, 1)
  814.  
  815.         AddTriangle surf, v0, v1, v2
  816.         AddTriangle surf, v0, v2, v3
  817.  
  818.         If parent Then EntityParent Mesh, parent
  819.         If fx Then EntityFX Mesh, fx
  820.         If tex Then EntityTexture Mesh, tex
  821.         If blend Then EntityBlend Mesh, blend
  822.  
  823.         EntityColor Mesh, r, g, b
  824.         EntityAlpha Mesh, a
  825.  
  826.         VertexColor surf, v0, r, g, b, a
  827.         VertexColor surf, v1, r, g, b, a
  828.         VertexColor surf, v2, r, g, b, a
  829.         VertexColor surf, v3, r, g, b, a
  830.  
  831.         ScaleEntity Mesh, Scale, Scale, Scale
  832.  
  833.         Return Mesh
  834.  
  835. End Function
  836.  
  837. ' creates a texture from a pixmap
  838. Function PixmapToTexture(pixmap:TPixmap, tex:TTexture)
  839.  
  840.         If PixmapFormat(pixmap) <> PF_RGBA8888 Then pixmap = ConvertPixmap(pixmap, PF_RGBA8888)
  841.  
  842.         ' OpenB3D only function to copy pixmap to texture
  843.         'BufferToTex tex, PixmapPixelPtr(pixmap, 0, 0)
  844.  
  845.         ' MiniB3D workaround to copy pixmap to texture
  846.         glBindTexture (GL_TEXTURE_2D, tex.gltex[0])
  847.         gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, pixmap.width, pixmap.Height, GL_RGBA, GL_UNSIGNED_BYTE, PixmapPixelPtr(pixmap, 0, 0))
  848.  
  849. End Function
  850.  
  851. ' --------------------------------------------------------------------------------
  852. ' Fixed BeginMax2D()
  853. ' --------------------------------------------------------------------------------
  854. Function Begin2D()
  855.  
  856.         Local x:Int, y:Int, w:Int, h:Int
  857.         GetViewport(x, y, w, h)
  858.  
  859.         'glPopClientAttrib()
  860.         'glPopAttrib()
  861.         glMatrixMode(GL_MODELVIEW)
  862.         glPopMatrix()
  863.         glMatrixMode(GL_PROJECTION)
  864.         glPopMatrix()
  865.         glMatrixMode(GL_TEXTURE)
  866.         glPopMatrix()
  867.         glMatrixMode(GL_COLOR)
  868.         glPopMatrix()
  869.        
  870.         glDisable(GL_LIGHTING)
  871.         glDisable(GL_DEPTH_TEST)
  872.         glDisable(GL_SCISSOR_TEST)
  873.         glDisable(GL_FOG)
  874.         glDisable(GL_CULL_FACE)
  875.  
  876.         glMatrixMode GL_TEXTURE
  877.         glLoadIdentity
  878.  
  879.         glMatrixMode GL_PROJECTION
  880.         glLoadIdentity
  881.         glOrtho 0, GraphicsWidth(), GraphicsHeight(), 0, -1, 1
  882.  
  883.         glMatrixMode GL_MODELVIEW
  884.         glLoadIdentity
  885.  
  886.         SetViewport x, y, w, h
  887.  
  888.         Local MaxTex:Int
  889.         glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))
  890.  
  891.         For Local Layer:Int = 0 Until MaxTex
  892.  
  893.                 glActiveTexture(GL_TEXTURE0+Layer)
  894.  
  895.                 glDisable(GL_TEXTURE_CUBE_MAP)
  896.                 glDisable(GL_TEXTURE_GEN_S)
  897.                 glDisable(GL_TEXTURE_GEN_T)
  898.                 glDisable(GL_TEXTURE_GEN_R)
  899.  
  900.                 glDisable(GL_TEXTURE_2D)
  901.  
  902.         Next
  903.  
  904.         glActiveTexture(GL_TEXTURE0)
  905.  
  906.         glViewport(0, 0, GraphicsWidth(), GraphicsHeight())
  907.         glScissor(0, 0, GraphicsWidth(), GraphicsHeight())
  908.  
  909.         glEnable GL_BLEND
  910.         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  911.         glEnable(GL_TEXTURE_2D)
  912.  
  913. End Function
  914.  
  915. ' --------------------------------------------------------------------------------
  916. ' Fixed EndMax2D()
  917. ' --------------------------------------------------------------------------------
  918. Function End2D()
  919.  
  920.         ' save the Max2D settings for later
  921.         'glPushAttrib(GL_ALL_ATTRIB_BITS)
  922.         'glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS)
  923.         glMatrixMode(GL_MODELVIEW)
  924.         glPushMatrix()
  925.         glMatrixMode(GL_PROJECTION)
  926.         glPushMatrix()
  927.         glMatrixMode(GL_TEXTURE)
  928.         glPushMatrix()
  929.         glMatrixMode(GL_COLOR)
  930.         glPushMatrix()
  931.                
  932.         glDisable(GL_TEXTURE_CUBE_MAP)
  933.         glDisable(GL_TEXTURE_GEN_S)
  934.         glDisable(GL_TEXTURE_GEN_T)
  935.         glDisable(GL_TEXTURE_GEN_R)
  936.  
  937.         glDisable(GL_TEXTURE_2D)
  938.         glDisable(GL_BLEND)
  939.  
  940.         TGlobal.EnableStates()
  941.         'glDisable(GL_TEXTURE_2D)
  942.  
  943.         ' ' only needed for OpenB3D
  944.         'TGlobal.alpha_enable[0] = 0    ' alpha blending was disabled by Max2d (GL_BLEND)
  945.         'TGlobal.blend_mode[0] = 1      ' force alpha blending
  946.         'TGlobal.fx1[0] = 0                     ' full bright/surface normals was enabled by EnableStates (GL_NORMAL_ARRAY)
  947.         'TGlobal.fx2[0] = 1                     ' vertex colors was enabled by EnableStates (GL_COLOR_ARRAY)
  948.  
  949.         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)
  950.         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)
  951.  
  952.         glClearDepth(1.0)
  953.         glDepthFunc(GL_LEQUAL)
  954.         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  955.  
  956.         glAlphaFunc(GL_GEQUAL, 0.5)
  957.  
  958.         ' ' only needed for OpenB3D
  959.         'For Local cam:TCamera=EachIn TCamera.cam_list
  960.                
  961.                  ' active camera - was if cam.hide[0]=0
  962.                  'If cam = TGlobal.camera_in_use
  963.                
  964.                         ' fog with Max2d fix
  965.                 '       cam.UpdateFog()
  966.                 '       Exit
  967.                        
  968.                 'EndIf
  969.                
  970.         'Next
  971.  
  972. End Function

OpenB3D Version:
Code: BlitzMax
  1. SuperStrict
  2.  
  3. Import openb3dmax.B3dglgraphics
  4.  
  5. Graphics3D DesktopWidth() / 1.5, DesktopHeight() / 1.5, 32, 2
  6.  
  7. ClearTextureFilters()
  8.  
  9. Global STARS:Int = 50000        ' number of stars per cluster part
  10. Global DIMENSION:Int = 2000     ' cluster dimension
  11. Global DISTRIBUTION:Float = 0.99' star distribution (0...1 = random...clustered)
  12. Global SPEED:Float = 1.0        ' overall move speed multiplicator
  13. Global BRAKE:Float = 0.95       ' brake multiplicator
  14. Global VSYNC:Int = False        ' Vertical Sync
  15. Global HOMING:Int = True        ' turn homing on/off
  16. Global COLORED:Int = False      ' colorize clusters
  17. Global TEXTURED:Int = True      ' use star texture
  18. Global Scale:Float = 0.5        ' star scale factor
  19. Global FADE:Int = True          ' fade distant clusters
  20. Global INSTANCING:Int = True    ' duplicate source mesh
  21.  
  22. Global DEBUGLEVEL:Int = 0       ' 0=off, 1=no instancing, 2=colored, 3=scene
  23.  
  24. If DEBUGLEVEL > 0 Then
  25.  
  26.         STARS = 1000
  27.         Scale = 1.6
  28.         DISTRIBUTION = 0.5
  29.         INSTANCING = False
  30.  
  31.         If DEBUGLEVEL > 1 Then
  32.  
  33.                 COLORED = True
  34.                 TEXTURED = False
  35.  
  36.                 If DEBUGLEVEL > 2 Then
  37.  
  38.                         HOMING = False
  39.                         FADE = False
  40.  
  41.                 EndIf
  42.  
  43.         EndIf
  44.  
  45. EndIf
  46.  
  47. ' ----------------------------------------------------------------------------
  48. ' Global variables
  49. ' ----------------------------------------------------------------------------
  50. Global localx:Float, localy:Float, localz:Float
  51. Global globalx:Float, globaly:Float, globalz:Float
  52. Global simx:Float, simy:Float, simz:Float
  53. Global xspeed:Float, yspeed:Float, zspeed:Float, rspeed:Float
  54. Global xadd:Float, yadd:Float, zadd:Float, radd:Float, tadd:Float
  55.  
  56. Global FPS:TFPS = New TFPS
  57. Global MS:Int = MilliSecs()
  58.  
  59. ' ----------------------------------------------------------------------------
  60. ' Init scene
  61. ' ----------------------------------------------------------------------------
  62. Global masterpivot:TPivot = CreatePivot()
  63.  
  64. Global cam:TCamera = CreateCamera()
  65. CameraRange cam, 1, DIMENSION * 8
  66. PositionEntity cam, 0, 0, 0
  67.  
  68. Local tex:TTexture = CreateSunTexture(512, 128, 128, 128)
  69. TextureBlend tex, 3
  70.  
  71. ' ----------------------------------------------------------------------------
  72. ' Duplicate Quad mesh in a 9x9x9 matrix
  73. ' ----------------------------------------------------------------------------
  74. Global meshlist:TList = CreateList()
  75. Global quadlist:TList = CreateList()
  76. Global quadsourcelist:TList = CreateList()
  77. Global lx:Float, ly:Float, lz:Float
  78.  
  79. Local entities:TEntity[9, 9, 9]
  80. Local meshes:TMesh[9, 9, 9]
  81.  
  82. Local mesh:TMesh
  83.  
  84. ' star cluster properties
  85. mesh = CreateMesh()
  86. EntityFX mesh, 1 + 2
  87. EntityBlend mesh, 3
  88. If TEXTURED Then EntityTexture mesh, tex
  89. HideEntity mesh
  90.  
  91. ' create blueprint star cluster
  92. For Local i:Int = 1 To STARS
  93.        
  94.         CreateStar(mesh)
  95.                
  96. Next
  97.  
  98. ' fix for OpenB3D to enable Texture Blending and Alpha?
  99. SetBlend ALPHABLEND
  100.  
  101. ' create 5x5x5 = 125 cluster
  102. For Local x:Int = 0 To 4 Step 1
  103.                
  104.         For Local y:Int = 0 To 4 Step 1
  105.  
  106.                 For Local z:Int = 0 To 4 Step 1
  107.  
  108.                         ' create a mesh and duplicate its properties = FAST
  109.                         If INSTANCING Then
  110.  
  111.                                 entities[x, y, z] = CopyEntity(mesh)
  112.  
  113.                                 PositionEntity entities[x, y, z], (x - 2) * DIMENSION, (y - 2) * DIMENSION, (z - 2) * DIMENSION
  114.  
  115.                                 If COLORED Then
  116.  
  117.                                         EntityColor entities[x, y, z], Rand(64, 255), Rand(64, 255), Rand(64, 255)
  118.  
  119.                                 Else
  120.  
  121.                                         EntityColor entities[x, y, z], 255, 255, 255
  122.  
  123.                                 EndIf
  124.  
  125.                                 ListAddLast(meshlist, entities[x, y, z])
  126.  
  127.                         ' create many unique meshes without instancing = SLOW
  128.                         Else
  129.  
  130.                                 ' new mesh
  131.                                 meshes[x, y, z] = CreateMesh()
  132.                                 EntityFX meshes[x, y, z], 1
  133.                                 EntityBlend meshes[x, y, z], 3
  134.                                 If TEXTURED Then
  135.                                
  136.                                         EntityTexture meshes[x, y, z], tex
  137.                                         EntityFX meshes[x, y, z], 1 + 2
  138.                                        
  139.                                 EndIf
  140.        
  141.                                 ' duplicate blueprint cluster
  142.                                 For Local s:TQuad = EachIn quadsourcelist
  143.  
  144.                                         Local q:TQuad = New TQuad
  145.  
  146.                                         q.mesh = meshes[x, y, z]
  147.                                         q.x = s.x
  148.                                         q.y = s.y
  149.                                         q.z = s.z
  150.                                         q.scalex = s.scalex
  151.                                         q.scaley = s.scaley
  152.                                         q.RGB = s.RGB
  153.  
  154.                                         q.Add()
  155.                                         q.Update(cam)
  156.  
  157.                                         ListAddLast(quadlist, q)
  158.                                        
  159.                                 Next
  160.                                
  161.                                 PositionEntity meshes[x, y, z], (x - 2) * DIMENSION, (y - 2) * DIMENSION, (z - 2) * DIMENSION
  162.  
  163.                                 If COLORED Then
  164.  
  165.                                         EntityColor meshes[x, y, z], Rand(128, 255), Rand(128, 255), Rand(128, 255)
  166.  
  167.                                 Else
  168.  
  169.                                         EntityColor meshes[x, y, z], 255, 255, 255
  170.  
  171.                                 EndIf
  172.  
  173.                                 ListAddLast(meshlist, meshes[x, y, z])
  174.  
  175.                         EndIf
  176.  
  177.                         RenderWorld
  178.  
  179.                         Flip False
  180.  
  181.                 Next
  182.  
  183.         Next
  184.  
  185. Next
  186.  
  187. ' Fix to really center the mouse (otherwise it "jumps" a little bit initially)
  188. MoveMouse(GraphicsWidth() / 2, GraphicsHeight() / 2) ; Flip
  189. MouseX()
  190. MouseY()
  191. MouseXSpeed()
  192. MouseYSpeed()
  193. Flip
  194.  
  195. MS = MilliSecs() - MS
  196.  
  197. ' ----------------------------------------------------------------------------
  198. ' Main Loop
  199. ' ----------------------------------------------------------------------------
  200. While Not AppTerminate()
  201.  
  202.         If KeyHit(KEY_ESCAPE) Then End
  203.  
  204.         ' axis rotation
  205.         Local pitch:Float = Normalize(MouseY(), 0, GraphicsHeight() - 1, -2, 2)
  206.         Local yaw:Float = Normalize(MouseX(), 0, GraphicsWidth() - 1, 2, -2)
  207.         Local roll:Int = KeyDown(KEY_Q) - KeyDown(KEY_E)
  208.  
  209.         ' XYZ movement
  210.         Local xmove:Int = KeyDown(KEY_D) - KeyDown(KEY_A)
  211.         Local ymove:Int = KeyDown(KEY_R) - KeyDown(KEY_F)
  212.         Local zmove:Int = KeyDown(KEY_W) - KeyDown(KEY_S)
  213.         Local turbo:Int = KeyDown(KEY_TAB)
  214.  
  215.         If xmove = 0 And xadd <> 0 Then xadd = 0 Else If xmove And xadd = 0 Then xadd = 0.001
  216.         If ymove = 0 And yadd <> 0 Then yadd = 0 Else If ymove And yadd = 0 Then yadd = 0.001
  217.         If zmove = 0 And zadd <> 0 Then zadd = 0 Else If zmove And zadd = 0 Then zadd = 0.001
  218.         If roll = 0 And radd <> 0 Then radd = 0 Else If roll And radd = 0 Then radd = 0.01
  219.         If turbo = 0 And tadd <> 0 Then tadd:*0.9 Else If turbo And tadd = 0 Then tadd = 0.1
  220.  
  221.         If tadd < 0.01 Then tadd = 0.0
  222.  
  223.         If Abs(xmove) Then xadd:+0.01
  224.         If Abs(ymove) Then yadd:+0.01
  225.         If Abs(zmove) Then zadd:+0.01
  226.         If Abs(roll) Then radd:+0.025
  227.         If Abs(turbo) Then tadd:+0.05
  228.  
  229.         xadd:*1.025
  230.         yadd:*1.025
  231.         zadd:*1.025
  232.         radd:*1.025
  233.         tadd:*1.025
  234.  
  235.         If xadd > 2.0 Then xadd = 2.0
  236.         If yadd > 2.0 Then yadd = 2.0
  237.         If zadd > 2.0 Then zadd = 2.0
  238.         If radd > 1.5 Then radd = 1.5
  239.         If tadd > 25.0 Then tadd = 25.0
  240.  
  241.         ' calculate movespeed/rollspeed
  242.         If Abs(xmove) Then xspeed = xadd * SPEED * Sgn(xmove) * (1.0 + tadd)
  243.         If Abs(ymove) Then yspeed = yadd * SPEED * Sgn(ymove) * (1.0 + tadd)
  244.         If Abs(zmove) Then zspeed = zadd * SPEED * Sgn(zmove) * (1.0 + tadd)
  245.         If Abs(roll) Then rspeed = radd * Sgn(roll)
  246.  
  247.         ' perform rotation and motion
  248.         Turn(cam, pitch, yaw, rspeed)
  249.         MoveEntity cam, xspeed, yspeed, zspeed
  250.  
  251.         ' keep camera at home
  252.         If HOMING Then Home(cam, masterpivot, DIMENSION)
  253.  
  254.         ' only the master instance quads are facing to the camera
  255.         For Local q:TQuad = EachIn quadlist
  256.  
  257.                 q.Update(cam)
  258.  
  259.         Next
  260.  
  261.         ' fade mesh according to its distance
  262.         If FADE Then
  263.  
  264.                 For Local e:TEntity = EachIn meshlist
  265.  
  266.                         Local d:Float = EntityDistance(cam, e)
  267.                         Local a:Float = Normalize(d, DIMENSION * 1.0, DIMENSION * 2.0, 1.0, 0.0)
  268.                         EntityAlpha e, a
  269.  
  270.                 Next
  271.  
  272.         EndIf
  273.  
  274.         RenderWorld
  275.  
  276.         FPS.Update()
  277.  
  278.         ' fix for OpenB3D to have vertex colors enabled (otherwise its greyscale)
  279.         Begin2D()
  280.  
  281.                 DrawText("FPS [Init]..: " + FPS.FPS + " [" + MS + "ms]", 0, 0)
  282.                 DrawText("Star Cluster: " + STARS, 0, 15)
  283.                 DrawText("Stars Total.: " + (STARS * 5 * 5 * 5), 0, 30)
  284.  
  285.         End2D()
  286.        
  287.         Flip VSYNC
  288.  
  289.         ' decrease speed
  290.         xspeed:*BRAKE
  291.         yspeed:*BRAKE
  292.         zspeed:*BRAKE
  293.         rspeed:*BRAKE
  294.  
  295. Wend
  296.  
  297. End
  298.  
  299. ' creates a single star quad
  300. Function CreateStar(mesh:TMesh, surf:TSurface = Null, xoff:Float = 0.0:Float, yoff:Float = 0.0, zoff:Float = 0.0)
  301.  
  302.         Local q:TQuad = New TQuad
  303.  
  304.         q.mesh = mesh
  305.         q.surf = surf
  306.  
  307.         q.x = Rnd(-DIMENSION / 2, DIMENSION / 2) + xoff
  308.         q.y = Rnd(-DIMENSION / 2, DIMENSION / 2) + yoff
  309.         q.z = Rnd(-DIMENSION / 2, DIMENSION / 2) + zoff
  310.        
  311.         ' randomized clustering
  312.         If Rnd(1) > 1 - DISTRIBUTION Then
  313.  
  314.                 Local d:Float = Rnd(0.0001, 0.05)
  315.  
  316.                 q.x = lx + Rnd(-DIMENSION * d, DIMENSION * d) + xoff
  317.                 q.y = ly + Rnd(-DIMENSION * d, DIMENSION * d) + yoff
  318.                 q.z = lz + Rnd(-DIMENSION * d, DIMENSION * d) + zoff
  319.  
  320.         EndIf
  321.  
  322.         q.scalex = Rnd(1, Rnd(2, Rnd(4, Rnd(8, Rnd(16, 32))))) * Scale
  323.         q.scaley = q.scalex
  324.  
  325.         Local c:Float = (1.0 / q.scalex)
  326.         If Rnd(1) > 0.9 And c < 0.70 Then c = 1 - c             ' 10% Giants
  327.         If c >= 0.0 And c < 0.35 Then q.RGB = [255, 64, 0]      ' 35% Class M
  328.         If c >= 0.35 And c < 0.50 Then q.RGB = [255, 128, 32]   ' 15% Class K
  329.         If c >= 0.50 And c < 0.60 Then q.RGB = [255, 255, 64]   ' 10% Class G
  330.         If c >= 0.60 And c < 0.70 Then q.RGB = [255, 255, 128]  ' 10% Class F
  331.         If c >= 0.70 And c < 0.80 Then q.RGB = [255, 255, 255]  ' 10% Class A
  332.         If c >= 0.80 And c < 0.90 Then q.RGB = [0, 64, 255]     ' 10% Class B
  333.         If c >= 0.90 And c <= 1.00 Then q.RGB = [0, 0, 255]     ' 10% Class O
  334.  
  335.         q.Add()
  336.         q.Update(cam)
  337.  
  338.         ListAddLast(quadlist, q)
  339.         ListAddLast(quadsourcelist, q)
  340.        
  341.         lx = q.x
  342.         ly = q.y
  343.         lz = q.z
  344.  
  345. End Function
  346.  
  347. ' keeps the player in a predefined cubic area
  348. Function Home(target:TEntity, world:TEntity, homesize:Int = 100)
  349.  
  350.         ' store Local player Position
  351.         Local localx:Double = EntityX(target)
  352.         Local localy:Double = EntityY(target)
  353.         Local localz:Double = EntityZ(target)
  354.  
  355.         ' Check X axis
  356.         While localx > homesize
  357.  
  358.                 globalx:+homesize
  359.                 localx:-homesize
  360.                 PositionEntity target, localx, localy, localz
  361.                 MoveEntity world, -homesize, 0, 0
  362.                
  363.         Wend
  364.  
  365.         While localx < - homesize
  366.  
  367.                 globalx:-homesize
  368.                 localx:+homesize
  369.                 PositionEntity target, localx, localy, localz
  370.                 MoveEntity world, homesize, 0, 0
  371.  
  372.         Wend
  373.  
  374.         ' Check Y axis
  375.         While localy > homesize
  376.  
  377.                 globaly:+homesize
  378.                 localy:-homesize
  379.                 PositionEntity target, localx, localy, localz
  380.                 MoveEntity world, 0, -homesize, 0
  381.  
  382.         Wend
  383.  
  384.         While localy < - homesize
  385.  
  386.                 globaly:-homesize
  387.                 localy:+homesize
  388.                 PositionEntity target, localx, localy, localz
  389.                 MoveEntity world, 0, homesize, 0
  390.  
  391.         Wend
  392.  
  393.         ' Check Z axis
  394.         While localz > homesize
  395.  
  396.                 globalz:+homesize
  397.                 localz:-homesize
  398.                 PositionEntity target, localx, localy, localz
  399.                 MoveEntity world, 0, 0, -homesize
  400.  
  401.         Wend
  402.  
  403.         While localz < - homesize
  404.  
  405.                 globalz:-homesize
  406.                 localz:+homesize
  407.                 PositionEntity target, localx, localy, localz
  408.                 MoveEntity world, 0, 0, homesize
  409.  
  410.         Wend
  411.  
  412.         ' store simulated player Position
  413.         simx = localx + globalx
  414.         simy = localy + globaly
  415.         simz = localz + globalz
  416.  
  417. End Function
  418.  
  419. ' ----------------------------------------------------------------------------
  420. ' Normalizes a value to given range
  421. ' ----------------------------------------------------------------------------
  422. Function Normalize:Float(value:Float, vmin:Float, vmax:Float, nmin:Float, nmax:Float)
  423.  
  424.         Return((value - vmin) / (vmax - vmin)) * (nmax - nmin) + nmin
  425.  
  426. End Function
  427.  
  428. ' ----------------------------------------------------------------------------
  429. ' Turn Entity using Quaternions
  430. ' ----------------------------------------------------------------------------
  431. Function Turn(Ent:TEntity, X:Float = 0.0, Y:Float = 0.0, Z:Float = 0.0, Glob:Int = False)
  432.  
  433.         Local Pitch:Float = 0.0
  434.         Local Yaw:Float = 0.0
  435.         Local Roll:Float = 0.0
  436.  
  437.         Local Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  438.         Local Turn_Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  439.  
  440.         If Glob = False
  441.  
  442.                 Quat = EulerToQuat(EntityPitch(Ent, True), EntityYaw(Ent, True), EntityRoll(Ent, True))
  443.                 Turn_Quat = EulerToQuat(X, Y, Z)
  444.                 Quat = MultiplyQuats(Quat, Turn_Quat)
  445.                 Quat = NormalizeQuat(Quat)
  446.                 QuatToEuler2(Quat.x[0], Quat.y[0], Quat.z[0], Quat.w[0], pitch, yaw, roll)
  447.                 RotateEntity Ent, pitch, yaw, roll
  448.  
  449.         Else
  450.  
  451.                 RotateEntity Ent, EntityPitch(Ent) + X, EntityYaw(Ent) + Y, EntityRoll(Ent) + Z
  452.  
  453.         EndIf
  454.  
  455. End Function
  456.  
  457. ' ----------------------------------------------------------------------------
  458. ' Euler to Quaternion
  459. ' ----------------------------------------------------------------------------
  460. Function EulerToQuat:TQuaternion(pitch:Float, yaw:Float, roll:Float)
  461.  
  462.         Local cr:Float = Cos(-roll / 2.0)
  463.         Local cp:Float = Cos(pitch / 2.0)
  464.         Local cy:Float = Cos(yaw / 2.0)
  465.         Local sr:Float = Sin(-roll / 2.0)
  466.         Local sp:Float = Sin(pitch / 2.0)
  467.         Local sy:Float = Sin(yaw / 2.0)
  468.         Local cpcy:Float = cp * cy
  469.         Local spsy:Float = sp * sy
  470.         Local spcy:Float = sp * cy
  471.         Local cpsy:Float = cp * sy
  472.  
  473.         Local q:TQuaternion = NewQuaternion()
  474.        
  475.         q.w[0] = cr * cpcy + sr * spsy
  476.         q.x[0] = sr * cpcy - cr * spsy
  477.         q.y[0] = cr * spcy + sr * cpsy
  478.         q.z[0] = cr * cpsy - sr * spcy
  479.  
  480.         Return q
  481.  
  482. End Function
  483.  
  484. ' ----------------------------------------------------------------------------
  485. ' Quaternion to Euler
  486. ' ----------------------------------------------------------------------------
  487. Function QuatToEuler2(x:Float, y:Float, z:Float, w:Float, pitch:Float Var, yaw:Float Var, roll:Float Var)
  488.  
  489.         Local QuatToEulerAccuracy:Double = 1.0 / 2 ^ 31
  490.  
  491.         Local sint:Float = (2.0 * w * y) - (2.0 * x * z)
  492.         Local cost_temp:Float = 1.0 - (sint * sint)
  493.         Local cost:Float
  494.  
  495.         If Abs(cost_temp) > QuatToEulerAccuracy
  496.  
  497.                 cost = Sqr(cost_temp)
  498.  
  499.         Else
  500.  
  501.                 cost = 0.0
  502.  
  503.         EndIf
  504.  
  505.         Local sinv:Float, cosv:Float, sinf:Float, cosf:Float
  506.  
  507.         If Abs(cost) > QuatToEulerAccuracy
  508.  
  509.                 sinv = ((2.0 * y * z) + (2.0 * w * x)) / cost
  510.                 cosv = (1.0 - (2.0 * x * x) - (2.0 * y * y)) / cost
  511.                 sinf = ((2.0 * x * y) + (2.0 * w * z)) / cost
  512.                 cosf = (1.0 - (2.0 * y * y) - (2.0 * z * z)) / cost
  513.  
  514.         Else
  515.  
  516.                 sinv = (2.0 * w * x) - (2.0 * y * z)
  517.                 cosv = 1.0 - (2.0 * x * x) - (2.0 * z * z)
  518.                 sinf = 0.0
  519.                 cosf = 1.0
  520.  
  521.         EndIf
  522.  
  523.         pitch = ATan2(sint, cost)
  524.         yaw = ATan2(sinf, cosf)
  525.         roll = -ATan2(sinv, cosv)
  526.  
  527. End Function
  528.  
  529. ' ----------------------------------------------------------------------------
  530. ' Multiply Quaternion
  531. ' ----------------------------------------------------------------------------
  532. Function MultiplyQuats:TQuaternion(q1:TQuaternion, q2:TQuaternion)
  533.  
  534.         Local q:TQuaternion = NewQuaternion()
  535.  
  536.         q.w[0] = q1.w[0] * q2.w[0] - q1.x[0] * q2.x[0] - q1.y[0] * q2.y[0] - q1.z[0] * q2.z[0]
  537.         q.x[0] = q1.w[0] * q2.x[0] + q1.x[0] * q2.w[0] + q1.y[0] * q2.z[0] - q1.z[0] * q2.y[0]
  538.         q.y[0] = q1.w[0] * q2.y[0] + q1.y[0] * q2.w[0] + q1.z[0] * q2.x[0] - q1.x[0] * q2.z[0]
  539.         q.z[0] = q1.w[0] * q2.z[0] + q1.z[0] * q2.w[0] + q1.x[0] * q2.y[0] - q1.y[0] * q2.x[0]
  540.  
  541.         Return q
  542.  
  543. End Function
  544.  
  545. ' ----------------------------------------------------------------------------
  546. ' Normalize Quaternion
  547. ' ----------------------------------------------------------------------------
  548. Function NormalizeQuat:TQuaternion(q:TQuaternion)
  549.  
  550.         Local uv:Float = Sqr(q.w[0] * q.w[0] + q.x[0] * q.x[0] + q.y[0] * q.y[0] + q.z[0] * q.z[0])
  551.  
  552.         q.w[0] = q.w[0] / uv
  553.         q.x[0] = q.x[0] / uv
  554.         q.y[0] = q.y[0] / uv
  555.         q.z[0] = q.z[0] / uv
  556.  
  557.         Return q
  558.  
  559. End Function
  560.  
  561. ' ------------------------------------------------------------------------------------------------
  562. ' Quad Type
  563. ' ------------------------------------------------------------------------------------------------
  564. Type TQuad
  565.  
  566.         Field x:Float = 0.0                                                                             ' position x
  567.         Field y:Float = 0.0                                                                             ' position y
  568.         Field z:Float = 0.0                                                                             ' position z
  569.  
  570.         Field row:Int = 0                                                                               ' texture row
  571.         Field col:Int = 0                                                                               ' texture column
  572.  
  573.         Field scalex:Float = 1.0                                                                ' current size X
  574.         Field scaley:Float = 1.0                                                                ' current size Y
  575.  
  576.         Field RGB:Int[] = [255, 255, 255]                                               ' Vertex Color
  577.         Field Alpha:Float = 1.0                                                                 ' Vertex Alpha
  578.  
  579.         Field v:Int = 0                                                                                 ' vertex counter
  580.         Field mesh:TMesh = Null                                                                 ' mesh pointer
  581.         Field surf:TSurface = Null                                                              ' surface pointer
  582.  
  583.         ' --------------------------------------------------------------------------------------------
  584.         ' METHOD: Add new Quad
  585.         ' --------------------------------------------------------------------------------------------
  586.         Method Add(col:Int = 0, row:Int = 0)
  587.  
  588.                 Local s:Int = CountSurfaces(mesh)
  589.                 If s = 0 Then
  590.                
  591.                         surf = CreateSurface(mesh)
  592.                        
  593.                 Else
  594.                
  595.                         surf = GetSurface(mesh, s)
  596.                        
  597.                 EndIf
  598.                
  599.                 Local i:Int = CountVertices(surf)
  600.                 If i + 4 > 32768 Then
  601.  
  602.                         surf = CreateSurface(mesh)
  603.                         v = 0
  604.  
  605.                 EndIf
  606.  
  607.                 ' add Vertices
  608.                 Local V0:Int = AddVertex(surf, 0, 0, 0, 1, 0)
  609.                 Local V1:Int = AddVertex(surf, 0, 0, 0, 1, 1)
  610.                 Local V2:Int = AddVertex(surf, 0, 0, 0, 0, 1)
  611.                 Local V3:Int = AddVertex(surf, 0, 0, 0, 0, 0)
  612.  
  613.                 ' color vertices
  614.                 VertexColor surf, V0, RGB[0], RGB[1], RGB[2], Alpha
  615.                 VertexColor surf, V1, RGB[0], RGB[1], RGB[2], Alpha
  616.                 VertexColor surf, V2, RGB[0], RGB[1], RGB[2], Alpha
  617.                 VertexColor surf, V3, RGB[0], RGB[1], RGB[2], Alpha
  618.  
  619.                 ' connect triangles
  620.                 AddTriangle surf, V0, V1, V2
  621.                 AddTriangle surf, V0, V2, V3
  622.  
  623.                 VertexTexCoords surf, V0, col + 1, row
  624.                 VertexTexCoords surf, V1, col + 1, row + 1
  625.                 VertexTexCoords surf, V2, col, row + 1
  626.                 VertexTexCoords surf, V3, col, row
  627.  
  628.                 ' increase vertex counter
  629.                 If v >= 4 Then v = V0 + 4 Else v = V0
  630.  
  631.         End Method
  632.  
  633.         ' --------------------------------------------------------------------------------------------
  634.         ' METHOD: Update a Quad
  635.         ' --------------------------------------------------------------------------------------------
  636.         Method Update(target:TEntity)
  637.  
  638.                 TFormVector scalex, 0, 0, target, Null
  639.                 Local X1:Float = TFormedX()
  640.                 Local Y1:Float = TFormedY()
  641.                 Local Z1:Float = TFormedZ()
  642.                
  643.                 TFormVector 0, scaley, 0, target, Null
  644.                 Local X2:Float = TFormedX()
  645.                 Local Y2:Float = TFormedY()
  646.                 Local Z2:Float = TFormedZ()
  647.  
  648.                 ' set vertices
  649.                 VertexCoords surf, v + 0, x - x1 - x2, y - y1 - y2, z - z1 - z2
  650.                 VertexCoords surf, v + 1, x - x1 + x2, y - y1 + y2, z - z1 + z2
  651.                 VertexCoords surf, v + 2, x + x1 + x2, y + y1 + y2, z + z1 + z2
  652.                 VertexCoords surf, v + 3, x + x1 - x2, y + y1 - y2, z + z1 - z2
  653.  
  654.         End Method
  655.  
  656. End Type
  657.  
  658. ' ------------------------------------------------------------------------------------------------
  659. ' Exact FPS counter
  660. ' ------------------------------------------------------------------------------------------------
  661.  
  662. Type TFPS
  663.  
  664.         Global renders:Int = 0
  665.  
  666.         Field FPS:Int = 60                                                                              ' current FPS value
  667.         Field interval:Int = 999
  668.         Field averagefps:Int = 60                                                               ' average FPS value
  669.         Field framedrops:Int = 0                                                                ' dropped frames
  670.         Field oldlooptime:Int = 0
  671.         Field looptime:Int = 0
  672.         Field multi:Float                                                                               ' main loop multiplicator
  673.  
  674.         Field old:Int = MilliSecs()
  675.         Field totalfps:Int = 30
  676.         Field Ticks:Int
  677.  
  678.         ' --------------------------------------------------------------------------------------------
  679.         ' METHOD: Update FPS counter
  680.         ' --------------------------------------------------------------------------------------------
  681.         Method Update()
  682.  
  683.                 renders:+1
  684.  
  685.                 looptime = MilliSecs() - oldlooptime
  686.                 oldlooptime = MilliSecs()
  687.  
  688.                 If MilliSecs() - old >= interval Then
  689.  
  690.                         old = MilliSecs()
  691.  
  692.                         FPS = renders * (1000 / interval)
  693.                         renders = 0
  694.                         totalfps:+FPS
  695.                         Ticks:+1
  696.                        
  697.                         averagefps = totalfps / Ticks
  698.  
  699.                 EndIf
  700.  
  701.         End Method
  702.  
  703. End Type
  704.  
  705. ' Create a stunning star texture
  706. Function CreateSunTexture:TTexture(size:Int = 512, r:Int = 255, g:Int = 255, b:Int = 255)
  707.  
  708.         Local i:Float, j:Int, col:Int, rgb:Int
  709.         Local x:Int, y:Int
  710.        
  711.         Local w:Int = GraphicsWidth()
  712.  
  713.         Local tempcam:TCamera, tempsun:TPivot
  714.         Local pixmap:TPixmap = CreatePixmap(size, size, PF_RGBA8888)
  715.         Local tex:TTexture = CreateTexture(size, size, 1 + 8)
  716.  
  717.         For j = 0 To (size / 2) - 1
  718.  
  719.                 col = 255 - Normalize(j, 0, (size / 2.0) - 1, 0, 255)
  720.                 If col > 255 Then col = 255
  721.                 rgb = col * $1000000 + col * $10000 + col * $100 + col
  722.  
  723.                 For i = 0 To 360 Step 0.1
  724.  
  725.                         WritePixel(pixmap, (size / 2) + (Sin(i) * j), (size / 2) + (Cos(i) * j), rgb)
  726.  
  727.                 Next
  728.  
  729.         Next
  730.        
  731.         PixmapToTexture(pixmap, tex)
  732.         'SavePixmapPNG(pixmap, "proceduralstar1.png", 0)
  733.  
  734.         ' temp camera
  735.         tempcam = CreateCamera()
  736.         CameraRange tempcam, 1, w * 2
  737.        
  738.         ' fix for OpenB3D to simulate MiniB3D's Cameraviewport handling
  739.         CameraViewport tempcam, 0, GraphicsHeight() - size, size, size
  740.  
  741.         ' temp pivot
  742.         tempsun = CreatePivot()
  743.  
  744.         ' Create 4 body quads
  745.         CreateQuad(tempsun, size * 1.0, tex, 3, 1 + 8 + 16, r * 1.00, g * 1.00, b * 1.00, 1.00)
  746.         CreateQuad(tempsun, size * 1.5, tex, 3, 1 + 8 + 16, r * 1.00, g * 1.00, b * 1.00, 1.00)
  747.         CreateQuad(tempsun, size * 2.0, tex, 3, 1 + 8 + 16, r * 0.75, g * 0.75, b * 0.50, 0.75)
  748.         CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, r * 0.50, g * 0.50, b * 0.50, 0.50)
  749.  
  750.         ' create 4 ray quads
  751.         Local ray1:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 1)
  752.         Local ray2:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 1)
  753.         Local ray3:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 0.5)
  754.         Local ray4:TMesh = CreateQuad(tempsun, size * 4.0, tex, 3, 1 + 8 + 16, 255, 255, 255, 0.5)
  755.  
  756.         ' rescale and rotate rays
  757.         ScaleEntity ray1, size * 2, size / 32, size
  758.         ScaleEntity ray2, size / 32, size * 2, size
  759.         ScaleEntity ray3, size, size / 32, size
  760.         ScaleEntity ray4, size, size / 32, size
  761.         RotateEntity ray3, 0, 0, 45
  762.         RotateEntity ray4, 0, 0, 135
  763.        
  764.         PositionEntity tempsun, 0, 0, w
  765.  
  766.         ' render star
  767.         RenderWorld
  768.         RenderWorld
  769.  
  770.         ' grab image
  771.         pixmap = GrabPixmap(0, 0, size, size)
  772.         For x = 0 To size - 1
  773.  
  774.                 For y = 0 To size - 1
  775.  
  776.                         rgb = ReadPixel(pixmap, x, y)
  777.  
  778.                         r = (rgb & $ff0000) / $10000
  779.                         g = (rgb & $ff00) / $100
  780.                         b = (rgb & $ff)
  781.  
  782.                         ' rgb
  783.                         rgb = (r + g + b) / 3 * $1000000 + r * $10000 + g * $100 + b
  784.  
  785.                         WritePixel(pixmap, x, y, rgb)
  786.  
  787.                 Next
  788.  
  789.         Next
  790.  
  791.         PixmapToTexture(pixmap, tex)
  792.         'SavePixmapPNG(pixmap, "proceduralstar2.png", 0)
  793.  
  794.         ' Delete pixmap, pivot and temp cam
  795.         pixmap = Null
  796.         FreeEntity tempsun
  797.         FreeEntity tempcam
  798.  
  799.         Return tex
  800.  
  801. End Function
  802.  
  803. ' custom quad creation
  804. Function CreateQuad:Tmesh(parent:TEntity, scale:Float = 1.0, tex:TTexture = Null, blend:Int = False, fx:Int = False, r:Int = 255, g:Int = 255, b:Int = 255, a:Float = 1.0)
  805.  
  806.         Local mesh:TMesh = CreateMesh()
  807.         Local surf:TSurface = CreateSurface(mesh)
  808.         Local v0:Int, v1:Int, v2:Int, v3:Int
  809.  
  810.         v0 = AddVertex(surf, 1, 1, 0, 0, 0)
  811.         v1 = AddVertex(surf, -1, 1, 0, 1, 0)
  812.         v2 = AddVertex(surf, -1, -1, 0, 1, 1)
  813.         v3 = AddVertex(surf, 1, -1, 0, 0, 1)
  814.  
  815.         AddTriangle surf, v0, v1, v2
  816.         AddTriangle surf, v0, v2, v3
  817.  
  818.         If parent Then EntityParent Mesh, parent
  819.         If fx Then EntityFX Mesh, fx
  820.         If tex Then EntityTexture Mesh, tex
  821.         If blend Then EntityBlend Mesh, blend
  822.  
  823.         EntityColor Mesh, r, g, b
  824.         EntityAlpha Mesh, a
  825.  
  826.         VertexColor surf, v0, r, g, b, a
  827.         VertexColor surf, v1, r, g, b, a
  828.         VertexColor surf, v2, r, g, b, a
  829.         VertexColor surf, v3, r, g, b, a
  830.  
  831.         ScaleEntity Mesh, Scale, Scale, Scale
  832.  
  833.         Return Mesh
  834.  
  835. End Function
  836.  
  837. ' creates a texture from a pixmap
  838. Function PixmapToTexture(pixmap:TPixmap, tex:TTexture)
  839.  
  840.         If PixmapFormat(pixmap) <> PF_RGBA8888 Then pixmap = ConvertPixmap(pixmap, PF_RGBA8888)
  841.  
  842.         ' OpenB3D only function to copy pixmap to texture
  843.         BufferToTex tex, PixmapPixelPtr(pixmap, 0, 0)
  844.  
  845.         ' MiniB3D workaround to copy pixmap to texture
  846.         'glBindTexture (GL_TEXTURE_2D, tex.gltex[0])
  847.         'gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, PixmapPixelPtr(pixmap, 0, 0))
  848.  
  849. End Function
  850.  
  851. ' --------------------------------------------------------------------------------
  852. ' Fixed BeginMax2D()
  853. ' --------------------------------------------------------------------------------
  854. Function Begin2D()
  855.  
  856.         Local x:Int, y:Int, w:Int, h:Int
  857.         GetViewport(x, y, w, h)
  858.  
  859.         'glPopClientAttrib()
  860.         'glPopAttrib()
  861.         glMatrixMode(GL_MODELVIEW)
  862.         glPopMatrix()
  863.         glMatrixMode(GL_PROJECTION)
  864.         glPopMatrix()
  865.         glMatrixMode(GL_TEXTURE)
  866.         glPopMatrix()
  867.         glMatrixMode(GL_COLOR)
  868.         glPopMatrix()
  869.        
  870.         glDisable(GL_LIGHTING)
  871.         glDisable(GL_DEPTH_TEST)
  872.         glDisable(GL_SCISSOR_TEST)
  873.         glDisable(GL_FOG)
  874.         glDisable(GL_CULL_FACE)
  875.  
  876.         glMatrixMode GL_TEXTURE
  877.         glLoadIdentity
  878.  
  879.         glMatrixMode GL_PROJECTION
  880.         glLoadIdentity
  881.         glOrtho 0, GraphicsWidth(), GraphicsHeight(), 0, -1, 1
  882.  
  883.         glMatrixMode GL_MODELVIEW
  884.         glLoadIdentity
  885.  
  886.         SetViewport x, y, w, h
  887.  
  888.         Local MaxTex:Int
  889.         glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))
  890.  
  891.         For Local Layer:Int = 0 Until MaxTex
  892.  
  893.                 glActiveTexture(GL_TEXTURE0+Layer)
  894.  
  895.                 glDisable(GL_TEXTURE_CUBE_MAP)
  896.                 glDisable(GL_TEXTURE_GEN_S)
  897.                 glDisable(GL_TEXTURE_GEN_T)
  898.                 glDisable(GL_TEXTURE_GEN_R)
  899.  
  900.                 glDisable(GL_TEXTURE_2D)
  901.  
  902.         Next
  903.  
  904.         glActiveTexture(GL_TEXTURE0)
  905.  
  906.         glViewport(0, 0, GraphicsWidth(), GraphicsHeight())
  907.         glScissor(0, 0, GraphicsWidth(), GraphicsHeight())
  908.  
  909.         glEnable GL_BLEND
  910.         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  911.         glEnable(GL_TEXTURE_2D)
  912.  
  913. End Function
  914.  
  915. ' --------------------------------------------------------------------------------
  916. ' Fixed EndMax2D()
  917. ' --------------------------------------------------------------------------------
  918. Function End2D()
  919.  
  920.         ' save the Max2D settings for later
  921.         'glPushAttrib(GL_ALL_ATTRIB_BITS)
  922.         'glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS)
  923.         glMatrixMode(GL_MODELVIEW)
  924.         glPushMatrix()
  925.         glMatrixMode(GL_PROJECTION)
  926.         glPushMatrix()
  927.         glMatrixMode(GL_TEXTURE)
  928.         glPushMatrix()
  929.         glMatrixMode(GL_COLOR)
  930.         glPushMatrix()
  931.                
  932.         glDisable(GL_TEXTURE_CUBE_MAP)
  933.         glDisable(GL_TEXTURE_GEN_S)
  934.         glDisable(GL_TEXTURE_GEN_T)
  935.         glDisable(GL_TEXTURE_GEN_R)
  936.  
  937.         glDisable(GL_TEXTURE_2D)
  938.         glDisable(GL_BLEND)
  939.  
  940.         TGlobal.EnableStates()
  941.         'glDisable(GL_TEXTURE_2D)
  942.  
  943.         ' only needed for OpenB3D
  944.         TGlobal.alpha_enable[0] = 0     ' alpha blending was disabled by Max2d (GL_BLEND)
  945.         TGlobal.blend_mode[0] = 1       ' force alpha blending
  946.         TGlobal.fx1[0] = 0                      ' full bright/surface normals was enabled by EnableStates (GL_NORMAL_ARRAY)
  947.         TGlobal.fx2[0] = 1                      ' vertex colors was enabled by EnableStates (GL_COLOR_ARRAY)
  948.  
  949.         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)
  950.         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)
  951.  
  952.         glClearDepth(1.0)
  953.         glDepthFunc(GL_LEQUAL)
  954.         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  955.  
  956.         glAlphaFunc(GL_GEQUAL, 0.5)
  957.  
  958.         ' only needed for OpenB3D
  959.         For Local cam:TCamera=EachIn TCamera.cam_list
  960.                
  961.                  ' active camera - was if cam.hide[0]=0
  962.                  If cam = TGlobal.camera_in_use
  963.                
  964.                         ' fog with Max2d fix
  965.                         cam.UpdateFog()
  966.                         Exit
  967.                        
  968.                 EndIf
  969.                
  970.         Next
  971.  
  972. End Function
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline Flanker

  • Jr. Member
  • **
  • Posts: 33
    • Youtube channel on Blitzmax programming prototypes
Re: OpenB3D Questions
« Reply #1 on: January 05, 2019, 02:17:03 AM »
Nice demo here, instancing is very powerful. You're not the only one using OpenB3D, I've totally abandon Blitz3D for OpenB3D because I prefer Blitzmax coding and because GLSL (or shaders in general) are amazing.

1) The only problem if I comment "SetBlend ALPHABLEND" is that there is no alpha when building the mesh at startup but after that it works well. However I also noticed a problem with alpha textures on my side a few weeks ago when I tried to code a 3D snow fall effect with OpenB3D. I had to use EntityAlpha to be able to activate texture alpha, wich is strange.

2) I remember using instancing with CopyEntity() in Blitz3D to make an "ocean" from one single animated mesh, and as you mentioned, in Blitz3D when you modify the source mesh, all instancies are also affected (useful to animate a lot of vertices). Maybe it's just not implemented here.

5) Funny to see that you also have a fix before the main loop to prevent the camera from spinning at the start. I think there is also a problem with MouseXSpeed()/MouseYSpeed() and MoveMouse(), or at least it works differently than Blitz3D.
Everyone knew it was impossible, until someone who didn't know made it.

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
Re: OpenB3D Questions
« Reply #2 on: January 05, 2019, 11:21:54 AM »
The mouse fix is needed both in MiniB3D and OpenB3D, but I don't know why this happens. And the two Flips before and after the Mouse Commands are important or it won't work. I had blending problems with OpenB3D since I first saw it - I created a few workarounds but this should be fixed in general IMHO. And yes, GLSL shaders are amazing with OpenB3D but a big problem with GLSL is that I hate to code without the possibility to debug values onscreen - you need tricks or hints to see what's wrong. But this is not a problem of OpenB3D ;D

Another problem I had already pointed out to mark is a strange bug in my game with reloaded Textures on B3D Models. In my game, when a new level is loaded, a BSP file is parsed and created as a mesh, gets textured and then I load a B3D model like a chest or a torch template and use CopyEntity to spread it across the level. After entering another level, all loaded assets are deleted and recreated. This worked until May 18 2017.

Now with the latest versions, either the models are completely untextured, I see only the normalmap or the normalmap+diffusemap in a random manner, but only on the B3D models - the level geometry is still fine. I've checked the OpenB3D source changes since the May 18 2017 version which is the last one where it worked (and it was the last one I could compile with my old BMK until he fixed this in the more current versions). I've sent my whole game project to Mark a few months ago and hope he will find some time to find the error as I failed with it.

But beside all these annoyances Blitzmax+OpenB3D is still a great combo and my first choice. On the other hand I spend more time to create workarounds in OpenB3D than creating progress in the game engine and game logic, which is not good.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #3 on: January 06, 2019, 01:48:05 AM »
Hi Krischan,

I'll just reply to point 8 for now, yes I'll be continuing development on Openb3dmax in my spare time, in fact I have been working on it these last few days and have an update to the 1.25 source coming, but I've a few nasty bugs to fix first, shaders and b3d files are crashing!

Well I'll more fully explain why development stopped, about the start of September I got sciatica in my lower back lifting about 20kg, so yes about 4 months ago, this is a recurring injury and I just lifted something too heavy. So I was in too much pain to concentrate for coding, now I still have sciatica quite bad but I've found ibuprofen gel which makes the pain manageable so I can do a bit of coding now.

I sorry you've had so many problems with Openb3d, it's always been a WIP but it is starting to mature into something like Blitz3d. It has great potential as Angros has done an awesome job on the OpenGL, all it needs is a bit more work, well quite a bit really!

Also sorry I never got back to you on LOF, I ran the exe but it just crashed when I launched a level. I'll have another look at it soon.

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
Re: OpenB3D Questions
« Reply #4 on: January 07, 2019, 08:06:57 PM »
Mark, your health is more important than our projects - don't worry, take the time you need and get well soon! I'll continue developing the game with the old April 30 version which seemed stable enough for me. I know that OpenB3D is not finished but it already creates stunning results. I/we really appreciate your work and if you get LOF running you can see what can be done with it by a single enthusiast (but I don't think I can already tap the full potential yet and my shaders are a mess). For the LOF crash: I've re-uploaded my complete Blitzmax+LOF environment and sent you a PM with some instructions how to setup. I think it makes sense to have the same basis here to hunt the bugs.

Beside that I found an interesting issue today:

9) I tried MSI Afterburner on LOF today - works fine until I switch with "Escape" into the game menu (which uses 2D) - the MSI overlay turns into filled quads and stays filled until I end+restart the game (see attached screenshots). This happens too when I replace my custom Begin2D()+End2D() functions with BeginMax2D()+EndMax2D(). Can somebody confirm this with another demo or could it be a bug in my game?
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #5 on: January 11, 2019, 03:44:20 AM »
Hi Krischan,

thanks for your consideration of my health, I am really not too bad so work will continue, albeit at a slow pace.

I have a fix up for the B3D textures not reloaded bug in LOF, it appears to have been the texture ref not getting returned from LoadTexture in TB3D, it's strange though as the ref *should* be the same and not need to be returned, anyway I'm pretty sure that was the problem.

Note that the latest version is now updated to Openb3d 1.25 so it will need LinkShader(s) called after AttachVertShader and AttachFragShader. The most interesting new feature is the PostFX functions which I'll need to make an example for. Also the GLES2 stuff, so it might build for Android now but I haven't tested.

Also I noticed your LOF shaders are written for GL3 which is what was crashing the game, so I just edited a few things to get it to compile on GL2.1:
Code: [Select]
//#version 130
//precision mediump float;
replace "in" with "varying"
replace "out" with "varying"

@Point 7: yes gltex[] was removed by Angros but I can add that back in to the streamed texture functions.

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
Re: OpenB3D Questions
« Reply #6 on: January 11, 2019, 10:02:59 AM »
Hi Mark,

great that you found time to add these fixes. It compiles and runs here, I've changed my shaders and added the LinkShader to the AssembleMap() Method in TBSP.bmx.

But when I switch the level it crashes at the ParseTextures() method - it seems to load the first texture but the next one crashes (in Renderworld() - inside the texture load function are some calls to UpdateLoader() which updates the Loading Screen with the spinning compass which needs a render pass in the loop there). This worked before and happens before the shaders are re-applied again.

I've added the patched Source, just overwrite the Dev project I've sent you.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #7 on: January 11, 2019, 09:12:49 PM »
Hi Krischan,

thanks, I can't reproduce this so I'm guessing it's a shader crash, you should try reverting to your original GLSL 130 syntax. I haven't tried your patch yet so I'll do that now.

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
Re: OpenB3D Questions
« Reply #8 on: January 11, 2019, 10:55:42 PM »
It didn't work with the original shader, too. It only "works" (=no crash) if I uncomment my ApplyShaderCache() Method - but then I don't have any level textures anymore. My current level loader is quite complex, but as far as I remember it works like that (it's all in the source but I try to describe it with my own words):

Global Shader Variables in the Type:

Code: BlitzMax
  1. Field VERTEXSHADER_SOURCE:String
  2. Field FRAGMENTSHADER_SOURCE:String
  3. Field MAINSHADER:TShader
  4. Field VERTEXSHADER_COMPILED:TShaderObject
  5. Field FRAGMENTSHADER_COMPILED:TShaderObject
  6. Field SHADERLIST:TList
  7. Field SHADERCACHED:TList

The BSP level geometry consists of several meshes and these can have different diffuse textures while the doors share the same texture but doors must be additional single meshes (not part of the level geometry mesh) to make alpha / Z-Index work on them (you can actually see through some of them). As I have many doors but only some level geometry meshes, I try to reuse the door shader using a cache to load the level faster. But I use only ONE shader source for both use cases (geometry and doors).

I first load the fragment+vertex shader source once (VERTEXSHADER_SOURCE+FRAGMENTSHADER_SOURCE), create a shader material (MAINSHADER), compile both sources once and attach the compiled shaders (VERTEXSHADER_COMPILED+FRAGMENTSHADER_COMPILED) to the MAINSHADER material. With your additions I then use the new LinkShader command on the MAINSHADER material? Is this correct?

Code: BlitzMax
  1. s = ReadFile(PATH_SHADER + filename + ".vert")
  2. VERTEXSHADER_SOURCE = ReadString(s, FileSize(PATH_SHADER + filename + ".vert"))
  3. s = ReadFile(PATH_SHADER + filename + ".vert")
  4. FRAGMENTSHADER_SOURCE = ReadString(s, FileSize(PATH_SHADER + filename + ".frag"))
  5. MAINSHADER = CreateShaderMaterial("")
  6. FRAGMENTSHADER_COMPILED = CreateFragShaderString(MAINSHADER, FRAGMENTSHADER_SOURCE)
  7. VERTEXSHADER_COMPILED = CreateVertShaderString(MAINSHADER, VERTEXSHADER_SOURCE)
  8. AttachFragShader(MAINSHADER, FRAGMENTSHADER_COMPILED)
  9. AttachVertShader(MAINSHADER, VERTEXSHADER_COMPILED)
  10. LinkShader(MAINSHADER)

The Shader cache works like this:
When a mesh gets assembled (geometry or door), on every new surface with different textures I create a new TShaderCache TMap Object and add all detail information about this surface to it (diffuse map, normal map, light map, surface id, mesh num and so on). I use a MD5 string of the diffuse filename plus the surface ID as a GUID key to distinguish between the same texture combinations and add new combinations to the SHADERLIST TList. This is because I don't want to create a new surface if it already exists. For example Walls should share the same shader while carpets or painting have their own shader. I think this is the best way to speed things up. And I've saved a lot of new surfaces with this algorithm.

After creating all meshes I use the ApplyShaderCache() Method. It iterates through all SHADERLIST objects and creates new shaders from the shader sources only for these surfaces. It adds the textures and variables to the shader and uses the ShadeSurface command to apply it to the cached surface. If it is a door, the MAINSHADER is applied instead.

I don't know why I don't compile this new created shader at this point (it is only created from the source) but I think I've had a big problem here I can't remember and needed to bypass it somehow (compiling here leads to a instant crash loading the initial level). I don't know if this is part of the problem:

Code: BlitzMax
  1. s.shader = CreateShader("", VERTEXSHADER_SOURCE, FRAGMENTSHADER_SOURCE)
  2. ShaderTexture(s.shader, s.dm, "diffuseMap", 0)
  3. ShaderTexture(s.shader, s.nm, "normalMap", 1)
  4. ShaderTexture(s.shader, s.lm, "lightMap", 2)
  5. ...
  6. ShadeSurface(s.surf, s.shader)

This new s.shader is then added to the SHADERCACHED TList for the next cache loop. The doors all use the precompiled global MAINSHADER instead of the newly created shaders. I don't know why but I had to create it this way but it really worked fast and flawless. When entering a new level, everything I created on the Load() Method is unloaded, cleared, nullified and destroyed. It is a large function but I think I didn't missed something and this worked before, too.

Currently I don't know what to change in my source to make it work again. So a very simple example would be nice: how to properly create, load, apply and unload/recreate a Vert+Frag Shader on a mesh with the same or a different texture without leaving shader, mesh or texture garbage behind before loading a new level - ideally with some kind of caching like I tried. A simple level loader/unloader with shaded meshes. I'm really confused how to use the shaders in such a complex but common scenario. But with such an example, I might be able to understand the problem better.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #9 on: January 12, 2019, 12:20:48 AM »
Hi Krischan,

well it's probably a bug in the Openb3d 1.25 code as the usematrix example is crashing, so  somethings wrong somewhere and I haven't figured it out yet, however your patch works perfectly here in win32 GL2.1. I suggest you test this by reverting to before the 1.25 update which is 12 sep 18.

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #10 on: January 18, 2019, 03:50:11 AM »
Hi Krischan,

here's an update on my progress, still lots to do...

I added the missing tex.gltex[0], Angros renamed it to frames so you can use that too, gltex just points to frames. Edit: actually only working with anim textures but fixed in latest commit.

Also added is tex.no_mipmaps[0] but it's calculated rather than counted at generation like Minib3d.

BeginMax2D now has a version parameter 0 for old one, 1 for your latest code, which I've credited you for in the source. So thanks. Your version definitely works better with 2d text so it should really be the default.

Other changes are error messages if mesh or texture urls are bad, this is essential functionality, of course Blitz3d does this.

And the 3DS loader is fixed (edit: well nearly) it's a port from Openb3d but with a few changes, texture v's are flipped so words read from left-right, mesh transforms are enabled with MeshLoader "trans" and there's a second 3DS loader from Warner which is improved and basically should now work the same as the default one, it's enabled by MeshLoader "3ds2".

Then there's MeshDebug 1 to enable extra mesh debug info (edit: changed to MeshLoader "debug").

And then LightMesh ported from Blitz3d. And a fix for FreeSurface crashing.

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
Re: OpenB3D Questions
« Reply #11 on: January 18, 2019, 08:59:01 AM »
Thanks for the update - it builds but I can't compile my game anymore:

C:/Apps/Coding/BlitzMax/mod/openb3dmax.mod/openb3dmax.mod/openb3dmax.release.win32.x86.a(openb3dmax.bmx.release.win32.x86.o):(code+0x1ca5b): undefined reference to `Log2_'
Build Error: Failed to link C:/LOF/Legend of Faerghail.exe

I compiled it like I did with all previous versions, cross-tested it with the 30 apr 18 version (everything is fine) and the 12 sep 18 version works, too (still with the texture/model bug).
bmk makemods -a -r openb3dmax
bmk makemods -a -d openb3dmax

By the way, does LOF work for you now? Another suggestion for future versions: sometimes OpenB3D shows error messages, sometimes they are commented in the CPP sources. For example in texture.cpp all errors are commented while in file.cpp there are some outputs.

It would be nice if this would be uniform across all sources and that you could switch it on/off with a global command, like let's say ShowDebugErrors() / HideDebugErrors(). But this is only a nice-to-have feature.
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #12 on: January 19, 2019, 06:22:04 AM »
Yes sorry, I forgot a file yesterday and didn't double-check.

The latest version replaces Log2 to Mipmaps. Also BeginMax2D now defaults to 1 which is your version. And another update to the 3DS loader, LoadMesh loads one mesh with many surfaces, LoadAnimMesh loads many meshes with one surface, CollapseAnimMesh was used before but wasn't working in bmx, it's a wierd function though so I'm not sure what it does. And shaders now debug errors when the filename is wrong.

Yes, LOF works with this latest commit so I'm not sure what's up but it may be a GL3 issue as I'm in GL2. You could try commenting out all ShadeSurface but I've just tested and that was working. Is it crashing exactly at the ShadeSurface function? It also might be the shader matrix code, so try running shader/bumpmap as it has some mat3 code.

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
Re: OpenB3D Questions
« Reply #13 on: January 20, 2019, 11:53:05 AM »
First - the model texture bug has vanished now - so the model textures are applied correct again after loading another level. Great.

But it still crashes after loading the next level. It only "works" when I comment the two ShadeSurface() commands in the ApplyShaderCache() Method in include\types\TBSP.bmx. The level geometry is untextured then, well at least I have some distance fog ;-) So Shadesurface crashes the texture loader in the second run. But why? I've tested it on an old nVidia GTX 780M with a very outdated driver (398.82) and a brandnew GTX 2080 with the newest driver (417.71) which still has the same problem. So is it a bug in LOF or in OpenB3D? I don't know.

And I think my custom Begin/End commands are not complete yet as I'm still having the MSI Afterburner OSD bug after entering the menu. The bug vanishes when I uncomment the glActiveTexture(GL_TEXTURE0) in BeginMax2D(), but then all menu textures vanish, too. Does anybody know why or how to fix it? And it is risky to use my own functions in OpenB3D as I really didn't knew what excactly to do there - it is the result of try and error only.

So it would make sense if someone who knows more about OpenGL than I do would take a look at it.

Code: BlitzMax
  1. Rem
  2. bbdoc: Blitz2D
  3. EndRem
  4. Type TBlitz2D
  5.  
  6.         Function BeginMax2D( version:Int=1 )
  7.        
  8.                 Select version
  9.                
  10.                 Case 0 ' Old begin function (by Oddball)
  11.                        
  12.                         glPopClientAttrib()
  13.                         glPopAttrib()
  14.                         glMatrixMode(GL_MODELVIEW)
  15.                         glPopMatrix()
  16.                         glMatrixMode(GL_PROJECTION)
  17.                         glPopMatrix()
  18.                         glMatrixMode(GL_TEXTURE)
  19.                         glPopMatrix()
  20.                         glMatrixMode(GL_COLOR)
  21.                         glPopMatrix()
  22.                        
  23.                 Case 1 ' New begin function, allows instant resolution switch (by Krischan)
  24.                        
  25.                         Local x:Int, y:Int, w:Int, h:Int
  26.                         GetViewport(x, y, w, h)
  27.                        
  28.                         'glPopClientAttrib()
  29.                         'glPopAttrib()
  30.                         glMatrixMode(GL_MODELVIEW)
  31.                         glPopMatrix()
  32.                         glMatrixMode(GL_PROJECTION)
  33.                         glPopMatrix()
  34.                         glMatrixMode(GL_TEXTURE)
  35.                         glPopMatrix()
  36.                         glMatrixMode(GL_COLOR)
  37.                         glPopMatrix()
  38.                          
  39.                         glDisable(GL_LIGHTING)
  40.                         glDisable(GL_DEPTH_TEST)
  41.                         glDisable(GL_SCISSOR_TEST)
  42.                         glDisable(GL_FOG)
  43.                         glDisable(GL_CULL_FACE)
  44.                        
  45.                         glMatrixMode GL_TEXTURE
  46.                         glLoadIdentity
  47.                        
  48.                         glMatrixMode GL_PROJECTION
  49.                         glLoadIdentity
  50.                         glOrtho(0, TGlobal.width[0], TGlobal.height[0], 0, -1, 1) ' TGlobal.w/h instead of GraphicsW/H for MaxGUI
  51.                        
  52.                         glMatrixMode GL_MODELVIEW
  53.                         glLoadIdentity
  54.                        
  55.                         SetViewport x, y, w, h
  56.                        
  57.                         Local MaxTex:Int
  58.                         glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))
  59.                        
  60.                         For Local Layer:Int = 0 Until MaxTex
  61.                                 glActiveTexture(GL_TEXTURE0+Layer)
  62.                        
  63.                                 glDisable(GL_TEXTURE_CUBE_MAP)
  64.                                 glDisable(GL_TEXTURE_GEN_S)
  65.                                 glDisable(GL_TEXTURE_GEN_T)
  66.                                 glDisable(GL_TEXTURE_GEN_R)
  67.                        
  68.                                 glDisable(GL_TEXTURE_2D)
  69.                         Next
  70.                        
  71.                         glActiveTexture(GL_TEXTURE0)
  72.                        
  73.                         glViewport(0, 0, TGlobal.width[0], TGlobal.height[0])
  74.                         glScissor(0, 0, TGlobal.width[0], TGlobal.height[0])
  75.                        
  76.                         glEnable GL_BLEND
  77.                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  78.                         glEnable(GL_TEXTURE_2D)
  79.                        
  80.                 End Select
  81.                
  82.         End Function
  83.        
  84.         ' Old end Max2d function
  85.         Function EndMax2D( version:Int=1 )
  86.        
  87.                 Select version
  88.                
  89.                 Case 0 ' Old end function (by Oddball)
  90.                
  91.                         ' save the Max2D settings for later
  92.                         glPushAttrib(GL_ALL_ATTRIB_BITS)
  93.                         glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS)
  94.                         glMatrixMode(GL_MODELVIEW)
  95.                         glPushMatrix()
  96.                         glMatrixMode(GL_PROJECTION)
  97.                         glPushMatrix()
  98.                         glMatrixMode(GL_TEXTURE)
  99.                         glPushMatrix()
  100.                         glMatrixMode(GL_COLOR)
  101.                         glPushMatrix()
  102.                        
  103.                         TGlobal.EnableStates() ' enables normals and vertex colors
  104.                         glDisable(GL_TEXTURE_2D) ' needed as Draw in Max2d enables it, but doesn't disable after use
  105.                        
  106.                         ' set render state flags (crash if fx2 is not set)
  107.                         TGlobal.alpha_enable[0]=0 ' alpha blending was disabled by Max2d (GL_BLEND)
  108.                         TGlobal.blend_mode[0]=1 ' force alpha blending
  109.                         TGlobal.fx1[0]=0 ' full bright/surface normals was enabled by EnableStates (GL_NORMAL_ARRAY)
  110.                         TGlobal.fx2[0]=1 ' vertex colors was enabled by EnableStates (GL_COLOR_ARRAY)
  111.                        
  112.                         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR)
  113.                         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)
  114.                        
  115.                         glClearDepth(1.0)                                              
  116.                         glDepthFunc(GL_LEQUAL)
  117.                         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  118.                        
  119.                         glAlphaFunc(GL_GEQUAL,0.5)
  120.                        
  121.                         For Local cam:TCamera=EachIn TCamera.cam_list
  122.                                 If cam=TGlobal.camera_in_use ' active camera - was if cam.hide[0]=0
  123.                                         cam.UpdateFog() ' fog with Max2d fix
  124.                                         Exit
  125.                                 EndIf
  126.                         Next
  127.                        
  128.                 Case 1 ' New end function, allows instant resolution switch (by Krischan)
  129.                
  130.                         ' save the Max2D settings for later
  131.                         'glPushAttrib(GL_ALL_ATTRIB_BITS)
  132.                         'glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS)
  133.                         glMatrixMode(GL_MODELVIEW)
  134.                         glPushMatrix()
  135.                         glMatrixMode(GL_PROJECTION)
  136.                         glPushMatrix()
  137.                         glMatrixMode(GL_TEXTURE)
  138.                         glPushMatrix()
  139.                         glMatrixMode(GL_COLOR)
  140.                         glPushMatrix()
  141.                          
  142.                         glDisable(GL_TEXTURE_CUBE_MAP)
  143.                         glDisable(GL_TEXTURE_GEN_S)
  144.                         glDisable(GL_TEXTURE_GEN_T)
  145.                         glDisable(GL_TEXTURE_GEN_R)
  146.                        
  147.                         glDisable(GL_TEXTURE_2D)
  148.                         glDisable(GL_BLEND)
  149.                        
  150.                         TGlobal.EnableStates()
  151.                        
  152.                         ' set render state flags (crash if fx2 is not set)
  153.                         TGlobal.alpha_enable[0]=0 ' alpha blending was disabled by Max2d (GL_BLEND)
  154.                         TGlobal.blend_mode[0]=1 ' force alpha blending
  155.                         TGlobal.fx1[0]=0 ' full bright/surface normals was enabled by EnableStates (GL_NORMAL_ARRAY)
  156.                         TGlobal.fx2[0]=1 ' vertex colors was enabled by EnableStates (GL_COLOR_ARRAY)
  157.                        
  158.                         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)
  159.                         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)
  160.                        
  161.                         glClearDepth(1.0)
  162.                         glDepthFunc(GL_LEQUAL)
  163.                         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  164.                        
  165.                         glAlphaFunc(GL_GEQUAL, 0.5)
  166.                        
  167.                         For Local cam:TCamera=EachIn TCamera.cam_list ' active camera - was if cam.hide[0]=0
  168.                                 If cam = TGlobal.camera_in_use ' fog with Max2d fix
  169.                                         cam.UpdateFog()
  170.                                         Exit
  171.                                 EndIf
  172.                         Next
  173.                        
  174.                 End Select
  175.                
  176.         End Function
  177.        
  178. End Type
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D Questions
« Reply #14 on: January 22, 2019, 04:34:00 AM »
Hi Krischan,

I think I have a fix for the ShadeSurface crash now, I was able to reproduce it, as it turns out the shader/usematrix crash is the same bug, which is a crash if a b3d model had no texture, it happened in shader render TurnOn. The fix skips rendering if there's no texture for shader, brush and surface brush.

Then there's a fix for the vertex color breaking with Max2D, it happens if the mesh is the last in the list, some state is not being set/reset but I couldn't figure out what so I settled for just rendering a dummy mesh after everything.

Also BeginMax2d has the glPopAttrib/glPushAttrib code back in because this may fix your MSI Afterburner issue, if you don't do this the blend state isn't saved and can be affected by other code, Text doesn't do this and it changes depending on the last blend used, see standard/alphamap. I wasn't able to test with Afterburner as I don't know what that is, so please let me know how that goes. Thanks!

I also noticed in LOF when you reload a level sometimes a letter is blocked out in the menu text, like it was a C today but an S last time, I think it must be a LOF bug as it happens randomly.