The Amazing Bubble Universe Animation

Started by MrBcx, December 20, 2024, 09:31:39 PM

Previous topic - Next topic

MrBcx

The attached screenshot doesn't do this justice - you really need to watch it run.

The depth of detail from so little code is mind-blowing and just fun to watch.

BED will build this GUI app using any of the compilers.




'===================================================================
' Based on Bubble Universe by Yuruyurau
' https://x.com/yuruyurau/status/1226846058728177665
' Converted to BCX by MrBcx on December 20, 2024.     Public Domain
'===================================================================
$BCXVERSION "8.0.4"

GUI "Bubble Universe", PIXELS

CONST xmax = 900
CONST ymax = 900


SUB FORMLOAD
    GLOBAL Form1 AS HWND
    Form1 = BCX_FORM ("Bubble Universe",  0, 0, xmax+10, ymax+20)
    MODSTYLE(Form1, 0, WS_MAXIMIZEBOX | WS_MINIMIZEBOX, FALSE)
    CENTER Form1
    SHOW   Form1
    CALL Drawit
END SUB


BEGIN EVENTS
    SELECT CASE CBMSG
        CASE WM_QUIT, WM_CLOSE, WM_DESTROY
        END
    END SELECT
END EVENTS


SUB Drawit
    DIM AS DWORD Kolor
    DIM AS LONG n, y, CenterX, CenterY
    DIM AS DOUBLE Impedance, Tau, r, u, v, x, t

    Impedance = 0.01  ' lower this value to slow down the animation, if needed
    Tau = PI * 2
    r = Tau / 235
    CenterX = xmax / 2
    CenterY = ymax / 2
    n = 200           ' pixels per frame = n^2

   DO
        BCX_BUFFER_START(xmax, ymax)
        DOEVENTS
        SLEEP(0)
        FOR INT i = 0 TO n
            FOR INT j = 0 TO n
                u = SIN(i + v) + SIN(r * i + x)
                v = COS(i + v) + COS(r * i + x)
                x = u + t
                Kolor = RGB(i, j, 99)
                BCX_PSET (0, CenterX + u * CenterX * 0.4, CenterY + v * CenterY * 0.4, Kolor, BCX_BUFFER)
            NEXT
        NEXT
        BCX_BUFFER_STOP(Form1)
        t = t + Impedance
    LOOP
END SUB





dragon57

Right down my alley, wonderful, I love it.

Saleh

Thank you kevin, very very amazing!

I say that God exists (of course, after the universe came into being from nothing, he came into being by accident too) and because he himself could not find the root of the matter, he created another microcosm surrounding himself without any purpose and just for his own enjoyment. Yes, he is playing, and he is playing very well.

MrBcx

#3
I started creating a tiny OpenGL wrapper library to simplify things in a familiar BCX way.

Here is an OpenGL version of Bubble Universe that uses my wrappers.  One point worth
noting is the code similarity of the OpenGL version to the original Win32 GDI version, thanks to
the way I've named the wrappers.  This demo displays twice as many pixels per frame and yet
still runs faster and smoother than the original GDI version.

The wrapper library was only started today, so it's very limited but this demo only uses about
half of the SUBs contained in the library.  Eventually, the wrapper will be placed in its own
include file but for this demo, it is included at the bottom of the main app.  It was tested
with Pelles and MSVC using BED.  It should not take much effort to build with other compilers.


'====================================================
'                    Bubble Universe
'           MrBcx OpenGL Tiny Wrapper Library
'====================================================
'            Tested with MSCV and Pelles C
'====================================================
GUI "Demo", PIXELS

CONST xmax = 900
CONST ymax = 900

SUB FORMLOAD
    GLOBAL AS HWND Form1
    Form1 = BCX_FORM("Demo", 0, 0, xmax, ymax)
    MODSTYLE(Form1, 0, WS_MAXIMIZEBOX | WS_MINIMIZEBOX, FALSE)
    CENTER Form1
    SHOW Form1
    CALL Drawit
END SUB


