mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-02-24 08:47:02 +00:00
Added Inertia's Julia Fractal example.
This commit is contained in:
parent
57b097f7d0
commit
90cd690843
BIN
Source/Examples/Data/JuliaColorTable.bmp
Normal file
BIN
Source/Examples/Data/JuliaColorTable.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 B |
66
Source/Examples/Data/Shaders/JuliaSet_SM2_FS.glsl
Normal file
66
Source/Examples/Data/Shaders/JuliaSet_SM2_FS.glsl
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#version 110
|
||||||
|
// www.OpenTK.net GLSL Julia Set (c) 2008 Christoph Brandtner
|
||||||
|
|
||||||
|
// uniforms from OpenGL
|
||||||
|
uniform sampler1D COLORTABLE;
|
||||||
|
uniform float CETX;
|
||||||
|
uniform float CETY;
|
||||||
|
uniform float SCALINGX;
|
||||||
|
uniform float SCALINGY;
|
||||||
|
uniform float OFFSETX;
|
||||||
|
uniform float OFFSETY;
|
||||||
|
|
||||||
|
// GLSL internal variables.
|
||||||
|
const int MAXIterations = 16; // must be greater than zero, 16 is a good blend between detail and speed
|
||||||
|
float XPos;
|
||||||
|
float YPos;
|
||||||
|
float XQuad;
|
||||||
|
float YQuad; // half precision floating point could be used on those 4 floats for speed, but will throw a warning.
|
||||||
|
int TableIndex;
|
||||||
|
int LoopCount;
|
||||||
|
|
||||||
|
// this function reduces duplicate code
|
||||||
|
void Iterate(void)
|
||||||
|
{
|
||||||
|
YPos = 2.0 * XPos * YPos + CETY;
|
||||||
|
XPos = XQuad - YQuad + CETX;
|
||||||
|
XQuad = pow(XPos, 2.0);
|
||||||
|
YQuad = pow(YPos, 2.0);
|
||||||
|
TableIndex++;
|
||||||
|
if ( (XQuad + YQuad) > 4.0 ) LoopCount = MAXIterations; // skip further iterations for this Pixel
|
||||||
|
LoopCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shader entry point, this is executed per Pixel
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
XPos = gl_FragCoord.x / SCALINGX - OFFSETX;
|
||||||
|
YPos = gl_FragCoord.y / SCALINGY - OFFSETY;
|
||||||
|
XQuad = pow(XPos, 2.0);
|
||||||
|
YQuad = pow(YPos, 2.0);
|
||||||
|
TableIndex = -1;
|
||||||
|
LoopCount = 0;
|
||||||
|
// the loop is unrolled for SM 2.0 compatibility
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate(); // TableIndex==0
|
||||||
|
if ( LoopCount > 1 ) discard; // attempt to early-out, will affect ~1/3 of all Pixels
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate();
|
||||||
|
if ( LoopCount <= MAXIterations ) Iterate(); // TableIndex==16
|
||||||
|
float FinalTableIndex = float( TableIndex ) / float( MAXIterations );
|
||||||
|
|
||||||
|
gl_FragColor = texture1D( COLORTABLE, FinalTableIndex ); // lookup texture for output
|
||||||
|
// gl_FragColor.rgb = vec3(FinalTableIndex); // Debug: output greyscale
|
||||||
|
}
|
41
Source/Examples/Data/Shaders/JuliaSet_SM3_FS.glsl
Normal file
41
Source/Examples/Data/Shaders/JuliaSet_SM3_FS.glsl
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#version 120
|
||||||
|
// www.OpenTK.net GLSL Julia Set (c) 2008 Christoph Brandtner
|
||||||
|
|
||||||
|
uniform sampler1D COLORTABLE;
|
||||||
|
uniform float CETX;
|
||||||
|
uniform float CETY;
|
||||||
|
uniform float SCALINGX;
|
||||||
|
uniform float SCALINGY;
|
||||||
|
uniform float OFFSETX;
|
||||||
|
uniform float OFFSETY;
|
||||||
|
|
||||||
|
const int MAXIterations = 32; // *must* be > 0
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
float XPos = gl_FragCoord.x / SCALINGX - OFFSETX;
|
||||||
|
float YPos = gl_FragCoord.y / SCALINGY - OFFSETY;
|
||||||
|
float XQuad = pow( XPos, 2.0 );
|
||||||
|
float YQuad = pow( YPos, 2.0 );
|
||||||
|
int TableIndex = -1;
|
||||||
|
int LoopCount = 0;
|
||||||
|
while ( LoopCount <= MAXIterations )
|
||||||
|
{
|
||||||
|
YPos = 2.0 * XPos * YPos + CETY;
|
||||||
|
XPos = XQuad - YQuad + CETX;
|
||||||
|
XQuad = pow( XPos, 2.0 );
|
||||||
|
YQuad = pow( YPos, 2.0 );
|
||||||
|
TableIndex++;
|
||||||
|
if ( (XQuad + YQuad) > 4.0 )
|
||||||
|
{
|
||||||
|
if (TableIndex == 0)
|
||||||
|
discard;
|
||||||
|
LoopCount = MAXIterations;
|
||||||
|
}
|
||||||
|
LoopCount++;
|
||||||
|
}
|
||||||
|
float FinalTableIndex = float( TableIndex ) / float( MAXIterations );
|
||||||
|
|
||||||
|
gl_FragColor = texture1D( COLORTABLE, FinalTableIndex ); // lookup texture for output
|
||||||
|
// gl_FragColor.rgb = vec3( FinalTableIndex ); // Debug: output greyscale
|
||||||
|
}
|
4
Source/Examples/Data/Shaders/JuliaSet_VS.glsl
Normal file
4
Source/Examples/Data/Shaders/JuliaSet_VS.glsl
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_Position = ftransform(); // gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||||
|
}
|
277
Source/Examples/OpenGL/T11_Julia_Set.cs
Normal file
277
Source/Examples/OpenGL/T11_Julia_Set.cs
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
#region --- License ---
|
||||||
|
/* Copyright (c) 2008 Christoph Brandtner
|
||||||
|
* See license.txt for license info
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace Examples.Tutorial
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Demonstrates how to render an animated Julia Set in real-time. Quality is sacrificed for speed.
|
||||||
|
/// Info about the fractal: http://en.wikipedia.org/wiki/Julia_set
|
||||||
|
/// One more major optimization could be applied (exploit the symmetry of the image with RTT), but
|
||||||
|
/// that would make the program alot more complicated to follow. You can do this as an exercise.
|
||||||
|
/// </summary>
|
||||||
|
[Example("GLSL Animated Julia Set", ExampleCategory.GLSL)]
|
||||||
|
public class T11_Julia_Set : GameWindow
|
||||||
|
{
|
||||||
|
public T11_Julia_Set()
|
||||||
|
: base(512, 512)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#region private Fields
|
||||||
|
// GLSL Objects
|
||||||
|
int VertexShaderObject, FragmentShaderObject, ProgramObject;
|
||||||
|
int TextureObject;
|
||||||
|
|
||||||
|
// Julia Variables for animation
|
||||||
|
float AnimOffsetX = 0.213f; // using non-zero as starting point to make it more interesting
|
||||||
|
float AnimOffsetY = 0.63f;
|
||||||
|
|
||||||
|
const double AnimSpeedX = 0.65; // anim speed scaling is solely used to make the anim more interesting
|
||||||
|
const double AnimSpeedY = 1.05;
|
||||||
|
const double AnimCosinusPercent = 0.85f; // scales the cosinus down to 85% to avoid the (boring) borders
|
||||||
|
|
||||||
|
float UniformScaleFactorX; // fractal horizontal scaling is only affected by window resize
|
||||||
|
float UniformScaleFactorY; // fractal vertical scaling is only affected by window resize
|
||||||
|
float UniformOffsetX = 1.8f; // fractal horizontal offset
|
||||||
|
float UniformOffsetY = 1.8f; // fractal vertical offset
|
||||||
|
#endregion private Fields
|
||||||
|
|
||||||
|
#region OnLoad
|
||||||
|
/// <summary>
|
||||||
|
/// Setup OpenGL and load resources here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Not used.</param>
|
||||||
|
public override void OnLoad(EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Check for necessary capabilities:
|
||||||
|
if (!GL.SupportsExtension("VERSION_2_0"))
|
||||||
|
{
|
||||||
|
MessageBox.Show("You need at least OpenGL 2.0 to run this example. Aborting.",
|
||||||
|
"GLSL not supported", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||||
|
this.Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.VSync = VSyncMode.Off;
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.Dither);
|
||||||
|
GL.ClearColor(0.2f, 0f, 0.4f, 0f);
|
||||||
|
|
||||||
|
// declare some variables for tracking which shader did compile, and which texture to use
|
||||||
|
string[] ShaderFilenames = new string[2];
|
||||||
|
ShaderFilenames[0] = "Data/Shaders/JuliaSet_SM3_FS.glsl";
|
||||||
|
ShaderFilenames[1] = "Data/Shaders/JuliaSet_SM2_FS.glsl";
|
||||||
|
|
||||||
|
byte CurrentOption = 0;
|
||||||
|
string LogInfo;
|
||||||
|
|
||||||
|
#region Shaders
|
||||||
|
// Load&Compile Vertex Shader
|
||||||
|
using (StreamReader sr = new StreamReader("Data/Shaders/JuliaSet_VS.glsl"))
|
||||||
|
{
|
||||||
|
VertexShaderObject = GL.CreateShader(ShaderType.VertexShader);
|
||||||
|
GL.ShaderSource(VertexShaderObject, sr.ReadToEnd());
|
||||||
|
GL.CompileShader(VertexShaderObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.GetShaderInfoLog(VertexShaderObject, out LogInfo);
|
||||||
|
if (LogInfo.Length > 0 && !LogInfo.Contains("hardware"))
|
||||||
|
Trace.WriteLine("Vertex Shader Log:\n" + LogInfo);
|
||||||
|
else
|
||||||
|
Trace.WriteLine("Vertex Shader compiled without complaint.");
|
||||||
|
|
||||||
|
// Load&Compile Fragment Shader
|
||||||
|
|
||||||
|
|
||||||
|
FragmentShaderObject = GL.CreateShader(ShaderType.FragmentShader);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
using (StreamReader sr = new StreamReader(ShaderFilenames[CurrentOption]))
|
||||||
|
{
|
||||||
|
|
||||||
|
GL.ShaderSource(FragmentShaderObject, sr.ReadToEnd());
|
||||||
|
GL.CompileShader(FragmentShaderObject);
|
||||||
|
}
|
||||||
|
GL.GetShaderInfoLog(FragmentShaderObject, out LogInfo);
|
||||||
|
|
||||||
|
if (LogInfo.Length > 0 && !LogInfo.Contains("hardware"))
|
||||||
|
Trace.WriteLine("Compiling " + ShaderFilenames[CurrentOption] + " failed!\nLog:\n" + LogInfo);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.WriteLine("Fragment Shader compiled without complaint.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++CurrentOption > 1)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Neither SM2 nor SM3 Fragment Shader compiled successfully. Aborting.",
|
||||||
|
"Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
this.Exit();
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
// Link the Shaders to a usable Program
|
||||||
|
ProgramObject = GL.CreateProgram();
|
||||||
|
GL.AttachShader(ProgramObject, VertexShaderObject);
|
||||||
|
GL.AttachShader(ProgramObject, FragmentShaderObject);
|
||||||
|
GL.LinkProgram(ProgramObject);
|
||||||
|
|
||||||
|
// make current
|
||||||
|
GL.UseProgram(ProgramObject);
|
||||||
|
|
||||||
|
// Flag ShaderObjects for delete when app exits
|
||||||
|
GL.DeleteShader(VertexShaderObject);
|
||||||
|
GL.DeleteShader(FragmentShaderObject);
|
||||||
|
#endregion Shaders
|
||||||
|
|
||||||
|
#region Textures
|
||||||
|
// Load&Bind the 1D texture for color lookups
|
||||||
|
GL.ActiveTexture(TextureUnit.Texture0); // select TMU0
|
||||||
|
GL.GenTextures(1, out TextureObject);
|
||||||
|
GL.TexParameter(TextureTarget.Texture1D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||||
|
GL.TexParameter(TextureTarget.Texture1D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||||
|
GL.TexParameter(TextureTarget.Texture1D, TextureParameterName.TextureWrapS, (int)(TextureWrapMode)All.ClampToEdge);
|
||||||
|
|
||||||
|
Bitmap bitmap = new Bitmap("Data/JuliaColorTable.bmp");
|
||||||
|
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
||||||
|
GL.TexImage1D(TextureTarget.Texture1D, 0, PixelInternalFormat.Rgb8, data.Width, 0, OpenTK.Graphics.PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
|
||||||
|
bitmap.UnlockBits(data);
|
||||||
|
#endregion Textures
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnUnLoad
|
||||||
|
|
||||||
|
public override void OnUnload(EventArgs e)
|
||||||
|
{
|
||||||
|
GL.DeleteTextures(1, ref TextureObject);
|
||||||
|
GL.DeleteProgram(ProgramObject); // implies deleting the previously flagged ShaderObjects
|
||||||
|
|
||||||
|
base.OnUnload(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnResize
|
||||||
|
/// <summary>
|
||||||
|
/// Respond to resize events here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Contains information on the new GameWindow size.</param>
|
||||||
|
/// <remarks>There is no need to call the base implementation.</remarks>
|
||||||
|
protected override void OnResize(OpenTK.Platform.ResizeEventArgs e)
|
||||||
|
{
|
||||||
|
// magic numbers so the fractal almost fits inside the window.
|
||||||
|
// If changing this, also change the -1.6f offset in the fragment shader accordingly.
|
||||||
|
UniformScaleFactorX = Width / (UniformOffsetX * 2f);
|
||||||
|
UniformScaleFactorY = Height / (UniformOffsetY * 2f);
|
||||||
|
|
||||||
|
GL.Viewport(0, 0, Width, Height);
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Projection);
|
||||||
|
GL.LoadIdentity();
|
||||||
|
GL.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 0.1); // 2D setup
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
|
GL.LoadIdentity();
|
||||||
|
|
||||||
|
base.OnResize(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnUpdateFrame
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add your game logic here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Contains timing information.</param>
|
||||||
|
/// <remarks>There is no need to call the base implementation.</remarks>
|
||||||
|
public override void OnUpdateFrame(UpdateFrameEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnUpdateFrame(e);
|
||||||
|
|
||||||
|
if (Keyboard[OpenTK.Input.Key.Escape])
|
||||||
|
{
|
||||||
|
this.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnRenderFrame
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add your game rendering code here.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Contains timing information.</param>
|
||||||
|
/// <remarks>There is no need to call the base implementation.</remarks>
|
||||||
|
public override void OnRenderFrame(RenderFrameEventArgs e)
|
||||||
|
{
|
||||||
|
this.Title = "FPS: " + 1 / e.Time;
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
|
// advance the animation by elapsed time, scaling is solely used to make the anim more interesting
|
||||||
|
AnimOffsetX += (float)(e.Time * AnimSpeedX);
|
||||||
|
AnimOffsetY += (float)(e.Time * AnimSpeedY);
|
||||||
|
|
||||||
|
// pass uniforms into the fragment shader
|
||||||
|
// first the texture
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "COLORTABLE"), TextureObject);
|
||||||
|
// the rest are floats
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "CETX"), (float)(Math.Cos(AnimOffsetX) * AnimCosinusPercent));
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "CETY"), (float)(Math.Cos(AnimOffsetY) * AnimCosinusPercent));
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "SCALINGX"), UniformScaleFactorX);
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "SCALINGY"), UniformScaleFactorY);
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "OFFSETX"), UniformOffsetX);
|
||||||
|
GL.Uniform1(GL.GetUniformLocation(ProgramObject, "OFFSETY"), UniformOffsetY);
|
||||||
|
|
||||||
|
// Fullscreen quad. Using immediate mode, since this app is fragment shader limited anyways.
|
||||||
|
GL.Begin(BeginMode.Quads);
|
||||||
|
{
|
||||||
|
GL.Vertex3(-1.0f, -1.0f, 0f);
|
||||||
|
GL.Vertex3(1.0f, -1.0f, 0f);
|
||||||
|
GL.Vertex3(1.0f, 1.0f, 0f);
|
||||||
|
GL.Vertex3(-1.0f, 1.0f, 0f);
|
||||||
|
}
|
||||||
|
GL.End();
|
||||||
|
|
||||||
|
this.SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public static void Main()
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Entry point of this example.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
public static void Main()
|
||||||
|
{
|
||||||
|
|
||||||
|
using (T11_Julia_Set example = new T11_Julia_Set())
|
||||||
|
{
|
||||||
|
// Get the title and category of this example using reflection.
|
||||||
|
ExampleAttribute info = ((ExampleAttribute)example.GetType().GetCustomAttributes(false)[0]);
|
||||||
|
example.Title = String.Format("OpenTK | {0} {1}: {2}", info.Category, info.Difficulty, info.Title);
|
||||||
|
example.Run(30.0, 60.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue