Bouncy Balls On Water conversion from Delphi

Started by SToS, November 21, 2024, 13:59:30

Previous topic - Next topic

SToS

Just for fun... Although, I'm not quite happy with this one.  Something seems off. :-[

SuperStrict

'//-ORIGINAL CODE (in Delphi) by-------------------------------------------
'//
'// Author      : Maarten Kronberger
'// Email       : maartenk@tinderbox.co.za
'// Website     : http:'//www.sulaco.co.za
'//               http:'//www.tinderbox.co.za
'// date        : 12 September 2002
'// Version     : 1.0
'// Description : Bounce water
'//
'//------------------------------------------------------------------------
' Translated (roughly) to BlitzMax NG by SToS/A.K.A. Tantalus

Const WIN_WIDTH:UInt = 800
Const WIN_HEIGHT:UInt = 600
Const GRIDSIZE:Int = 64
Const GLU_SMOOTH:Int = 100000

Type TVertex3 Final
    Field x:Float
    Field y:Float
    Field z:Float
    Method New()
        Self.x = 0.0
        Self.y = 0.0
        Self.z = 0.0
    End Method
End Type

Type TBall Final
    Field bally:Float
    Field angle:Float
    Field xsize:Float
    Field ysize:Float
    Field anglemodifier:Float
    Field ripplex:Int
    Field rippley:Int
    Method New(anglemodifier:Float, ripplex:Int, rippley:Int)
        Self.bally = 0.0
        Self.angle = 0.0
        Self.xsize = 0.0
        Self.ysize = 0.0
        Self.anglemodifier = anglemodifier
        Self.ripplex = ripplex
        Self.rippley = rippley
    End Method
End Type

Global elapsedtime:Int
Global lasttime:Int
' textures
Global floortex:UInt
Global balltex:UInt
Global reflectmirrortex:UInt
' user vaiables
Global myquadratic:Byte Ptr
'ball variables
Global balls:TBall[6]
'water variables
Global viscosity:Float
Global position:Float[GRIDSIZE, GRIDSIZE]
Global velocity:Float[GRIDSIZE, GRIDSIZE]
Global vertex:TVertex3[GRIDSIZE, GRIDSIZE]
Global normals:TVertex3[GRIDSIZE, GRIDSIZE]

Function Rad2Deg:Float(r:Float)
    Return r * 180.0 / 3.14159
End Function

Function CreateRipple(i:Int, j:Int)
    velocity[i, j] = 1000.0
End Function

Function LoadTexture:UInt(path:String)
    Local id:UInt = 0
    Local tmp:TPixmap = LoadPixmap(path)
    Assert(tmp)
    Local pixmap:TPixmap = ConvertPixmap(tmp, PF_RGB888)
    Assert(pixmap)
    Local pixel_data:Byte Ptr = PixmapPixelPtr(pixmap)
    Assert(pixel_data)
    glGenTextures(1, Varptr id)
    glBindTexture(GL_TEXTURE_2D, id)
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, PixmapWidth(pixmap), PixmapHeight(pixmap), GL_RGB, GL_UNSIGNED_BYTE, pixel_data)
    Return id
End Function

