Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Share your advanced PureBasic knowledge/code with the community.
User avatar
STARGÅTE
Addict
Addict
Posts: 2063
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by STARGÅTE »

Dear all,

here is a small gimmick regarding the Mandelbrot set and the Julia set.
With two OpenGLGadgets you can move through the Mandelbrot set with your cursor and the mouse wheel,
while the corresponding Julia set is rendered on the other side.
For this, I have written a fragment shader to iterate the color at all drawn pixels.

Image

Code: Select all

EnableExplicit


;{ OpenGL
;  https://www.purebasic.fr/english/viewtopic.php?p=576628#p576628

#GL_VERTEX_SHADER = $8B31
#GL_FRAGMENT_SHADER = $8B30

Prototype glCreateShader(type.l)
Prototype glCreateProgram()
Prototype glDeleteShader(shader.l)
Prototype glCompileShader(shader.l)
Prototype glLinkProgram(shader.l)
Prototype glUseProgram(shader.l)
Prototype glAttachShader(Program.l, shader.l)
Prototype glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) : 
Prototype glGetUniformLocation(Program.i, name.p-ascii)
Prototype glUniform1i(location.i, v0.i)
Prototype glUniform2i(location.i, v0.i, v1.i)
Prototype glUniform1f(location.i, v0.f)
Prototype glUniform1d(location.i, v0.d)
Prototype glUniform2f(location.i, v0.f, v1.f)
Prototype glUniform2d(location.i, v0.d, v1.d)
Prototype glGetShaderInfoLog(shader.i, bufSize.l, *length_l, *infoLog)


Procedure InitOpenGL()
	
	Global glCreateShader.glCreateShader             = wglGetProcAddress_("glCreateShader")
	Global glCreateProgram.glCreateProgram           = wglGetProcAddress_("glCreateProgram")
	Global glDeleteShader.glDeleteShader             = wglGetProcAddress_("glDeleteShader")
	Global glCompileShader.glCompileShader           = wglGetProcAddress_("glCompileShader")
	Global glLinkProgram.glLinkProgram               = wglGetProcAddress_("glLinkProgram")
	Global glUseProgram.glUseProgram                 = wglGetProcAddress_("glUseProgram")
	Global glAttachShader.glAttachShader             = wglGetProcAddress_("glAttachShader")
	Global glShaderSource.glShaderSource             = wglGetProcAddress_("glShaderSource")
	Global glGetUniformLocation.glGetUniformLocation = wglGetProcAddress_("glGetUniformLocation")
	Global glUniform1i.glUniform1i                   = wglGetProcAddress_("glUniform1i")
	Global glUniform2i.glUniform2i                   = wglGetProcAddress_("glUniform2i")
	Global glUniform1f.glUniform1f                   = wglGetProcAddress_("glUniform1f")
	Global glUniform1d.glUniform1d                   = wglGetProcAddress_("glUniform1d")
	Global glUniform2f.glUniform2f                   = wglGetProcAddress_("glUniform2f")
	Global glUniform2d.glUniform2d                   = wglGetProcAddress_("glUniform2d")
	Global glGetShaderInfoLog.glGetShaderInfoLog     = wglGetProcAddress_("glGetShaderInfoLog")
	
EndProcedure

;}


