Support complex powers of z
This commit is contained in:
parent
2037786319
commit
9c903179cf
19
config.h
19
config.h
@ -6,13 +6,13 @@
|
|||||||
#define MAXITER 1000
|
#define MAXITER 1000
|
||||||
|
|
||||||
// Pretty Julia set zoom
|
// Pretty Julia set zoom
|
||||||
#define SS 9
|
//#define SS 9
|
||||||
#define JULIA
|
//#define JULIA
|
||||||
#define JULIA_C_RE 0.285
|
//#define JULIA_C_RE 0.285
|
||||||
#define JULIA_C_IM 0.010
|
//#define JULIA_C_IM 0.010
|
||||||
#define CENTRE_RE -0.47353731
|
//#define CENTRE_RE -0.47353731
|
||||||
#define CENTRE_IM -0.18894516
|
//#define CENTRE_IM -0.18894516
|
||||||
#define ZOOMRATE 0.01
|
//#define ZOOMRATE 0.01
|
||||||
|
|
||||||
// Cool zoomy swirly animated Julia set
|
// Cool zoomy swirly animated Julia set
|
||||||
//#define SS 9
|
//#define SS 9
|
||||||
@ -43,3 +43,8 @@
|
|||||||
//#define JULIA_DTHETA -0.00002
|
//#define JULIA_DTHETA -0.00002
|
||||||
//#define POWRATE 0.0001
|
//#define POWRATE 0.0001
|
||||||
//#define ZOOMRATE 0.0003
|
//#define ZOOMRATE 0.0003
|
||||||
|
|
||||||
|
// Complex power Mandelbrot
|
||||||
|
#define SS 4
|
||||||
|
#define CPOW_DTHETA 0.01
|
||||||
|
#define MAXMAG 100.0
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
|
|
||||||
#define NCOLS 8
|
#define NCOLS 8
|
||||||
|
|
||||||
|
#ifndef CPOW_DTHETA
|
||||||
|
#define MAXMAG 2.0
|
||||||
|
#endif
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_colour;
|
layout(location = 0) out vec4 out_colour;
|
||||||
|
|
||||||
layout(push_constant) uniform Constants {
|
layout(push_constant) uniform Constants {
|
||||||
@ -17,10 +21,13 @@ layout(push_constant) uniform Constants {
|
|||||||
vec2 julia;
|
vec2 julia;
|
||||||
#endif
|
#endif
|
||||||
vec2 centre;
|
vec2 centre;
|
||||||
float scale;
|
#ifdef CPOW_DTHETA
|
||||||
|
vec2 cpow;
|
||||||
|
#endif
|
||||||
#ifdef POWRATE
|
#ifdef POWRATE
|
||||||
float zpow;
|
float zpow;
|
||||||
#endif
|
#endif
|
||||||
|
float scale;
|
||||||
} params;
|
} params;
|
||||||
|
|
||||||
vec3 incol = vec3(0.000000, 0.014444, 0.027321);
|
vec3 incol = vec3(0.000000, 0.014444, 0.027321);
|
||||||
@ -61,13 +68,37 @@ vec2 maptoz(vec2 xy)
|
|||||||
return params.scale * z + params.centre;
|
return params.scale * z + params.centre;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 zpow(vec2 z, float p) {
|
#ifdef CPOW_DTHETA
|
||||||
|
vec2 cmul(vec2 a, vec2 b)
|
||||||
|
{
|
||||||
|
return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 cexp(vec2 z)
|
||||||
|
{
|
||||||
|
return exp(z.x) * vec2(cos(z.y), sin(z.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 cln(vec2 z)
|
||||||
|
{
|
||||||
|
return vec2(log(length(z)), atan(z.y, z.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 cpow(vec2 z, vec2 p)
|
||||||
|
{
|
||||||
|
if (z.x == 0.0 && z.y == 0.0) return vec2(0.0, 0.0);
|
||||||
|
return cexp(cmul(p, cln(z)));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
vec2 zpow(vec2 z, float p)
|
||||||
|
{
|
||||||
float r = length(z);
|
float r = length(z);
|
||||||
float theta = atan(z.y, z.x);
|
float theta = atan(z.y, z.x);
|
||||||
float mag = pow(r, p);
|
float mag = pow(r, p);
|
||||||
float phi = p * theta;
|
float phi = p * theta;
|
||||||
return mag * vec2(cos(phi), sin(phi));
|
return mag * vec2(cos(phi), sin(phi));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int fractal(vec2 c) {
|
int fractal(vec2 c) {
|
||||||
#ifdef JULIA
|
#ifdef JULIA
|
||||||
@ -77,12 +108,14 @@ int fractal(vec2 c) {
|
|||||||
vec2 z = vec2(0.0, 0.0);
|
vec2 z = vec2(0.0, 0.0);
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < MAXITER; ++i) {
|
for (int i = 0; i < MAXITER; ++i) {
|
||||||
#ifdef POWRATE
|
#ifdef CPOW_DTHETA
|
||||||
|
z = cpow(z, params.cpow) + c;
|
||||||
|
#elif defined(POWRATE)
|
||||||
z = zpow(z, params.zpow) + c;
|
z = zpow(z, params.zpow) + c;
|
||||||
#else
|
#else
|
||||||
z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;
|
z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;
|
||||||
#endif
|
#endif
|
||||||
if (length(z) > 2.0)
|
if (length(z) > MAXMAG)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
81
main.c
81
main.c
@ -10,6 +10,7 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -26,6 +27,10 @@
|
|||||||
|
|
||||||
#define MAX_SHADER_SIZE (8 * 1024)
|
#define MAX_SHADER_SIZE (8 * 1024)
|
||||||
|
|
||||||
|
#if defined(CPOW_DTHETA) && defined(POWRATE)
|
||||||
|
#error "Cannot define CPOW_DTHETA and POWRATE simulataneously"
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float width, height;
|
float width, height;
|
||||||
#ifdef JULIA
|
#ifdef JULIA
|
||||||
@ -36,14 +41,23 @@ typedef struct {
|
|||||||
struct {
|
struct {
|
||||||
float re, im;
|
float re, im;
|
||||||
} centre;
|
} centre;
|
||||||
float scale;
|
#ifdef CPOW_DTHETA
|
||||||
|
struct {
|
||||||
|
float re, im;
|
||||||
|
} cpow;
|
||||||
|
#endif
|
||||||
#ifdef POWRATE
|
#ifdef POWRATE
|
||||||
float zpow;
|
float zpow;
|
||||||
#endif
|
#endif
|
||||||
|
float scale;
|
||||||
} params_t;
|
} params_t;
|
||||||
|
|
||||||
static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
|
static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
|
||||||
static const char *swapchain_ext_name = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
|
static const char *extensions[] = {
|
||||||
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NEXTENSIONS (sizeof(extensions) / sizeof(extensions[0]))
|
||||||
|
|
||||||
// Initial parameters
|
// Initial parameters
|
||||||
static params_t params = {
|
static params_t params = {
|
||||||
@ -67,10 +81,13 @@ static params_t params = {
|
|||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
.scale = 1.0,
|
#ifdef CPOW_DTHETA
|
||||||
|
.cpow = { .re = 2.0, .im = 0.0 },
|
||||||
|
#endif
|
||||||
#ifdef POWRATE
|
#ifdef POWRATE
|
||||||
.zpow = 2.0,
|
.zpow = 2.0,
|
||||||
#endif
|
#endif
|
||||||
|
.scale = 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -89,7 +106,7 @@ mouse_button_callback(GLFWwindow *window, int button, int action, int mods)
|
|||||||
double zx = 4.0 * (x / params.width - 0.5);
|
double zx = 4.0 * (x / params.width - 0.5);
|
||||||
double zy = 4.0 * (y / params.height - 0.5);
|
double zy = 4.0 * (y / params.height - 0.5);
|
||||||
zx *= params.width / params.height;
|
zx *= params.width / params.height;
|
||||||
|
|
||||||
zx = params.scale * zx + params.centre.re;
|
zx = params.scale * zx + params.centre.re;
|
||||||
zy = params.scale * zy + params.centre.im;
|
zy = params.scale * zy + params.centre.im;
|
||||||
|
|
||||||
@ -192,6 +209,28 @@ int main(void)
|
|||||||
}
|
}
|
||||||
assert(found_queue_family);
|
assert(found_queue_family);
|
||||||
|
|
||||||
|
// Check that the physical device supports all extensions
|
||||||
|
uint32_t ext_count = EXT_PROP_BUFFER_SIZE;
|
||||||
|
VkExtensionProperties ext_props[EXT_PROP_BUFFER_SIZE];
|
||||||
|
result = vkEnumerateDeviceExtensionProperties(
|
||||||
|
physical_dev, NULL, &ext_count, ext_props);
|
||||||
|
assert(result == VK_SUCCESS);
|
||||||
|
bool supported[NEXTENSIONS] = { 0 };
|
||||||
|
for (unsigned i = 0; i < ext_count; ++i) {
|
||||||
|
for (unsigned j = 0; j < NEXTENSIONS; ++j) {
|
||||||
|
if (strcmp(extensions[j], ext_props[i].extensionName) == 0) {
|
||||||
|
supported[j] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned j = 0; j < NEXTENSIONS; ++j) {
|
||||||
|
if (!supported[j]) {
|
||||||
|
fprintf(stderr, "Unsupported: %s\n", extensions[j]);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the logical device and get the queue handle.
|
// Create the logical device and get the queue handle.
|
||||||
float queue_priority = 1.0;
|
float queue_priority = 1.0;
|
||||||
const VkDeviceQueueCreateInfo queue_create_info = {
|
const VkDeviceQueueCreateInfo queue_create_info = {
|
||||||
@ -204,8 +243,8 @@ int main(void)
|
|||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
.pQueueCreateInfos = &queue_create_info,
|
.pQueueCreateInfos = &queue_create_info,
|
||||||
.queueCreateInfoCount = 1,
|
.queueCreateInfoCount = 1,
|
||||||
.enabledExtensionCount = 1,
|
.enabledExtensionCount = NEXTENSIONS,
|
||||||
.ppEnabledExtensionNames = &swapchain_ext_name,
|
.ppEnabledExtensionNames = extensions,
|
||||||
};
|
};
|
||||||
VkDevice dev;
|
VkDevice dev;
|
||||||
result = vkCreateDevice(physical_dev, &dev_create_info, NULL, &dev);
|
result = vkCreateDevice(physical_dev, &dev_create_info, NULL, &dev);
|
||||||
@ -213,21 +252,6 @@ int main(void)
|
|||||||
VkQueue queue;
|
VkQueue queue;
|
||||||
vkGetDeviceQueue(dev, queue_family, 0, &queue);
|
vkGetDeviceQueue(dev, queue_family, 0, &queue);
|
||||||
|
|
||||||
// Check that the physical device has swap chain support
|
|
||||||
uint32_t ext_count = EXT_PROP_BUFFER_SIZE;
|
|
||||||
VkExtensionProperties ext_props[EXT_PROP_BUFFER_SIZE];
|
|
||||||
result = vkEnumerateDeviceExtensionProperties(
|
|
||||||
physical_dev, NULL, &ext_count, ext_props);
|
|
||||||
assert(result == VK_SUCCESS);
|
|
||||||
bool swapchain_support = false;
|
|
||||||
for (unsigned i = 0; i < ext_count; ++i) {
|
|
||||||
if (strcmp(swapchain_ext_name, ext_props[i].extensionName) == 0) {
|
|
||||||
swapchain_support = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(swapchain_support);
|
|
||||||
|
|
||||||
// Select a surface format, preferring R8G8B8A8_SRGB with
|
// Select a surface format, preferring R8G8B8A8_SRGB with
|
||||||
// SRGB_NONLINEAR colour space.
|
// SRGB_NONLINEAR colour space.
|
||||||
uint32_t surface_fmt_count = SURFACE_FMT_BUFFER_SIZE;
|
uint32_t surface_fmt_count = SURFACE_FMT_BUFFER_SIZE;
|
||||||
@ -534,8 +558,10 @@ int main(void)
|
|||||||
params.width = (float)swapchain_extent.width;
|
params.width = (float)swapchain_extent.width;
|
||||||
params.height = (float)swapchain_extent.height;
|
params.height = (float)swapchain_extent.height;
|
||||||
#ifdef JULIA_DTHETA
|
#ifdef JULIA_DTHETA
|
||||||
const double dtheta = JULIA_DTHETA;
|
const double complex julia_rotz = cexp(I * JULIA_DTHETA);
|
||||||
const double complex rotz = cexp(I * dtheta);
|
#endif
|
||||||
|
#ifdef CPOW_DTHETA
|
||||||
|
const double complex cpow_rotz = cexp(I * CPOW_DTHETA);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window)) {
|
while (!glfwWindowShouldClose(window)) {
|
||||||
@ -617,7 +643,7 @@ int main(void)
|
|||||||
|
|
||||||
#ifdef JULIA_DTHETA
|
#ifdef JULIA_DTHETA
|
||||||
double complex julia = params.julia.re + I * params.julia.im;
|
double complex julia = params.julia.re + I * params.julia.im;
|
||||||
julia *= rotz;
|
julia *= julia_rotz;
|
||||||
params.julia.re = (float)creal(julia);
|
params.julia.re = (float)creal(julia);
|
||||||
params.julia.im = (float)cimag(julia);
|
params.julia.im = (float)cimag(julia);
|
||||||
#endif
|
#endif
|
||||||
@ -626,6 +652,13 @@ int main(void)
|
|||||||
params.scale *= (1 - ZOOMRATE);
|
params.scale *= (1 - ZOOMRATE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CPOW_DTHETA
|
||||||
|
double complex cpow = params.cpow.re + I * params.cpow.im;
|
||||||
|
cpow *= cpow_rotz;
|
||||||
|
params.cpow.re = (float)creal(cpow);
|
||||||
|
params.cpow.im = (float)cimag(cpow);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef POWRATE
|
#ifdef POWRATE
|
||||||
params.zpow += POWRATE;
|
params.zpow += POWRATE;
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user