Function DrawWater()
    ' calculate New velocity
    For Local i:Int = 2 To GRIDSIZE - 2
        For Local j:Int = 2 To GRIDSIZE - 2
            velocity[i, j] = velocity[i  ,   j] + ..
                            (position[i  ,   j] - ..
                     (4.0 * (position[i-1,   j] + ..
                             position[i+1,   j] + ..
                             position[i,   j-1] + ..
                             position[i,   j+1]) + ..
                             position[i-1, j-1] + ..
                             position[i+1, j-1] + ..
                             position[i-1, j+1] + ..
                             position[i+1, j+1]) / 25.0) / 7.0
        Next j
    Next i
    
    ' calculate the New ripple positions
    For Local i:Int = 2 To GRIDSIZE - 3
        For Local j:Int = 2 To GRIDSIZE - 3
            position[i, j] :- velocity[i,j]
            velocity[i, j] :* viscosity
        Next j
    Next i
   
    ' calculate the New vertex coordinates
    For Local i:Int = 0 To GRIDSIZE - 1
        For Local j:Int = 0 To GRIDSIZE - 1
            vertex[i, j].x = (i - GRIDSIZE / 2.0) / GRIDSIZE * 5.0
            vertex[i, j].y = (position[i, j] / 1024)/GRIDSIZE * 3.0
            vertex[i, j].z = (j - GRIDSIZE / 2.0) / GRIDSIZE * 5.0
        Next j
    Next i
   
    ' calculate the New vertex normals.
    ' do this by using the points To each side To get the Right angle
    For Local i:Int = 0 To GRIDSIZE - 1
        For Local j:Int = 0 To GRIDSIZE - 1
            If (i > 0) And (j > 0) And (i < GRIDSIZE - 1) And (j < GRIDSIZE - 1) Then
                normals[i, j].x = position[i+1, j] - position[i-1,j]
                normals[i, j].y = -2048.0
                normals[i, j].z = position[i, j+1] - position[i, j-1]
           
                Local vectlength:Float = SqrF(normals[i, j].x * normals[i, j].x + ..
                                              normals[i, j].y * normals[i, j].y + ..
                                              normals[i, j].z * normals[i, j].z)
                If vectlength <> 0.0 Then
                    normals[i, j].x :/ vectlength
                    normals[i, j].y :/ vectlength
                    normals[i, j].z :/ vectlength
                EndIf
            Else
                normals[i, j].x = 0.0
                normals[i, j].y = 1.0
                normals[i, j].z = 0.0
            EndIf
        Next j
    Next i
    ' draw the water texture
    glBindTexture(GL_TEXTURE_2D, floortex)
   
    For Local j:Int = 0 To GRIDSIZE - 2
        glColor3f(j / 100.0, j / 100.0, j / 100.0)
        glBegin(GL_QUAD_STRIP)
        For Local i:Int = 0 To GRIDSIZE - 1
            glNormal3f(normals[i, j+1].x, normals[i, j+1].y, normals[i, j+1].z)
            glVertex3f( vertex[i, j+1].x,  vertex[i, j+1].y,  vertex[i, j+1].z)
            glNormal3f(normals[i,   j].x, normals[i,   j].y, normals[i,   j].z)
            glVertex3f( vertex[i,   j].x,  vertex[i,   j].y,  vertex[i,   j].z)
        Next i
        glEnd()
    Next j
End Function

Function DrawBall(xsize:Float, ysize:Float, xpos:Float, zpos:Float, bally:Float)
    glPushmatrix()
    '-----  draw pond walls  -----
    glDisable(GL_BLEND)
    glDisable(GL_ALPHA_TEST)
    glDisable(GL_TEXTURE_2D)
    glBegin(GL_QUADS)
        'Left wall
        glColor3f(0.5608, 0.5725, 0.5804)
        glVertex3f(-2.5, 0.0, -2.5)
        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(-2.5, 0.0, 2.5)
        glColor3f(1.0, 1.0, 1.0)
        glVertex3f(-2.5, 2.0, 2.5)
        glColor3f(0.5608, 0.5725, 0.5804)
        glVertex3f(-2.5, 2.0, -2.5)
       
        'Right wall
        glColor3f(1.0, 1.0, 1.0)
        glvertex3f(2.5, 0.0, 2.5)
        glColor3f(0.5608, 0.5725, 0.5804)
        glvertex3f(2.5, 0.0, -2.5)
        glColor3f(0.5608, 0.5725, 0.5804)
        glvertex3f(2.5, 2.0, -2.5)
        glColor3f(1.0, 1.0, 1.0)
        glvertex3f(2.5, 2.0, 2.5)
    glEnd()
    glEnable(GL_TEXTURE_2D)
    glEnable(GL_ALPHA_TEST)
    glPopMatrix()
    glPushmatrix()
        glFrontface(GL_CCW)
        '-----  draw the main ball  -----
        ' draw the ball using standard textures
        glTranslatef(0.0, 0.0 , 0.0)
       
        glScalef(xsize, ysize, xsize)     ' squash the ball into shape
       
        glDisable(GL_BLEND)
       
        glTranslatef(xpos, 0.1 + bally, zpos)
       
        ' draw top sphere   
        glColor3f(1.0, 1.0, 1.0)
        glBindTexture(GL_TEXTURE_2D, balltex)
        gluSphere(myquadratic, 0.3, 32, 32)
    glPopMatrix()
   
    glPushMatrix()
        '-----  draw the reflection of the ball  -----
        ' draw the ball using standard textures   
        glScalef(xsize, ysize, xsize)     ' squash the ball into shape
        glColor3f(0.4, 0.4, 0.4)
        glTranslatef(xpos, -0.1 - bally, zpos)
        glRotatef(45.0, 1.0, 1.0, 1.0)
   
        ' draw a sphere For the reflection
        glEnable(GL_BLEND)
       
        glDepthFunc(GL_LEQUAL)
        glBindTexture(GL_TEXTURE_2D, reflectmirrortex)
        gluSphere(myquadratic, 0.3, 24, 24)
       
        glEnable(GL_TEXTURE_GEN_S)     ' enable spherical
        glEnable(GL_TEXTURE_GEN_T)     ' environment mapping
    glPopMatrix()
End Function