BEGIN EVENTS
    SELECT CASE CBMSG
        CASE WM_QUIT, WM_CLOSE, WM_DESTROY
        CALL OGL_END()
        END
    END SELECT
END EVENTS


SUB Drawit
    DIM AS DWORD Kolor
    DIM AS LONG n, y, CenterX, CenterY
    DIM AS DOUBLE Impedance, Tau, r, u, v, x, t

    Impedance = 0.005  ' lower this value to slow down the animation, if needed
    Tau = PI * 2
    r = Tau / 235
    CenterX = xmax / 2
    CenterY = ymax / 2
    n = 400           ' pixels per frame = n^2

    DIM AS HDC hdc
    OGL_INIT(Form1, xmax, ymax)

    DO
        OGL_BUFFER_START()
        hdc = GetDC(Form1)

        DOEVENTS
        FOR INT i = 0 TO n
            FOR INT j = 0 TO n
                u = SIN(i + v) + SIN(r * i + x)
                v = COS(i + v) + COS(r * i + x)
                x = u + t
                Kolor = RGB(i, j, 99)
                OGL_PSET (CenterX + u * CenterX * 0.4, CenterY + v * CenterY * 0.4, Kolor)
            NEXT
        NEXT
        OGL_BUFFER_STOP(Form1, hdc)
        t = t + Impedance
    LOOP
END SUB




'==========================================================================================
'                                 BCX TINY OPENGL Library
'==========================================================================================
'             List of available wrappers ( this is a work in progress )
'==========================================================================================
' OGL_INIT         (Form1, MAXX, MAXY)
' OGL_END          ()
' OGL_BUFFER_START ()
' OGL_BUFFER_STOP  (Form1, hdc)
'==========================================================================================
' OGL_PSET   (x%, y%, RGBValue AS COLORREF)
' OGL_PRESET (x AS INT, y AS INT)
' OGL_LINE   (x1%, y1%, x2%, y2%, RGBValue AS COLORREF)
' OGL_LINETO (x%, y%, RGBValue AS COLORREF)
' OGL_CIRCLE (cx%, cy%, Radius AS SINGLE, RGBValue AS COLORREF, FillFlag% = 0)
' OGL_RECTANGLE (x1%, y1%, x2%, y2%, RGBValue AS COLORREF, FillFlag% = 0)
' OGL_TRIANGLE (x1%, y1%, x2%, y2%, x3%, y3%, RGBValue AS COLORREF, FillFlag% = 0)
' OGL_ELLIPSE (Left%, Top%, Right%, Bottom%, RGBValue AS COLORREF, FillFlag% = 0)
' OGL_ARC(Left%, Top%, Right%, Bottom%, BCX%, BCY%, ECX%, ECY%, RGBValue AS COLORREF)
'==========================================================================================

#include <GL/gl.h>
#include <GL/glu.h>

$PRAGMA comment(lib, "opengl32.lib")
$PRAGMA comment(lib, "glu32.lib")

GLOBAL GL_CurrentX% ' Globals for tracking the current position
GLOBAL GL_CurrentY%


SUB OGL_INIT(F AS HWND, x, y)
    DIM AS PIXELFORMATDESCRIPTOR pfd =                               _
    { SIZEOF(PIXELFORMATDESCRIPTOR), 1,                              _
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,      _
    PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 0, _
    PFD_MAIN_PLANE, 0, 0, 0, 0}

    DIM AS HDC hdc = GetDC(F)
    DIM AS INT pixelFormat = ChoosePixelFormat(hdc, &pfd)
    SetPixelFormat(hdc, pixelFormat, &pfd)

    DIM AS HGLRC hglrc = wglCreateContext(hdc)
    wglMakeCurrent(hdc, hglrc)

    glEnable(GL_DEPTH_TEST)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

    glViewport(0, 0, x, y)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, x, y, 0)  ' Adjusted to match the coordinate system used in GDI
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    ReleaseDC(F, hdc)
END SUB


SUB OGL_BUFFER_START
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
END SUB


SUB OGL_BUFFER_STOP(argForm AS HWND, arghdc AS HDC)
    SwapBuffers(arghdc)
    ReleaseDC(argForm, arghdc)