;{ Renderer

Structure Uniform
	Mode.i
	Iterations.i
	Scale.i
	Position.i
	Origin.i
	Center.i
	Rotation.i
EndStructure

Structure Scene
	Mode.i
	Iterations.i
	Scale.d
	Rotation.f
	PositionX.d
	PositionY.d
	OriginX.d
	OriginY.d
	CenterX.i
	CenterY.i
EndStructure

Global Uniform.Uniform
Global Mandelbrot.Scene
Global Julia.Scene


Procedure Compile(Gadget.i)
	
	Protected VertexShader.i, VertexShaderCode.s
	Protected FragmentShader.i, FragmentShaderCode.s
	Protected Program.i
	Protected *Buffer, Length.i
	Protected ErrorText.s
	
	VertexShaderCode = "#version 410" + #LF$ + 
	                   "in vec3 position;" + #LF$+
	                   "void main() {" + #LF$ + 
	                   "	gl_Position = vec4( position, 1.0 );" + #LF$ +
	                   "};"
	
	FragmentShaderCode = "#version 410" + #LF$ +
	                     "uniform int iterations;" + #LF$ +
	                     "uniform int mode;" + #LF$ +
	                     "uniform float rotation;" + #LF$ +
	                     "uniform double scale;" + #LF$ +
	                     "uniform dvec2 position;" + #LF$ +
	                     "uniform dvec2 origin;" + #LF$ +
	                     "uniform ivec2 center;" + #LF$ +
	                     "// Gradient Color" + #LF$ +
	                     "const int  gradientLength = 12;" + #LF$ +
	                     "const vec4 gradientColor[gradientLength] = vec4[gradientLength](" + #LF$ +
	                     "	vec4(0.000, 0.000, 0.000, 0.00000)," + #LF$ +
	                     "	vec4(0.125, 0.000, 0.250, 0.06250)," + #LF$ +
	                     "	vec4(0.500, 0.125, 0.250, 0.15625)," + #LF$ +
	                     "	vec4(0.875, 0.250, 0.000, 0.25000)," + #LF$ +
	                     "	vec4(1.000, 0.500, 0.000, 0.34375)," + #LF$ +
	                     "	vec4(1.000, 0.750, 0.000, 0.40625)," + #LF$ +
	                     "	vec4(1.000, 1.000, 1.000, 0.50000)," + #LF$ +
	                     "	vec4(0.625, 0.875, 0.000, 0.59375)," + #LF$ +
	                     "	vec4(0.250, 0.750, 0.000, 0.68750)," + #LF$ +
	                     "	vec4(0.000, 0.500, 0.625, 0.78125)," + #LF$ +
	                     "	vec4(0.000, 0.250, 0.500, 0.87500)," + #LF$ +
	                     "	vec4(0.000, 0.000, 0.000, 1.00000)" + #LF$ +
	                     ");" + #LF$ +
	                     "vec4 gradient( float value ) {" + #LF$ +
	                     "	" + #LF$ +
	                     "	for (int i=1; i<gradientLength; i++) {" + #LF$ +
	                     "		if (value < gradientColor[i].a)" + #LF$ +
	                     "			return vec4( mix( gradientColor[i-1].rgb, gradientColor[i].rgb, (value-gradientColor[i-1].a)/(gradientColor[i].a-gradientColor[i-1].a) ), 1.0); " + #LF$ +
	                     "	}" + #LF$ +
	                     "	" + #LF$ +
	                     "}" + #LF$ +
	                     "// Mandelbrot & Julia" + #LF$ +
	                     "dvec2 rotate( vec2 position, float angle ) {" + #LF$ +
	                     "	return dvec2(position.x*cos(angle)-position.y*sin(angle), position.x*sin(angle)+position.y*cos(angle));" + #LF$ +
	                     "};" + #LF$ +
	                     "void main( void ) {" + #LF$ +
	                     "	" + #LF$ +
	                     "	float x;" + #LF$ +
	                     "	dvec2 c;" + #LF$ +
	                     "	dvec2 z;" + #LF$ +
	                     "	" + #LF$ +
	                     "	if (mode == 0) {" + #LF$ +
	                     "		c = rotate(vec2(gl_FragCoord.x-center.x, gl_FragCoord.y-center.y), rotation) / (center.y*scale) + position;" + #LF$ +
	                     "		z = dvec2(0.0, 0.0);" + #LF$ +
	                     "	}" + #LF$ +
	                     "	else {" + #LF$ +
	                     "		c = origin;" + #LF$ +
	                     "		z = rotate(vec2(gl_FragCoord.x-center.x, gl_FragCoord.y-center.y), rotation) / (center.y*scale) + position;" + #LF$ +
	                     "	}" + #LF$ +
	                     "	dvec2 s;" + #LF$ +
	                     "	for (int i = 1; i<iterations; i++) {" + #LF$ +
	                     "		s = z*z;" + #LF$ +
	                     "		if (s.x+s.y > 64) {" + #LF$ +
	                     "			x = (i - log(log(float(s.x+s.y))*0.5*1.44269502162933)*1.44269502162933);" + #LF$ +
	                     "			//x = x*0.02;" + #LF$ +
	                     "			x = log(x+1)*sqrt(x)/50;" + #LF$ +
	                     "			break;" + #LF$ +
	                     "		}" + #LF$ +
	                     "		z = dvec2(s.x-s.y+c.x, 2.0*z.x*z.y+c.y);" + #LF$ +
	                     "	}" + #LF$ +
	                     "	gl_FragColor = gradient(mod(x, 1.0));" + #LF$ +
	                     "};"
	
	SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
	
	VertexShader = glCreateShader(#GL_VERTEX_SHADER)
	*Buffer = Ascii(VertexShaderCode)
	glShaderSource(VertexShader, 1, @*Buffer, #Null)
	glCompileShader(VertexShader)
	FreeMemory(*Buffer)
	*Buffer = AllocateMemory(1024)
	glGetShaderInfoLog(VertexShader, 1024, @Length, *Buffer)
	ErrorText + PeekS(*Buffer, Length, #PB_Ascii)
	FreeMemory(*Buffer)
	
	FragmentShader = glCreateShader(#GL_FRAGMENT_SHADER)
	*Buffer = Ascii(FragmentShaderCode)
	glShaderSource(FragmentShader, 1, @*Buffer, #Null)
	glCompileShader(FragmentShader)
	FreeMemory(*Buffer)
	*Buffer = AllocateMemory(1024)
	glGetShaderInfoLog(FragmentShader, 1024, @Length, *Buffer)
	ErrorText + PeekS(*Buffer, Length, #PB_Ascii)
	FreeMemory(*Buffer)
	
	Program = glCreateProgram()
	glAttachShader(Program, VertexShader)
	glAttachShader(Program, FragmentShader)
	glLinkProgram(Program)
	glUseProgram(Program)
	
	glDeleteShader(VertexShader)
	glDeleteShader(FragmentShader)
	
	With Uniform
		\Mode       = glGetUniformLocation(Program, "mode")
		\Iterations = glGetUniformLocation(Program, "iterations")
		\Scale      = glGetUniformLocation(Program, "scale")
		\Rotation   = glGetUniformLocation(Program, "rotation")
		\Position   = glGetUniformLocation(Program, "position")
		\Origin     = glGetUniformLocation(Program, "origin")
		\Center     = glGetUniformLocation(Program, "center")
	EndWith
	
	If ErrorText
		OpenConsole()
		PrintN(ErrorText)
	EndIf
	
EndProcedure


Procedure Render(Gadget.i)
	
	Protected *Scene.Scene = GetGadgetData(Gadget)
	
	SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
	
	glUniform1i(Uniform\Mode, *Scene\Mode)
	glUniform1i(Uniform\Iterations, *Scene\Iterations)
	glUniform1d(Uniform\Scale, *Scene\Scale)
	glUniform1f(Uniform\Rotation, *Scene\Rotation)
	glUniform2d(Uniform\Position, *Scene\PositionX, *Scene\PositionY)
	glUniform2d(Uniform\Origin, *Scene\OriginX, *Scene\OriginY)
	glUniform2i(Uniform\Center, *Scene\CenterX, *Scene\CenterY)
	
 	glBegin_(#GL_QUADS)
		glVertex2f_(-1,-1) 
		glVertex2f_( 1,-1) 
		glVertex2f_( 1, 1) 
		glVertex2f_(-1, 1) 
	glEnd_()           
	
	SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
	
EndProcedure

;}


;{ Main Program

Enumeration
	#Window
	#File
	#Gadget_OpenGL_Mandelbrot
	#Gadget_OpenGL_Julia
	#Gadget_Editor
	#Gadget_Error
EndEnumeration


Procedure Callback_Size()
	
	SetGadgetAttribute(#Gadget_OpenGL_Julia, #PB_OpenGL_SetContext, #True)
	ResizeGadget(#Gadget_OpenGL_Julia, WindowWidth(#Window)/2, 0, WindowWidth(#Window)-WindowWidth(#Window)/2, WindowHeight(#Window))
	SetGadgetAttribute(#Gadget_OpenGL_Mandelbrot, #PB_OpenGL_SetContext, #True)
	ResizeGadget(#Gadget_OpenGL_Mandelbrot, 0, 0, WindowWidth(#Window)/2, WindowHeight(#Window))
	Mandelbrot\CenterX = GadgetWidth(#Gadget_OpenGL_Mandelbrot) / 2
	Mandelbrot\CenterY = GadgetHeight(#Gadget_OpenGL_Mandelbrot) / 2
	Julia\CenterX = GadgetWidth(#Gadget_OpenGL_Julia) / 2
	Julia\CenterY = GadgetHeight(#Gadget_OpenGL_Julia) / 2
	Render(#Gadget_OpenGL_Julia)
	Render(#Gadget_OpenGL_Mandelbrot)
	
EndProcedure


OpenWindow(#Window, 0, 0, 1600, 800, "Vector Canvas Gadget", #PB_Window_MaximizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
OpenGLGadget(#Gadget_OpenGL_Mandelbrot, 0, 0, WindowWidth(#Window)/2, WindowHeight(#Window))
SetGadgetData(#Gadget_OpenGL_Mandelbrot, @Mandelbrot)
OpenGLGadget(#Gadget_OpenGL_Julia, WindowWidth(#Window)/2, 0, WindowWidth(#Window)/2, WindowHeight(#Window))
SetGadgetData(#Gadget_OpenGL_Julia, @Julia)

BindEvent(#PB_Event_SizeWindow, @Callback_Size(), #Window)

With Mandelbrot
	\Mode       = 0
	\Iterations = 512
	\PositionX  = -0.7
	\PositionY  = 0.0
	\Scale      = 0.5
	\Rotation   = 0.0
	\CenterX    = GadgetWidth(#Gadget_OpenGL_Mandelbrot) / 2
	\CenterY    = GadgetHeight(#Gadget_OpenGL_Mandelbrot) / 2
EndWith

With Julia
	\Mode       = 1
	\Iterations = 512
	\PositionX  = 0.0
	\PositionY  = 0.0
	\OriginX    = Mandelbrot\PositionX
	\OriginY    = Mandelbrot\PositionY
	\Scale      = 0.5
	\Rotation   = 0.0
	\CenterX    = GadgetWidth(#Gadget_OpenGL_Julia) / 2
	\CenterY    = GadgetHeight(#Gadget_OpenGL_Julia) / 2
EndWith

InitOpenGL()
Compile(#Gadget_OpenGL_Mandelbrot)
Compile(#Gadget_OpenGL_Julia)

Define Time.i, Text.s
Define *Scene.Scene
Define OldRotation.d, OldPositionX.d, OldPositionY.d, OldMouseX.i, OldMouseY.i
Define MouseX.i, MouseY.i

Repeat
	
	Select WaitWindowEvent(1)
		
		Case #PB_Event_CloseWindow
			Break
		Case #PB_Event_Gadget
			Select EventGadget()
				Case #Gadget_OpenGL_Mandelbrot, #Gadget_OpenGL_Julia
					*Scene = GetGadgetData(EventGadget())
					MouseX = GetGadgetAttribute(EventGadget(), #PB_OpenGL_MouseX)
					MouseY = GetGadgetAttribute(EventGadget(), #PB_OpenGL_MouseY)
					Select EventType()
						Case #PB_EventType_MouseWheel
							If GetGadgetAttribute(EventGadget(), #PB_OpenGL_Modifiers) & #PB_OpenGL_Control
								*Scene\Iterations * Pow(2, GetGadgetAttribute(EventGadget(), #PB_OpenGL_WheelDelta))
							Else
								*Scene\PositionX + (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
								*Scene\PositionY - (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
								*Scene\Scale * Pow(2, GetGadgetAttribute(EventGadget(), #PB_OpenGL_WheelDelta)*0.25)
								*Scene\PositionX - (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
								*Scene\PositionY + (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
							EndIf
						Case #PB_EventType_LeftButtonDown
							OldPositionX = *Scene\PositionX  :  OldPositionY = *Scene\PositionY
							OldMouseX = MouseX               :  OldMouseY = MouseY
						Case #PB_EventType_RightButtonDown
							OldRotation = ATan2(MouseX-*Scene\CenterX, MouseY-*Scene\CenterY) - *Scene\Rotation
							OldMouseX = MouseX               :  OldMouseY = MouseY
						Case #PB_EventType_LeftDoubleClick
							*Scene\PositionX + (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
							*Scene\PositionY - (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
						Case #PB_EventType_MouseMove
							If GetGadgetAttribute(EventGadget(), #PB_OpenGL_Buttons) & #PB_OpenGL_LeftButton
								*Scene\PositionX = OldPositionX - (Cos(*Scene\Rotation)*(MouseX-OldMouseX) + Sin(*Scene\Rotation)*(MouseY-OldMouseY)) / *Scene\Scale/*Scene\CenterY
								*Scene\PositionY = OldPositionY + (-Sin(*Scene\Rotation)*(MouseX-OldMouseX) + Cos(*Scene\Rotation)*(MouseY-OldMouseY)) / *Scene\Scale/*Scene\CenterY
							ElseIf GetGadgetAttribute(EventGadget(), #PB_OpenGL_Buttons) & #PB_OpenGL_RightButton
								*Scene\Rotation  = ATan2(MouseX-*Scene\CenterX, MouseY-*Scene\CenterY) - OldRotation
							EndIf
							If EventGadget() = #Gadget_OpenGL_Mandelbrot
								Julia\OriginX = Mandelbrot\PositionX + (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / Mandelbrot\Scale/*Scene\CenterY
								Julia\OriginY = Mandelbrot\PositionY - (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / Mandelbrot\Scale/*Scene\CenterY
							EndIf
						Case #PB_EventType_MouseLeave
							If EventGadget() = #Gadget_OpenGL_Mandelbrot
								Julia\OriginX = Mandelbrot\PositionX
								Julia\OriginY = Mandelbrot\PositionY
							EndIf
					EndSelect
				Case #Gadget_OpenGL_Julia
					Select EventType()
						Case #PB_EventType_MouseWheel
							Julia\Scale * Pow(2, GetGadgetAttribute(#Gadget_OpenGL_Julia, #PB_OpenGL_WheelDelta)*0.25)
					EndSelect
			EndSelect
		Case #PB_Event_None
			Time = ElapsedMilliseconds()
			Render(#Gadget_OpenGL_Mandelbrot)
			Render(#Gadget_OpenGL_Julia)
			Text = "Position: "+StrD(Julia\OriginX,17)+" + "+StrD(Julia\OriginY,17)+"i"
			Text + "  |  Iterations: "+Str(Mandelbrot\Iterations)+" ; "+Str(Julia\Iterations)
			Text + "  |  Render time: "+Str(ElapsedMilliseconds()-Time)+" ms"
			Text + "  |  Zoom: mouse wheel; move: left mouse button; rotate: right mouse button; iteration depth: STRG + mouse wheel; center view: double left click"
			SetWindowTitle(#Window, Text)
			
	EndSelect
	
ForEver

End

;}
Edit: Added rotation with pressed right mouse button
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by mpz »

Hi Stargate,

your code is great and a good tutorial how to use OpenGL shader.

Is it possible to translate it too linux/osX too? The problem ist these line

Global glDeleteShader.glDeleteShader = wglGetProcAddress_("glDeleteShader")

i dont know how to translate it because "wglGetProcAddress_" is a windows function...

Greetings Michael
Working on - MP3D Library - PB 5.73 version ready for download
User avatar
STARGÅTE
Addict
Addict
Posts: 2063
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by STARGÅTE »

You can pick this function from the OpenGL32 library.
Can you quickly check, if this code returns two addresses (one for wglGetProcAddress and the other as an example for glCreateShader)?

Code: Select all

Enumeration
	#Window
	#Gadget
	#Library
EndEnumeration

OpenWindow(#Window, 0, 0, 800, 450, "OpenGL", #PB_Window_MaximizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
OpenGLGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window), #PB_Canvas_Keyboard)

Prototype wglGetProcAddress(name.p-ascii)

If OpenLibrary(#Library, "OpenGL32")
	Global wglGetProcAddress.wglGetProcAddress = GetFunction(#Library, "wglGetProcAddress")
	Debug wglGetProcAddress
	Debug wglGetProcAddress("glCreateShader")
	CloseLibrary(#Library)
EndIf

End
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by #NULL »

On my Ubuntu the test code fails at OpenLibrary, but it works (on my system) with "libGL.so". But it then fails because GetFunction result is 0.
For a start: https://stackoverflow.com/a/66249269

Coole Fraktale :D
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by Mijikai »

Really nice thx :)
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by mpz »

Hi stargate,

after some tests i found a solution for all os systems. i think the wglGetProcAddress is only needed for windows...

Greetings Michael

Code: Select all

;///////////////////////////////////////////////////////////////
;//
;// Project Title: OpenGL_Import_function
;// Created On: 05.11.2021
;// Updated On: 
;// Author: Michael Paulwitz
;//
;// Version - 0.00.01 - Import of OpenGl function /Rosetta Code hihi/
;// tested with PB 5.73 for WIN10 x86/x64, Ubuntu 20.04.4/X64 and macOS Catalina 10.15.5/X64 
;//
;////////////////////////////////////////////////////////////////


CompilerIf #PB_Compiler_OS = #PB_OS_MacOS

  ImportC "-framework OpenGL" ; thx mksoft
    glGetString(name.i) As "_glGetString"
    glCreateShader(type.l) As "_glCreateShader"
    wglGetProcAddress(name.i) As "_wglGetProcAddress"
  EndImport

CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux ; yes here comes Ubuntu
  
  ImportC "/usr/lib/x86_64-linux-gnu/libGL.so"
    glGetString(name.i) ; string
    glCreateShader(type.l)
    wglGetProcAddress(name.i)
  EndImport

CompilerElseIf #PB_Compiler_OS = #PB_OS_Windows
  
  Import "OpenGL32.lib"
    glGetString(type.l)
  EndImport
  
CompilerEndIf


#GL_VERTEX_SHADER = $8B31
#GL_FRAGMENT_SHADER = $8B30


OpenWindow(0, 0, 0, 800,600, "tt", #PB_Window_BorderLess|#PB_Window_Maximize )
OpenGLGadget(0, 0, 0, WindowWidth(0),WindowHeight(0))

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Prototype glCreateShader(type.l)
  Global glCreateShader.glCreateShader       = wglGetProcAddress_("glCreateShader")
CompilerEndIf

Debug PeekS(glGetString(#GL_EXTENSIONS),-1,#PB_Ascii  ) ;Fetch Extension String
VertexShader = glCreateShader(#GL_VERTEX_SHADER)
Fragmentshader = glCreateShader(#GL_FRAGMENT_SHADER)
Debug VertexShader
Debug Fragmentshader
Debug "ende"


End
  
Last edited by mpz on Sun Dec 05, 2021 11:20 pm, edited 1 time in total.
Working on - MP3D Library - PB 5.73 version ready for download
mpz
Enthusiast
Enthusiast
Posts: 494
Joined: Sat Oct 11, 2008 9:07 pm
Location: Germany, Berlin > member German forum

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by mpz »

Hello stargate,

and now the final version for:
with PB 5.73 for WIN10 x86/x64, Ubuntu 20.04.4/X64 and macOS Catalina 10.15.5/X64

i use VM Virtual Box and there are problems with the shader, it is only a simulation..

MAC Error
ERROR: 0:1 : version 410 is not supportet
ERROR: 0:5 : syntax error: syntax error
ERROR: 0:1 : version 410 is not supportet
ERROR: 0:5 : double : reserved word.
ERROR: 0:5 : double :syntax error: syntax error

linux/Ubuntu error
0:1(10): error: GLSL 4.10 is not supported. Supported versions are: 1.10, 1.20, and 1.00 ES
0:1(10): error: GLSL 4.10 is not supported. Supported versions are: 1.10, 1.20, and 1.00 ES

but i hope somebody can test it with a "correct" hardware version of mac and Ubuntu

Greetings Michael

Code: Select all

EnableExplicit


;{ OpenGL
;  https://www.purebasic.fr/english/viewtopic.php?p=576628#p576628

#GL_VERTEX_SHADER = $8B31
#GL_FRAGMENT_SHADER = $8B30

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS

  ImportC "-framework OpenGL" ; thx mksoft
    glCreateShader(type.l) As "_glCreateShader" 
    glCreateProgram() As "_glCreateProgram"
    glDeleteShader(shader.l) As "_glDeleteShader"
    glCompileShader(shader.l) As  "_glCompileShader"
    glLinkProgram(shader.l) As "_glLinkProgram" 
    glUseProgram(shader.l) As "_glUseProgram" 
    glAttachShader(Program.l, shader.l) As  "_glAttachShader"
    glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) As  "_glShaderSource"
    glGetUniformLocation(Program.i, name.p-ascii) As  "_glGetUniformLocation"
    glUniform1i(location.i, v0.i) As "_glUniform1i"
    glUniform2i(location.i, v0.i, v1.i) As  "_glUniform2i"
    glUniform1f(location.i, v0.f) As  "_glUniform1f"
    glUniform1d(location.i, v0.d) As  "_glUniform1d"
    glUniform2f(location.i, v0.f, v1.f) As  "_glUniform2f"
    glUniform2d(location.i, v0.d, v1.d) As  "_glUniform2d"
    glGetShaderInfoLog(shader.i, bufSize.l, *length_l, *infoLog) As  "_glGetShaderInfoLog"
  EndImport

CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
  
  ImportC "/usr/lib/x86_64-linux-gnu/libGL.so"
    glCreateShader(type.l)
    glCreateProgram()
    glDeleteShader(shader.l)
    glCompileShader(shader.l)
    glLinkProgram(shader.l)
    glUseProgram(shader.l)
    glAttachShader(Program.l, shader.l)
    glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) : 
    glGetUniformLocation(Program.i, name.p-ascii)
    glUniform1i(location.i, v0.i)
    glUniform2i(location.i, v0.i, v1.i)
    glUniform1f(location.i, v0.f)
    glUniform1d(location.i, v0.d)
    glUniform2f(location.i, v0.f, v1.f)
    glUniform2d(location.i, v0.d, v1.d)
    glGetShaderInfoLog(shader.i, bufSize.l, *length_l, *infoLog)
  EndImport


CompilerElseIf #PB_Compiler_OS = #PB_OS_Windows
  
Prototype glCreateShader(type.l)
Prototype glCreateProgram()
Prototype glDeleteShader(shader.l)
Prototype glCompileShader(shader.l)
Prototype glLinkProgram(shader.l)
Prototype glUseProgram(shader.l)
Prototype glAttachShader(Program.l, shader.l)
Prototype glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) : 
Prototype glGetUniformLocation(Program.i, name.p-ascii)
Prototype glUniform1i(location.i, v0.i)
Prototype glUniform2i(location.i, v0.i, v1.i)
Prototype glUniform1f(location.i, v0.f)
Prototype glUniform1d(location.i, v0.d)
Prototype glUniform2f(location.i, v0.f, v1.f)
Prototype glUniform2d(location.i, v0.d, v1.d)
Prototype glGetShaderInfoLog(shader.i, bufSize.l, *length_l, *infoLog)


CompilerEndIf

Procedure InitOpenGL()
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
	Global glCreateShader.glCreateShader             = wglGetProcAddress_("glCreateShader")
	Global glCreateProgram.glCreateProgram           = wglGetProcAddress_("glCreateProgram")
	Global glDeleteShader.glDeleteShader             = wglGetProcAddress_("glDeleteShader")
	Global glCompileShader.glCompileShader           = wglGetProcAddress_("glCompileShader")
	Global glLinkProgram.glLinkProgram               = wglGetProcAddress_("glLinkProgram")
	Global glUseProgram.glUseProgram                 = wglGetProcAddress_("glUseProgram")
	Global glAttachShader.glAttachShader             = wglGetProcAddress_("glAttachShader")
	Global glShaderSource.glShaderSource             = wglGetProcAddress_("glShaderSource")
	Global glGetUniformLocation.glGetUniformLocation = wglGetProcAddress_("glGetUniformLocation")
	Global glUniform1i.glUniform1i                   = wglGetProcAddress_("glUniform1i")
	Global glUniform2i.glUniform2i                   = wglGetProcAddress_("glUniform2i")
	Global glUniform1f.glUniform1f                   = wglGetProcAddress_("glUniform1f")
	Global glUniform1d.glUniform1d                   = wglGetProcAddress_("glUniform1d")
	Global glUniform2f.glUniform2f                   = wglGetProcAddress_("glUniform2f")
	Global glUniform2d.glUniform2d                   = wglGetProcAddress_("glUniform2d")
	Global glGetShaderInfoLog.glGetShaderInfoLog     = wglGetProcAddress_("glGetShaderInfoLog")
  CompilerEndIf
	
EndProcedure

;}


;{ Renderer

Structure Uniform
	Mode.i
	Iterations.i
	Scale.i
	Position.i
	Origin.i
	Center.i
	Rotation.i
EndStructure

Structure Scene
	Mode.i
	Iterations.i
	Scale.d
	Rotation.f
	PositionX.d
	PositionY.d
	OriginX.d
	OriginY.d
	CenterX.i
	CenterY.i
EndStructure

Global Uniform.Uniform
Global Mandelbrot.Scene
Global Julia.Scene


Procedure Compile(Gadget.i)
	
	Protected VertexShader.i, VertexShaderCode.s
	Protected FragmentShader.i, FragmentShaderCode.s
	Protected Program.i
	Protected *Buffer, Length.i
	Protected ErrorText.s
	
	VertexShaderCode = "#version 410" + #LF$ + 
	                   "in vec3 position;" + #LF$+
	                   "void main() {" + #LF$ + 
	                   "	gl_Position = vec4( position, 1.0 );" + #LF$ +
	                   "};"
	
	FragmentShaderCode = "#version 410" + #LF$ +
	                     "uniform int iterations;" + #LF$ +
	                     "uniform int mode;" + #LF$ +
	                     "uniform float rotation;" + #LF$ +
	                     "uniform double scale;" + #LF$ +
	                     "uniform dvec2 position;" + #LF$ +
	                     "uniform dvec2 origin;" + #LF$ +
	                     "uniform ivec2 center;" + #LF$ +
	                     "// Gradient Color" + #LF$ +
	                     "const int  gradientLength = 12;" + #LF$ +
	                     "const vec4 gradientColor[gradientLength] = vec4[gradientLength](" + #LF$ +
	                     "	vec4(0.000, 0.000, 0.000, 0.00000)," + #LF$ +
	                     "	vec4(0.125, 0.000, 0.250, 0.06250)," + #LF$ +
	                     "	vec4(0.500, 0.125, 0.250, 0.15625)," + #LF$ +
	                     "	vec4(0.875, 0.250, 0.000, 0.25000)," + #LF$ +
	                     "	vec4(1.000, 0.500, 0.000, 0.34375)," + #LF$ +
	                     "	vec4(1.000, 0.750, 0.000, 0.40625)," + #LF$ +
	                     "	vec4(1.000, 1.000, 1.000, 0.50000)," + #LF$ +
	                     "	vec4(0.625, 0.875, 0.000, 0.59375)," + #LF$ +
	                     "	vec4(0.250, 0.750, 0.000, 0.68750)," + #LF$ +
	                     "	vec4(0.000, 0.500, 0.625, 0.78125)," + #LF$ +
	                     "	vec4(0.000, 0.250, 0.500, 0.87500)," + #LF$ +
	                     "	vec4(0.000, 0.000, 0.000, 1.00000)" + #LF$ +
	                     ");" + #LF$ +
	                     "vec4 gradient( float value ) {" + #LF$ +
	                     "	" + #LF$ +
	                     "	for (int i=1; i<gradientLength; i++) {" + #LF$ +
	                     "		if (value < gradientColor[i].a)" + #LF$ +
	                     "			return vec4( mix( gradientColor[i-1].rgb, gradientColor[i].rgb, (value-gradientColor[i-1].a)/(gradientColor[i].a-gradientColor[i-1].a) ), 1.0); " + #LF$ +
	                     "	}" + #LF$ +
	                     "	" + #LF$ +
	                     "}" + #LF$ +
	                     "// Mandelbrot & Julia" + #LF$ +
	                     "dvec2 rotate( vec2 position, float angle ) {" + #LF$ +
	                     "	return dvec2(position.x*cos(angle)-position.y*sin(angle), position.x*sin(angle)+position.y*cos(angle));" + #LF$ +
	                     "};" + #LF$ +
	                     "void main( void ) {" + #LF$ +
	                     "	" + #LF$ +
	                     "	float x;" + #LF$ +
	                     "	dvec2 c;" + #LF$ +
	                     "	dvec2 z;" + #LF$ +
	                     "	" + #LF$ +
	                     "	if (mode == 0) {" + #LF$ +
	                     "		c = rotate(vec2(gl_FragCoord.x-center.x, gl_FragCoord.y-center.y), rotation) / (center.y*scale) + position;" + #LF$ +
	                     "		z = dvec2(0.0, 0.0);" + #LF$ +
	                     "	}" + #LF$ +
	                     "	else {" + #LF$ +
	                     "		c = origin;" + #LF$ +
	                     "		z = rotate(vec2(gl_FragCoord.x-center.x, gl_FragCoord.y-center.y), rotation) / (center.y*scale) + position;" + #LF$ +
	                     "	}" + #LF$ +
	                     "	dvec2 s;" + #LF$ +
	                     "	for (int i = 1; i<iterations; i++) {" + #LF$ +
	                     "		s = z*z;" + #LF$ +
	                     "		if (s.x+s.y > 64) {" + #LF$ +
	                     "			x = (i - log(log(float(s.x+s.y))*0.5*1.44269502162933)*1.44269502162933);" + #LF$ +
	                     "			//x = x*0.02;" + #LF$ +
	                     "			x = log(x+1)*sqrt(x)/50;" + #LF$ +
	                     "			break;" + #LF$ +
	                     "		}" + #LF$ +
	                     "		z = dvec2(s.x-s.y+c.x, 2.0*z.x*z.y+c.y);" + #LF$ +
	                     "	}" + #LF$ +
	                     "	gl_FragColor = gradient(mod(x, 1.0));" + #LF$ +
	                     "};"
	
	SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
	
	VertexShader = glCreateShader(#GL_VERTEX_SHADER)
	*Buffer = Ascii(VertexShaderCode)
	glShaderSource(VertexShader, 1, @*Buffer, #Null)
	glCompileShader(VertexShader)
	FreeMemory(*Buffer)
	*Buffer = AllocateMemory(1024)
	glGetShaderInfoLog(VertexShader, 1024, @Length, *Buffer)
	ErrorText + PeekS(*Buffer, Length, #PB_Ascii)
	FreeMemory(*Buffer)
	
	FragmentShader = glCreateShader(#GL_FRAGMENT_SHADER)
	*Buffer = Ascii(FragmentShaderCode)
	glShaderSource(FragmentShader, 1, @*Buffer, #Null)
	glCompileShader(FragmentShader)
	FreeMemory(*Buffer)
	*Buffer = AllocateMemory(1024)
	glGetShaderInfoLog(FragmentShader, 1024, @Length, *Buffer)
	ErrorText + PeekS(*Buffer, Length, #PB_Ascii)
	FreeMemory(*Buffer)
	
	Program = glCreateProgram()
	glAttachShader(Program, VertexShader)
	glAttachShader(Program, FragmentShader)
	glLinkProgram(Program)
	glUseProgram(Program)
	
	glDeleteShader(VertexShader)
	glDeleteShader(FragmentShader)
	
	With Uniform
		\Mode       = glGetUniformLocation(Program, "mode")
		\Iterations = glGetUniformLocation(Program, "iterations")
		\Scale      = glGetUniformLocation(Program, "scale")
		\Rotation   = glGetUniformLocation(Program, "rotation")
		\Position   = glGetUniformLocation(Program, "position")
		\Origin     = glGetUniformLocation(Program, "origin")
		\Center     = glGetUniformLocation(Program, "center")
	EndWith
	
	If ErrorText
	  Debug ErrorText
		;OpenConsole()
		;PrintN(ErrorText)
	EndIf
	
EndProcedure


Procedure Render(Gadget.i)
	
	Protected *Scene.Scene = GetGadgetData(Gadget)
	
	SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
	
	glUniform1i(Uniform\Mode, *Scene\Mode)
	glUniform1i(Uniform\Iterations, *Scene\Iterations)
	glUniform1d(Uniform\Scale, *Scene\Scale)
	glUniform1f(Uniform\Rotation, *Scene\Rotation)
	glUniform2d(Uniform\Position, *Scene\PositionX, *Scene\PositionY)
	glUniform2d(Uniform\Origin, *Scene\OriginX, *Scene\OriginY)
	glUniform2i(Uniform\Center, *Scene\CenterX, *Scene\CenterY)
	
 	glBegin_(#GL_QUADS)
		glVertex2f_(-1,-1) 
		glVertex2f_( 1,-1) 
		glVertex2f_( 1, 1) 
		glVertex2f_(-1, 1) 
	glEnd_()           
	
	SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
	
EndProcedure

;}


;{ Main Program

Enumeration
	#Window
	#File
	#Gadget_OpenGL_Mandelbrot
	#Gadget_OpenGL_Julia
	#Gadget_Editor
	#Gadget_Error
EndEnumeration


Procedure Callback_Size()
	
	SetGadgetAttribute(#Gadget_OpenGL_Julia, #PB_OpenGL_SetContext, #True)
	ResizeGadget(#Gadget_OpenGL_Julia, WindowWidth(#Window)/2, 0, WindowWidth(#Window)-WindowWidth(#Window)/2, WindowHeight(#Window))
	SetGadgetAttribute(#Gadget_OpenGL_Mandelbrot, #PB_OpenGL_SetContext, #True)
	ResizeGadget(#Gadget_OpenGL_Mandelbrot, 0, 0, WindowWidth(#Window)/2, WindowHeight(#Window))
	Mandelbrot\CenterX = GadgetWidth(#Gadget_OpenGL_Mandelbrot) / 2
	Mandelbrot\CenterY = GadgetHeight(#Gadget_OpenGL_Mandelbrot) / 2
	Julia\CenterX = GadgetWidth(#Gadget_OpenGL_Julia) / 2
	Julia\CenterY = GadgetHeight(#Gadget_OpenGL_Julia) / 2
	Render(#Gadget_OpenGL_Julia)
	Render(#Gadget_OpenGL_Mandelbrot)
	
EndProcedure


OpenWindow(#Window, 0, 0, 800, 600, "Vector Canvas Gadget", #PB_Window_MaximizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
;OpenWindow(#Window, 0, 0, 1600, 800, "Vector Canvas Gadget", #PB_Window_MaximizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
OpenGLGadget(#Gadget_OpenGL_Mandelbrot, 0, 0, WindowWidth(#Window)/2, WindowHeight(#Window))
SetGadgetData(#Gadget_OpenGL_Mandelbrot, @Mandelbrot)
OpenGLGadget(#Gadget_OpenGL_Julia, WindowWidth(#Window)/2, 0, WindowWidth(#Window)/2, WindowHeight(#Window))
SetGadgetData(#Gadget_OpenGL_Julia, @Julia)

BindEvent(#PB_Event_SizeWindow, @Callback_Size(), #Window)

With Mandelbrot
	\Mode       = 0
	\Iterations = 512
	\PositionX  = -0.7
	\PositionY  = 0.0
	\Scale      = 0.5
	\Rotation   = 0.0
	\CenterX    = GadgetWidth(#Gadget_OpenGL_Mandelbrot) / 2
	\CenterY    = GadgetHeight(#Gadget_OpenGL_Mandelbrot) / 2
EndWith

With Julia
	\Mode       = 1
	\Iterations = 512
	\PositionX  = 0.0
	\PositionY  = 0.0
	\OriginX    = Mandelbrot\PositionX
	\OriginY    = Mandelbrot\PositionY
	\Scale      = 0.5
	\Rotation   = 0.0
	\CenterX    = GadgetWidth(#Gadget_OpenGL_Julia) / 2
	\CenterY    = GadgetHeight(#Gadget_OpenGL_Julia) / 2
EndWith

InitOpenGL()
Compile(#Gadget_OpenGL_Mandelbrot)
Compile(#Gadget_OpenGL_Julia)

Define Time.i, Text.s
Define *Scene.Scene
Define OldRotation.d, OldPositionX.d, OldPositionY.d, OldMouseX.i, OldMouseY.i
Define MouseX.i, MouseY.i

Repeat
	
	Select WaitWindowEvent(1)
		
		Case #PB_Event_CloseWindow
			Break
		Case #PB_Event_Gadget
			Select EventGadget()
				Case #Gadget_OpenGL_Mandelbrot, #Gadget_OpenGL_Julia
					*Scene = GetGadgetData(EventGadget())
					MouseX = GetGadgetAttribute(EventGadget(), #PB_OpenGL_MouseX)
					MouseY = GetGadgetAttribute(EventGadget(), #PB_OpenGL_MouseY)
					Select EventType()
						Case #PB_EventType_MouseWheel
							If GetGadgetAttribute(EventGadget(), #PB_OpenGL_Modifiers) & #PB_OpenGL_Control
								*Scene\Iterations * Pow(2, GetGadgetAttribute(EventGadget(), #PB_OpenGL_WheelDelta))
							Else
								*Scene\PositionX + (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
								*Scene\PositionY - (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
								*Scene\Scale * Pow(2, GetGadgetAttribute(EventGadget(), #PB_OpenGL_WheelDelta)*0.25)
								*Scene\PositionX - (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
								*Scene\PositionY + (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
							EndIf
						Case #PB_EventType_LeftButtonDown
							OldPositionX = *Scene\PositionX  :  OldPositionY = *Scene\PositionY
							OldMouseX = MouseX               :  OldMouseY = MouseY
						Case #PB_EventType_RightButtonDown
							OldRotation = ATan2(MouseX-*Scene\CenterX, MouseY-*Scene\CenterY) - *Scene\Rotation
							OldMouseX = MouseX               :  OldMouseY = MouseY
						Case #PB_EventType_LeftDoubleClick
							*Scene\PositionX + (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
							*Scene\PositionY - (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / *Scene\Scale/*Scene\CenterY
						Case #PB_EventType_MouseMove
							If GetGadgetAttribute(EventGadget(), #PB_OpenGL_Buttons) & #PB_OpenGL_LeftButton
								*Scene\PositionX = OldPositionX - (Cos(*Scene\Rotation)*(MouseX-OldMouseX) + Sin(*Scene\Rotation)*(MouseY-OldMouseY)) / *Scene\Scale/*Scene\CenterY
								*Scene\PositionY = OldPositionY + (-Sin(*Scene\Rotation)*(MouseX-OldMouseX) + Cos(*Scene\Rotation)*(MouseY-OldMouseY)) / *Scene\Scale/*Scene\CenterY
							ElseIf GetGadgetAttribute(EventGadget(), #PB_OpenGL_Buttons) & #PB_OpenGL_RightButton
								*Scene\Rotation  = ATan2(MouseX-*Scene\CenterX, MouseY-*Scene\CenterY) - OldRotation
							EndIf
							If EventGadget() = #Gadget_OpenGL_Mandelbrot
								Julia\OriginX = Mandelbrot\PositionX + (Cos(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Sin(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / Mandelbrot\Scale/*Scene\CenterY
								Julia\OriginY = Mandelbrot\PositionY - (-Sin(*Scene\Rotation)*(MouseX-*Scene\CenterX) + Cos(*Scene\Rotation)*(MouseY-*Scene\CenterY)) / Mandelbrot\Scale/*Scene\CenterY
							EndIf
						Case #PB_EventType_MouseLeave
							If EventGadget() = #Gadget_OpenGL_Mandelbrot
								Julia\OriginX = Mandelbrot\PositionX
								Julia\OriginY = Mandelbrot\PositionY
							EndIf
					EndSelect
				Case #Gadget_OpenGL_Julia
					Select EventType()
						Case #PB_EventType_MouseWheel
							Julia\Scale * Pow(2, GetGadgetAttribute(#Gadget_OpenGL_Julia, #PB_OpenGL_WheelDelta)*0.25)
					EndSelect
			EndSelect
		Case #PB_Event_None
			Time = ElapsedMilliseconds()
			Render(#Gadget_OpenGL_Mandelbrot)
			Render(#Gadget_OpenGL_Julia)
			Text = "Position: "+StrD(Julia\OriginX,17)+" + "+StrD(Julia\OriginY,17)+"i"
			Text + "  |  Iterations: "+Str(Mandelbrot\Iterations)+" ; "+Str(Julia\Iterations)
			Text + "  |  Render time: "+Str(ElapsedMilliseconds()-Time)+" ms"
			Text + "  |  Zoom: mouse wheel; move: left mouse button; rotate: right mouse button; iteration depth: STRG + mouse wheel; center view: double left click"
			SetWindowTitle(#Window, Text)
			
	EndSelect
	
ForEver

End

;}

Here the actualiszed code of the graficcard check program

Code: Select all

; German forum: http://www.purebasic.fr/german/viewtopic.php?t=45&postdays=0&postorder=asc&start=10
; Author: DarkDragon (updated for PB 4.00 by Andre)
; Date: 10. September 2004
; OS: Windows
; Demo: No
; actulized mpz nov 21, working on PB 5.73 win/linux and mac possible

; Ermitteln der OpenGL-Version

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS

  ImportC "-framework OpenGL" ; thx mksoft
    glGetString(name.i) As "_glGetString"
  EndImport

CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
  
  ImportC "/usr/lib/x86_64-linux-gnu/libGL.so"
    glGetString(name.i) ; string
  EndImport

CompilerElseIf #PB_Compiler_OS = #PB_OS_Windows
  
  Import "OpenGL32.lib"
    glGetString(type.l)
  EndImport
  
CompilerEndIf


#WindowWidth = 1
#WindowHeight = 1
#WindowFlags = #PB_Window_Invisible
#GL_SHADING_LANGUAGE_VERSION = $8B8C 
Global hWnd.l, Event

If OpenWindow(0, 0, 0, #WindowWidth, #WindowHeight, "", #WindowFlags)
  OpenGLGadget(0, 1, 1, WindowWidth(0) , WindowHeight(0))
  ;MessageRequester("OpenGL-Version", PeekS(glGetString_(#GL_VERSION),-1,#PB_Ascii))
  Debug "----------------"
  Debug PeekS(glGetString(#GL_VENDOR),-1,#PB_Ascii)
  Debug PeekS(glGetString(#GL_RENDERER),-1,#PB_Ascii)
  Debug PeekS(glGetString(#GL_VERSION),-1,#PB_Ascii)
  Debug PeekS(glGetString(#GL_SHADING_LANGUAGE_VERSION),-1,#PB_Ascii)
  Debug "----------------"
  Debug PeekS(glGetString(#GL_EXTENSIONS),-1,#PB_Ascii)
EndIf
Last edited by mpz on Sun Dec 05, 2021 11:21 pm, edited 1 time in total.
Working on - MP3D Library - PB 5.73 version ready for download
User avatar
mk-soft
Always Here
Always Here
Posts: 5313
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by mk-soft »

For macOS

Code: Select all

ImportC "-framework OpenGL"
but not support version 4.10
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by luis »

Nice idea, pretty cool :)
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Caronte3D
Addict
Addict
Posts: 1014
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by Caronte3D »

I only get a black screen :?
User avatar
STARGÅTE
Addict
Addict
Posts: 2063
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by STARGÅTE »

mpz wrote: Sun Dec 05, 2021 9:33 pm Hello stargate,

and now the final version for:
with PB 5.73 for WIN10 x86/x64, Ubuntu 20.04.4/X64 and macOS Catalina 10.15.5/X64
Thanks for the translation to Linux and Mac. However, I haven't checked it yet.
Caronte3D wrote: Mon Dec 06, 2021 12:33 pm I only get a black screen
The code requires at least OpenGL 4.1 with OpenGL Shading Language 4.10.
On my system, I have a AMD Radeon RX 5600 XT with OpenGL 4.6.

Did you receive an error text in a console?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
BarryG
Addict
Addict
Posts: 3268
Joined: Thu Apr 18, 2019 8:17 am

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by BarryG »

Nice code, STARGÅTE. Fast, too. I thought I could keep zooming in forever but it does come to an eventual end.
User avatar
Caronte3D
Addict
Addict
Posts: 1014
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by Caronte3D »

STARGÅTE wrote: Mon Dec 06, 2021 12:51 pm The code requires at least OpenGL 4.1 with OpenGL Shading Language 4.10.
On my system, I have a AMD Radeon RX 5600 XT with OpenGL 4.6.

Did you receive an error text in a console?
My laptop have 4.6 version of OpenGL & the same for Shading language.

The PB program runs (I can see the numbers on the window title) but the screen is back

I will test it the next weekend on my desktop PC...
User avatar
mk-soft
Always Here
Always Here
Posts: 5313
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by mk-soft »

Same black screen

Windows 10 Ultimate
Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
NicTheQuick
Addict
Addict
Posts: 1218
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Mandelbrot set and Julia set using the OpenGLGadget and a fragment shader

Post by NicTheQuick »

Works flawlessly an very snappy on Linux. very nice!

Well, 16384 iteration steps gave me a rendering time of about 1000 ms which in turn affects my whole system. Typical bad nvidia drivers on Linux I guess. :lol:
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Post Reply