Function glDraw()
    glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
   
    '----- set ball positions -----
    For Local ball:TBall = EachIn balls
        ball.angle = elapsedtime / 60.0 * ball.anglemodifier
    Next
   
    glTranslatef(-0.25, 0.0, -4.6)
    glRotatef(50, 1.0, 0.0, 0.0)
   
    '----- calculate the ball positions -----
    For Local ball:TBall = EachIn balls
        ball.bally = Abs(1.6 * SinF(Rad2Deg(ball.angle / 24)))
        If ball.bally < 0.11 Then
            CreateRipple(ball.ripplex, ball.rippley)
            ball.ysize = 0.5 / (1.0 + (0.11 - ball.bally))
        Else
            ball.ysize = 0.5
        EndIf
        ball.xsize = 0.5
    Next
   
    '//----- draw the balls -----'//
    DrawBall(balls[0].xsize * 1.3, balls[0].ysize * 1.3,  0.0,  0.0, balls[0].bally)
    DrawBall(balls[1].xsize      , balls[1].ysize      ,  0.7,  0.7, balls[1].bally)
    DrawBall(balls[2].xsize * 1.1, balls[2].ysize * 1.1,  1.6, -0.7, balls[2].bally)
    DrawBall(balls[3].xsize * 1.5, balls[3].ysize * 1.5, -1.0, -1.0, balls[3].bally)
    DrawBall(balls[4].xsize * 2.0, balls[4].ysize * 2.0, -1.0,  1.0, balls[4].bally)
    DrawBall(balls[5].xsize * 1.9, balls[5].ysize * 1.9,  1.7,  0.9, balls[5].bally)
   
    '//-----  draw the Floor  -----'//
    glFrontface(GL_CW)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE)
    glDepthFunc(GL_LESS)
   
    DrawWater()
   
    glFinish()
End Function

Function glInit()
    glClearColor(0.5608, 0.5725, 0.5804, 0.0)   ' black background
    glShadeModel(GL_SMOOTH)                     ' enables smooth color shading
    glClearDepth(1.0)                           ' depth buffer Setup
    glEnable(GL_DEPTH_TEST)                     ' enable depth buffer
    glDepthFunc(GL_LESS)                        ' the Type of depth test To do
      
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)   ' realy nice Perspective calculations
   
    myquadratic = gluNewQuadric()               ' Create a pointer To the quadric Object (Return 0 If no memory) (New)
    gluQuadricNormals(myquadratic, GLU_SMOOTH)  ' Create smooth normals (New)
    gluQuadricTexture(myquadratic, GL_TRUE)     ' Create texture coords (New)
   
    glEnable(GL_CULL_FACE)
    glEnable(GL_TEXTURE_2D)                     ' enable texture mapping
    glTexgenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
    glTexgenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
   
    'load textures
    floortex         = LoadTexture("floor.bmp")
    balltex          = LoadTexture("reflection.bmp")
    reflectmirrortex = LoadTexture("reflectionmirror.bmp")
   
    viscosity = 0.96
    For Local i:Int = 0 To GRIDSIZE - 1
        For Local j:Int = 0 To GRIDSIZE - 1
            position[i, j] = 0.0
            velocity[i, j] = 0.0
            vertex[i, j] = New TVertex3
            normals[i, j] = New TVertex3
        Next j
    Next i
    SeedRnd(MilliSecs())
    'init ripple positions
    balls[0] = New TBall(RndFloat() + 0.2, 32, 31)
    balls[1] = New TBall(RndFloat() + 0.2, 36, 37)
    balls[2] = New TBall(RndFloat() + 0.2, 42, 27)
    balls[3] = New TBall(RndFloat() + 0.2, 23, 24)
    balls[4] = New TBall(RndFloat() + 0.2, 20, 45)
    balls[5] = New TBall(RndFloat() + 0.2, 51, 44)
End Function

Function glResizeWnd(w:Int, h:Int)
    If h = 0 Then h = 1
    glViewport(0, 0, w, h)            ' set the viewport For the opengl window
    glMatrixMode(GL_PROJECTION)       ' change matrix mode To projection
    glLoadIdentity()                  ' reset view
    gluPerspective(45.0, Float(w) / Float(h), 1.0, 100.0)  ' do the Perspective calculations. last value = Max clipping depth
    glMatrixMode(GL_MODELVIEW)        ' Return To the modelview matrix
    glLoadIdentity()                  ' reset view
End Function

Graphics WIN_WIDTH, WIN_HEIGHT, 0

glInit()
glResizeWnd(WIN_WIDTH, WIN_HEIGHT)

lasttime = MilliSecs()
Repeat
    Cls
    glDraw()
    Flip
    elapsedtime = MilliSecs() - lasttime
Until KeyDown(KEY_ESCAPE) Or AppTerminate()

screenshot.png
bouncewater.zip