END SUB


SUB OGL_END
    ' Usage:  CASE WM_QUIT, WM_CLOSE, WM_DESTROY : CALL OGL_END()
    DIM AS HDC hdc = GetDC(Form1)
    DIM AS HGLRC hglrc = wglGetCurrentContext()
    wglMakeCurrent(NULL, NULL)
    wglDeleteContext(hglrc)
    ReleaseDC(Form1, hdc)
END SUB



SUB OGL_CIRCLE(cx AS INT, cy AS INT, Radius AS SINGLE, RGBValue AS COLORREF, FillFlag% = 0)
    '======================================================================================
    '                           Draw a circle with OpenGL
    '======================================================================================

    ' Decompose the RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red

    ' Set the OpenGL color
    glColor3f(r, g, b)

    ' Choose the appropriate OpenGL mode based on Fill
    IF FillFlag = 1 THEN
        glBegin(GL_POLYGON) ' Filled circle
    ELSE
        glBegin(GL_LINE_LOOP) ' Outline
    END IF

    ' Draw the circle
    FOR SINGLE angle = 0 TO 2 * PI STEP PI / 18
        glVertex2f(cx + Radius * COS(angle), cy + Radius * SIN(angle))
    NEXT
    glEnd()

    GL_CurrentX = cx
    GL_CurrentY = cy
END SUB


SUB OGL_PSET(cx AS INT, cy AS INT, RGBValue AS COLORREF)
    '======================================================================================
    '                           Draw a pixel with OpenGL
    '======================================================================================
    ' Convert RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red
    ' Set the OpenGL color
    glColor3f(r, g, b)
    ' Start drawing points
    glBegin(GL_POINTS) ' OpenGL requires GL_POINTS for individual pixels
    glVertex2f(cx, cy) ' Specify the pixel position
    glEnd()            ' End the drawing operation
    GL_CurrentX = cx
    GL_CurrentY = cy
END SUB


SUB OGL_PRESET(x AS INT, y AS INT)
    '======================================================================================
    '             Set the starting position for the next GL drawing command
    '======================================================================================
    GL_CurrentX = x
    GL_CurrentY = y
END SUB




SUB OGL_LINE (x1 AS INT, y1 AS INT, x2 AS INT, y2 AS INT, RGBValue AS COLORREF)
    '======================================================================================
    '                   DRAW a LINE WITH OpenGL
    '======================================================================================
    ' Convert RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red
    ' SET the OpenGL COLOR
    glColor3f(r, g, b)

    ' DRAW the LINE

    glBegin(GL_LINES)
    glVertex2f(x1, y1)
    glVertex2f(x2, y2)
    glEnd()

    GL_CurrentX = x2
    GL_CurrentY = y2
END SUB


SUB OGL_LINETO (x AS INT, y AS INT, RGBValue AS COLORREF)
    '======================================================================================
    '                           Draw a line to a new point with OpenGL
    '======================================================================================
    ' Convert RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red
    ' Set the OpenGL color
    glColor3f(r, g, b)
    ' Draw the line from the current position to the new position
    glBegin(GL_LINES)                    ' OpenGL requires GL_LINES for line segments
    glVertex2f(GL_CurrentX, GL_CurrentY) ' Start at the current position
    glVertex2f(x, y)                     ' End at the new position
    glEnd()
    ' Update the current position
    GL_CurrentX = x
    GL_CurrentY = y
END SUB


SUB OGL_RECTANGLE(x1%, y1%, x2%, y2%, RGBValue AS COLORREF, FillFlag% = 0)
    '======================================================================================
    '                           Draw a rectangle with OpenGL
    '======================================================================================

    ' Convert RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red

    ' Set the OpenGL color
    glColor3f(r, g, b)

    ' Choose the appropriate OpenGL mode based on FillFlag
    IF FillFlag = 1 THEN
        glBegin(GL_QUADS)    ' Filled rectangle
    ELSE
        glBegin(GL_LINE_LOOP) ' Rectangle outline
    END IF

    ' Specify the vertices of the rectangle
    glVertex2f(x1, y1) ' Bottom-left corner
    glVertex2f(x2, y1) ' Bottom-right corner
    glVertex2f(x2, y2) ' Top-right corner
    glVertex2f(x1, y2) ' Top-left corner

    ' End the drawing operation
    glEnd()
END SUB


SUB OGL_TRIANGLE(x1%, y1%, x2%, y2%, x3%, y3%, RGBValue AS COLORREF, FillFlag% = 0)
    '======================================================================================
    '                           Draw a triangle with OpenGL
    '======================================================================================

    ' Convert RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red

    ' Set the OpenGL color
    glColor3f(r, g, b)

    ' Choose the appropriate OpenGL mode based on FillFlag
    IF FillFlag = 1 THEN
        glBegin(GL_TRIANGLES)    ' Filled triangle
    ELSE
        glBegin(GL_LINE_LOOP)    ' Triangle outline
    END IF

    ' Specify the vertices of the triangle
    glVertex2f(x1, y1) ' First vertex
    glVertex2f(x2, y2) ' Second vertex
    glVertex2f(x3, y3) ' Third vertex

    ' End the drawing operation
    glEnd()
END SUB


SUB OGL_ELLIPSE(Left%, Top%, Right%, Bottom%, RGBValue AS COLORREF, FillFlag% = 0)
    '======================================================================================
    '                           Draw an ellipse with OpenGL
    '======================================================================================

    ' Calculate the center and radii
    DIM cx AS SINGLE, cy AS SINGLE
    DIM RadiusX AS SINGLE, RadiusY AS SINGLE
    cx = (Left + Right) / 2.0      ' X-coordinate of the center
    cy = (Top + Bottom) / 2.0      ' Y-coordinate of the center
    RadiusX = (Right - Left) / 2.0 ' Horizontal radius
    RadiusY = (Bottom - Top) / 2.0 ' Vertical radius

    ' Convert RGBValue into r, g, b components
    DIM AS SINGLE r, g, b
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red

    ' Set the OpenGL color
    glColor3f(r, g, b)

    ' Choose the appropriate OpenGL mode based on FillFlag
    IF FillFlag = 1 THEN
        glBegin(GL_POLYGON) ' Filled ellipse
    ELSE
        glBegin(GL_LINE_LOOP) ' Outline
    END IF

    ' Draw the ellipse
    FOR SINGLE angle = 0 TO 2 * PI STEP PI / 36 ' 36 segments for a smooth ellipse
        DIM x AS SINGLE, y AS SINGLE
        x = cx + RadiusX * COS(angle)
        y = cy + RadiusY * SIN(angle)
        glVertex2f(x, y)
    NEXT

    ' End the drawing operation
    glEnd()
END SUB



SUB OGL_ARC(Left%, Top%, Right%, Bottom%, BCX%, BCY%, ECX%, ECY%, RGBValue AS COLORREF)
    '======================================================================================
    '                               Draw an arc with OpenGL
    '======================================================================================

    ' Calculate the center and radii
    DIM cx AS SINGLE, cy AS SINGLE
    DIM RadiusX AS SINGLE, RadiusY AS SINGLE
    cx = (Left + Right) / 2.0      ' X-coordinate of the center
    cy = (Top + Bottom) / 2.0      ' Y-coordinate of the center
    RadiusX = (Right - Left) / 2.0 ' Horizontal radius
    RadiusY = (Bottom - Top) / 2.0 ' Vertical radius

    ' Convert RGBValue into r, g, b components
    DIM r AS FLOAT, g AS FLOAT, b AS FLOAT
    b = ((RGBValue AND &HFF0000) >> 16) / 255.0 ' Extract blue
    g = ((RGBValue AND &H00FF00) >> 8) / 255.0  ' Extract green
    r = (RGBValue AND &H0000FF) / 255.0         ' Extract red

    ' Set the OpenGL color
    glColor3f(r, g, b)

    ' Determine the angles for the start and end points
    DIM StartAngle AS SINGLE, EndAngle AS SINGLE
    StartAngle = ATN2(BCY - cy, BCX - cx) ' Angle for the beginning point
    EndAngle = ATN2(ECY - cy, ECX - cx)   ' Angle for the ending point

    ' Ensure the angles are in the range [0, 2π]
    IF StartAngle < 0 THEN StartAngle = StartAngle + 2 * PI
    IF EndAngle < 0 THEN EndAngle = EndAngle + 2 * PI

    ' Draw the arc
    glBegin(GL_LINE_STRIP)
    FOR SINGLE angle = StartAngle TO EndAngle STEP PI / 36 ' Adjust step for smoothness
        DIM x AS SINGLE, y AS SINGLE
        x = cx + RadiusX * COS(angle)
        y = cy + RadiusY * SIN(angle)
        glVertex2f(x, y)
    NEXT
    glEnd()
END SUB




Here is a 15 second loop ...



Saleh

Quote from: MrBcx on December 24, 2024, 06:43:50 PM
It should not take much effort to build with other compilers.

Hi kevin,
MinGW fails to prefix _impl_ to exported functions,


BCX BASIC to C/C++ Translator (c) 1999-2024 by Kevin Diggins
Version 8.1.8 (10/10/2024) Compiled using MS Visual C++ (194033812) for 64-bit Windows
[Lines In: 408] [Lines Out: 882] [Statements: 262] [Time: 0.02 Sec's]
BCX translated [File_4.Bas] to [File_4.C] for a C Compiler
**************************************************************************
MinGW g++ is compiling [ "C:\Users\Sa76\Desktop\code_anims_bcx\File_4" ] as a 64-bit GUI application.
c:/users/sa76/desktop/portabledev/pn/bcx_bed/bat/mingw/gcc/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Sa76\AppData\Local\Temp\ccBCnbdP.o:File_4.c:(.text+0xe46): undefined reference to `__imp_wglCreateContext'

MrBcx

#5
Hi Saleh,

Load the demo into BED and in the Build dialog box select Mingw
and paste this into the Binary files to link:

C:\Mingw\x86_64-w64-mingw32\lib\libopengl32.a     
C:\Mingw\x86_64-w64-mingw32\lib\libglu32.a


It builds and runs fine for me using the Equation Solutions MINGW distro.

( Adjust MINGW path to match your system )

Saleh

Quote from: MrBcx on December 25, 2024, 09:32:56 AM
Hi Saleh,

Load the demo into BED and in the Build dialog box select Mingw
and paste this into the Binary files to link:

C:\Mingw\x86_64-w64-mingw32\lib\libopengl32.a     
C:\Mingw\x86_64-w64-mingw32\lib\libglu32.a


It builds and runs fine for me using the Equation Solutions MINGW distro.

( Adjust MINGW path to match your system )

Thank you kevin

I thought that with the pragma directive, the compiler would recognize the path to the libraries.

$PRAGMA comment(lib, "libopengl32.a")
$PRAGMA comment(lib, "libglu32.a")

But apparently I had to do it manually.

nagrom


MrBcx

Quote from: nagrom on December 26, 2024, 06:22:39 AM
This pragma doesn't apply to gcc

That's correct.

#pragma comment(lib, "...") is a MSVC-specific directive and is not supported in MinGW.

For MinGW, you need to link libraries either:

* Via the command line: -lopengl32
* In your makefile/build system
* Using the direct GCC/G++ command: g++ myfile.cpp -lopengl32


I've included the following instructions in several of my postings:


If you want to compile this with MINGW using BED, simply add these two references to Binary Files to Link box:

C:\Mingw\x86_64-w64-mingw32\lib\libopengl32.a     
C:\Mingw\x86_64-w64-mingw32\lib\libglu32.a

Be sure to change the paths to match where your MINGW is installed.


If you want to compile this with LccWin32 using BED, simply add these two references to Binary Files to Link box:

c:\lcc\lib\opengl32.lib   
c:\lcc\lib\glu32.lib

Be sure to change the paths to match where your LccWin32 is installed.

Saleh

Thanks Kevin,
It compiled without a problem.