This commit is contained in:
Ashley Towns 2025-04-27 01:15:07 +10:00
commit 4d3a0d28cd
23 changed files with 3848 additions and 0 deletions

48
CMakeLists.txt Normal file
View file

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.31)
project(MandelbrotRenderer)
set(CMAKE_C_STANDARD 11)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # Enables LTO
# Set the required libraries
find_package(PkgConfig)
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(glfw3 REQUIRED)
find_package(OpenCL REQUIRED)
find_package(OpenMP REQUIRED)
if (OpenMP_C_FOUND)
message(STATUS "OpenMP found")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
else ()
message(STATUS "OpenMP not found")
endif ()
include_directories(${OPENGL_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
# Path to your OpenCL kernel
set(OPENCL_KERNEL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/mandelbrot_kernel.cl")
# Copy it into the binary directory automatically
configure_file(${OPENCL_KERNEL_FILE} ${CMAKE_CURRENT_BINARY_DIR}/mandelbrot_kernel.cl COPYONLY)
add_executable(MandelbrotRenderer src/main.c src/mandelbrot.c src/render.c src/input.c src/mandelbrot_opencl_kernels.c)
target_compile_options(MandelbrotRenderer PRIVATE
# -g # Debugging information
-O3 # Optimize for speed
-march=native # Use the best available instruction set for the host CPU
-ffast-math # Looser IEEE compliance, allows math reordering and vectorization
-ftree-vectorize # Enable vectorization (SIMD)
-funroll-loops # Unroll loops for better performance
-flto # Link Time Optimization
-fopenmp # Enable OpenMP for parallel processing
-fomit-frame-pointer # Omit frame pointers for better performance
-mavx2 # Enable AVX2 instructions\
-mavx512f # Enable AVX512 instructions
-mfma # Enable FMA (Fused Multiply-Add) instructions
-mfpmath=sse # Use SSE for floating-point math
-fvectorize # Enable vectorization
)
target_link_libraries(MandelbrotRenderer ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} glfw OpenMP::OpenMP_C m OpenCL::OpenCL)

View file

@ -0,0 +1,264 @@
#ifndef CIVIDIS_LUT_H
#define CIVIDIS_LUT_H
static const unsigned char cividis_name[] = "Cividis";
static const unsigned char cividis[256][3] = {
{0, 32, 77},
{0, 33, 78},
{0, 33, 80},
{0, 34, 82},
{0, 35, 83},
{0, 36, 85},
{0, 36, 87},
{0, 37, 88},
{0, 38, 90},
{0, 38, 92},
{0, 39, 94},
{0, 40, 95},
{0, 40, 97},
{0, 41, 99},
{0, 42, 101},
{0, 43, 103},
{0, 43, 105},
{0, 44, 106},
{0, 45, 108},
{0, 46, 110},
{0, 46, 111},
{0, 46, 111},
{0, 47, 111},
{0, 47, 111},
{0, 48, 111},
{0, 49, 111},
{0, 50, 111},
{0, 50, 111},
{0, 51, 111},
{0, 52, 111},
{0, 53, 110},
{1, 53, 110},
{6, 54, 110},
{10, 55, 110},
{14, 55, 110},
{18, 56, 109},
{21, 57, 109},
{23, 58, 109},
{26, 58, 109},
{28, 59, 109},
{30, 60, 109},
{32, 61, 108},
{34, 61, 108},
{36, 62, 108},
{38, 63, 108},
{40, 63, 108},
{41, 64, 108},
{43, 65, 108},
{44, 66, 108},
{46, 66, 108},
{47, 67, 107},
{49, 68, 107},
{50, 68, 107},
{51, 69, 107},
{53, 70, 107},
{54, 71, 107},
{55, 71, 107},
{57, 72, 107},
{58, 73, 107},
{59, 74, 107},
{60, 74, 107},
{61, 75, 107},
{63, 76, 107},
{64, 76, 107},
{65, 77, 107},
{66, 78, 107},
{67, 79, 107},
{68, 79, 107},
{69, 80, 107},
{70, 81, 107},
{71, 81, 107},
{73, 82, 107},
{74, 83, 107},
{75, 84, 107},
{76, 84, 108},
{77, 85, 108},
{78, 86, 108},
{79, 86, 108},
{80, 87, 108},
{81, 88, 108},
{82, 89, 108},
{83, 89, 108},
{84, 90, 108},
{85, 91, 109},
{86, 91, 109},
{86, 92, 109},
{87, 93, 109},
{88, 94, 109},
{89, 94, 109},
{90, 95, 109},
{91, 96, 110},
{92, 97, 110},
{93, 97, 110},
{94, 98, 110},
{95, 99, 110},
{96, 99, 111},
{97, 100, 111},
{98, 101, 111},
{99, 102, 111},
{99, 102, 111},
{100, 103, 112},
{101, 104, 112},
{102, 105, 112},
{103, 105, 112},
{104, 106, 113},
{105, 107, 113},
{106, 107, 113},
{107, 108, 113},
{107, 109, 114},
{108, 110, 114},
{109, 110, 114},
{110, 111, 115},
{111, 112, 115},
{112, 113, 115},
{113, 113, 116},
{114, 114, 116},
{114, 115, 116},
{115, 116, 117},
{116, 116, 117},
{117, 117, 117},
{118, 118, 118},
{119, 119, 118},
{120, 119, 119},
{120, 120, 119},
{121, 121, 119},
{122, 122, 120},
{123, 122, 120},
{124, 123, 120},
{125, 124, 120},
{126, 125, 120},
{127, 125, 120},
{128, 126, 121},
{129, 127, 121},
{130, 128, 121},
{131, 128, 121},
{132, 129, 121},
{133, 130, 121},
{133, 131, 121},
{134, 131, 121},
{135, 132, 121},
{136, 133, 121},
{137, 134, 121},
{138, 135, 121},
{139, 135, 121},
{140, 136, 121},
{141, 137, 121},
{142, 138, 121},
{143, 139, 121},
{144, 139, 121},
{145, 140, 120},
{146, 141, 120},
{147, 142, 120},
{148, 142, 120},
{149, 143, 120},
{150, 144, 120},
{151, 145, 120},
{152, 146, 120},
{153, 146, 120},
{154, 147, 119},
{155, 148, 119},
{156, 149, 119},
{157, 150, 119},
{158, 150, 119},
{159, 151, 119},
{160, 152, 119},
{161, 153, 118},
{163, 154, 118},
{164, 155, 118},
{165, 155, 118},
{166, 156, 117},
{167, 157, 117},
{168, 158, 117},
{169, 159, 117},
{170, 160, 117},
{171, 160, 116},
{172, 161, 116},
{173, 162, 116},
{174, 163, 116},
{175, 164, 115},
{176, 164, 115},
{177, 165, 115},
{178, 166, 114},
{179, 167, 114},
{180, 168, 114},
{181, 169, 113},
{182, 170, 113},
{183, 170, 113},
{184, 171, 112},
{186, 172, 112},
{187, 173, 112},
{188, 174, 111},
{189, 175, 111},
{190, 176, 111},
{191, 176, 110},
{192, 177, 110},
{193, 178, 109},
{194, 179, 109},
{195, 180, 109},
{196, 181, 108},
{197, 182, 108},
{198, 183, 107},
{200, 183, 107},
{201, 184, 106},
{202, 185, 106},
{203, 186, 105},
{204, 187, 105},
{205, 188, 104},
{206, 189, 104},
{207, 190, 103},
{208, 191, 103},
{209, 191, 102},
{211, 192, 101},
{212, 193, 101},
{213, 194, 100},
{214, 195, 100},
{215, 196, 99},
{216, 197, 99},
{217, 198, 98},
{218, 199, 97},
{219, 200, 97},
{221, 201, 96},
{222, 201, 95},
{223, 202, 95},
{224, 203, 94},
{225, 204, 93},
{226, 205, 92},
{227, 206, 92},
{229, 207, 91},
{230, 208, 90},
{231, 209, 89},
{232, 210, 88},
{233, 211, 88},
{234, 212, 87},
{235, 213, 86},
{237, 214, 85},
{238, 215, 84},
{239, 216, 83},
{240, 217, 82},
{241, 218, 81},
{242, 219, 80},
{244, 219, 79},
{245, 220, 78},
{246, 221, 77},
{247, 222, 76},
{248, 223, 75},
{250, 224, 74},
{251, 225, 73},
{252, 226, 71},
{253, 227, 70},
{254, 228, 69},
{255, 229, 67},
{255, 230, 66},
{255, 231, 66},
{255, 232, 67},
{255, 233, 68},
{255, 234, 69},
};
#endif // CIVIDIS_LUT_H

View file

@ -0,0 +1,29 @@
#ifndef COLOURMAPS_H
#define COLOURMAPS_H
#include "cividis_lut.h"
#include "cubehelix_lut.h"
#include "hsv_lut.h"
#include "inferno_lut.h"
#include "magma_lut.h"
#include "parula_lut.h"
#include "pastel_rainbow_lut.h"
#include "plasma_lut.h"
#include "turbo_lut.h"
#include "viridis_lut.h"
typedef enum
{
CIVIDIS_LUT_COLOR,
CUBEHELIX_LUT_COLOR,
HSV_LUT_COLOR,
INFERNO_LUT_COLOR,
MAGMA_LUT_COLOR,
PARULA_LUT_COLOR,
PASTEL_RAINBOW_LUT_COLOR,
PLASMA_LUT_COLOR,
TURBO_LUT_COLOR,
VIRIDIS_LUT_COLOR
} colourmap_type;
#endif // COLOURMAPS_H

View file

@ -0,0 +1,264 @@
#ifndef CUBEHELIX_LUT_H
#define CUBEHELIX_LUT_H
static const unsigned char cubehelix_name[] = "Cubehelix";
static const unsigned char cubehelix[256][3] = {
{0, 0, 0},
{1, 0, 1},
{3, 1, 3},
{5, 1, 4},
{6, 2, 6},
{8, 2, 8},
{9, 3, 9},
{10, 4, 11},
{12, 4, 13},
{13, 5, 15},
{14, 6, 17},
{16, 6, 19},
{17, 7, 21},
{18, 8, 23},
{19, 9, 25},
{20, 10, 27},
{20, 11, 29},
{21, 12, 31},
{22, 12, 33},
{23, 13, 35},
{23, 14, 37},
{24, 16, 39},
{24, 17, 41},
{25, 18, 43},
{25, 19, 45},
{25, 20, 47},
{26, 21, 49},
{26, 23, 50},
{26, 24, 52},
{26, 25, 54},
{26, 26, 56},
{26, 28, 57},
{26, 29, 59},
{26, 31, 61},
{26, 32, 62},
{26, 34, 64},
{26, 35, 65},
{25, 37, 66},
{25, 38, 68},
{25, 40, 69},
{25, 42, 70},
{24, 43, 71},
{24, 45, 72},
{24, 47, 73},
{24, 48, 74},
{23, 50, 75},
{23, 52, 75},
{23, 53, 76},
{22, 55, 77},
{22, 57, 77},
{22, 59, 77},
{22, 60, 78},
{21, 62, 78},
{21, 64, 78},
{21, 66, 78},
{21, 68, 78},
{21, 69, 78},
{21, 71, 78},
{21, 73, 78},
{21, 75, 78},
{21, 76, 77},
{21, 78, 77},
{21, 80, 77},
{21, 81, 76},
{21, 83, 76},
{22, 85, 75},
{22, 86, 74},
{22, 88, 74},
{23, 90, 73},
{24, 91, 72},
{24, 93, 71},
{25, 94, 70},
{26, 96, 70},
{27, 97, 69},
{28, 98, 68},
{29, 100, 67},
{30, 101, 66},
{31, 102, 65},
{32, 104, 64},
{33, 105, 63},
{35, 106, 62},
{36, 107, 61},
{38, 108, 60},
{40, 109, 59},
{41, 110, 58},
{43, 111, 57},
{45, 112, 56},
{47, 113, 55},
{49, 114, 54},
{51, 115, 53},
{53, 116, 52},
{55, 116, 52},
{58, 117, 51},
{60, 118, 50},
{62, 118, 49},
{65, 119, 49},
{67, 119, 48},
{70, 120, 48},
{73, 120, 47},
{75, 120, 47},
{78, 121, 47},
{81, 121, 47},
{84, 121, 47},
{87, 122, 46},
{90, 122, 47},
{93, 122, 47},
{96, 122, 47},
{99, 122, 47},
{102, 122, 47},
{105, 122, 48},
{108, 123, 48},
{111, 123, 49},
{114, 123, 50},
{117, 123, 51},
{120, 122, 52},
{123, 122, 53},
{126, 122, 54},
{129, 122, 55},
{132, 122, 56},
{135, 122, 57},
{138, 122, 59},
{141, 122, 61},
{144, 122, 62},
{147, 122, 64},
{150, 121, 66},
{153, 121, 68},
{156, 121, 70},
{159, 121, 72},
{162, 121, 74},
{164, 121, 76},
{167, 121, 78},
{169, 121, 81},
{172, 121, 83},
{174, 121, 86},
{177, 121, 89},
{179, 121, 91},
{181, 121, 94},
{184, 121, 97},
{186, 121, 100},
{188, 121, 103},
{190, 121, 106},
{192, 121, 109},
{193, 122, 112},
{195, 122, 115},
{197, 122, 118},
{198, 122, 121},
{200, 123, 124},
{201, 123, 127},
{203, 124, 131},
{204, 124, 134},
{205, 125, 137},
{206, 125, 140},
{207, 126, 144},
{208, 126, 147},
{209, 127, 150},
{210, 128, 153},
{210, 128, 156},
{211, 129, 160},
{211, 130, 163},
{212, 131, 166},
{212, 132, 169},
{212, 133, 172},
{213, 134, 175},
{213, 135, 178},
{213, 136, 181},
{213, 137, 184},
{213, 139, 187},
{213, 140, 190},
{212, 141, 193},
{212, 142, 196},
{212, 144, 198},
{212, 145, 201},
{211, 146, 203},
{211, 148, 206},
{210, 149, 208},
{210, 151, 211},
{209, 153, 213},
{209, 154, 215},
{208, 156, 217},
{207, 157, 219},
{207, 159, 221},
{206, 161, 223},
{205, 162, 225},
{205, 164, 226},
{204, 166, 228},
{203, 168, 230},
{203, 170, 231},
{202, 171, 232},
{201, 173, 234},
{201, 175, 235},
{200, 177, 236},
{199, 179, 237},
{199, 180, 238},
{198, 182, 239},
{197, 184, 240},
{197, 186, 240},
{196, 188, 241},
{196, 190, 242},
{195, 192, 242},
{195, 193, 243},
{195, 195, 243},
{194, 197, 243},
{194, 199, 243},
{194, 201, 244},
{194, 202, 244},
{194, 204, 244},
{194, 206, 244},
{194, 207, 244},
{194, 209, 244},
{194, 211, 244},
{194, 212, 244},
{194, 214, 244},
{195, 216, 243},
{195, 217, 243},
{195, 219, 243},
{196, 220, 243},
{196, 222, 242},
{197, 223, 242},
{198, 224, 242},
{199, 226, 241},
{199, 227, 241},
{200, 228, 241},
{201, 230, 241},
{202, 231, 240},
{203, 232, 240},
{205, 233, 240},
{206, 234, 240},
{207, 235, 239},
{208, 237, 239},
{210, 238, 239},
{211, 239, 239},
{213, 240, 239},
{214, 240, 239},
{216, 241, 239},
{217, 242, 239},
{219, 243, 239},
{221, 244, 240},
{222, 245, 240},
{224, 245, 240},
{226, 246, 240},
{228, 247, 241},
{230, 247, 241},
{231, 248, 242},
{233, 249, 243},
{235, 249, 243},
{237, 250, 244},
{239, 251, 245},
{241, 251, 246},
{243, 252, 247},
{245, 252, 248},
{246, 253, 249},
{248, 253, 250},
{250, 254, 251},
{252, 254, 253},
{254, 255, 254},
{255, 255, 255},
};
#endif // CUBEHELIX_LUT_H

264
src/colourmaps/hsv_lut.h Normal file
View file

@ -0,0 +1,264 @@
#ifndef _HSV_LUT_H_
#define _HSV_LUT_H_
static const unsigned char hsv_name[] = "HSV";
static const unsigned char hsv[256][3] = {
{255, 0, 0},
{255, 5, 0},
{255, 12, 0},
{255, 17, 0},
{255, 24, 0},
{255, 30, 0},
{255, 35, 0},
{255, 42, 0},
{255, 48, 0},
{255, 53, 0},
{255, 60, 0},
{255, 65, 0},
{255, 71, 0},
{255, 78, 0},
{255, 83, 0},
{255, 90, 0},
{255, 96, 0},
{255, 101, 0},
{255, 108, 0},
{255, 113, 0},
{255, 120, 0},
{255, 126, 0},
{255, 131, 0},
{255, 138, 0},
{255, 144, 0},
{255, 149, 0},
{255, 156, 0},
{255, 161, 0},
{255, 167, 0},
{255, 174, 0},
{255, 179, 0},
{255, 186, 0},
{255, 192, 0},
{255, 197, 0},
{255, 204, 0},
{255, 209, 0},
{255, 216, 0},
{255, 222, 0},
{255, 227, 0},
{255, 234, 0},
{255, 240, 0},
{255, 245, 0},
{255, 252, 0},
{254, 255, 0},
{248, 255, 0},
{241, 255, 0},
{236, 255, 0},
{229, 255, 0},
{224, 255, 0},
{218, 255, 0},
{211, 255, 0},
{206, 255, 0},
{199, 255, 0},
{193, 255, 0},
{188, 255, 0},
{181, 255, 0},
{176, 255, 0},
{170, 255, 0},
{163, 255, 0},
{158, 255, 0},
{152, 255, 0},
{145, 255, 0},
{140, 255, 0},
{133, 255, 0},
{128, 255, 0},
{122, 255, 0},
{115, 255, 0},
{110, 255, 0},
{103, 255, 0},
{97, 255, 0},
{92, 255, 0},
{85, 255, 0},
{80, 255, 0},
{74, 255, 0},
{67, 255, 0},
{62, 255, 0},
{56, 255, 0},
{49, 255, 0},
{44, 255, 0},
{37, 255, 0},
{32, 255, 0},
{26, 255, 0},
{19, 255, 0},
{14, 255, 0},
{7, 255, 0},
{1, 255, 0},
{0, 255, 3},
{0, 255, 10},
{0, 255, 16},
{0, 255, 21},
{0, 255, 28},
{0, 255, 33},
{0, 255, 39},
{0, 255, 46},
{0, 255, 51},
{0, 255, 58},
{0, 255, 64},
{0, 255, 69},
{0, 255, 76},
{0, 255, 81},
{0, 255, 88},
{0, 255, 94},
{0, 255, 99},
{0, 255, 106},
{0, 255, 112},
{0, 255, 117},
{0, 255, 124},
{0, 255, 129},
{0, 255, 135},
{0, 255, 142},
{0, 255, 147},
{0, 255, 154},
{0, 255, 160},
{0, 255, 165},
{0, 255, 172},
{0, 255, 177},
{0, 255, 184},
{0, 255, 190},
{0, 255, 195},
{0, 255, 202},
{0, 255, 208},
{0, 255, 213},
{0, 255, 220},
{0, 255, 225},
{0, 255, 231},
{0, 255, 238},
{0, 255, 243},
{0, 255, 250},
{0, 255, 255},
{0, 250, 255},
{0, 243, 255},
{0, 238, 255},
{0, 231, 255},
{0, 225, 255},
{0, 220, 255},
{0, 213, 255},
{0, 208, 255},
{0, 202, 255},
{0, 195, 255},
{0, 190, 255},
{0, 184, 255},
{0, 177, 255},
{0, 172, 255},
{0, 165, 255},
{0, 160, 255},
{0, 154, 255},
{0, 147, 255},
{0, 142, 255},
{0, 135, 255},
{0, 129, 255},
{0, 124, 255},
{0, 117, 255},
{0, 112, 255},
{0, 106, 255},
{0, 99, 255},
{0, 94, 255},
{0, 88, 255},
{0, 81, 255},
{0, 76, 255},
{0, 69, 255},
{0, 64, 255},
{0, 58, 255},
{0, 51, 255},
{0, 46, 255},
{0, 39, 255},
{0, 33, 255},
{0, 28, 255},
{0, 21, 255},
{0, 16, 255},
{0, 10, 255},
{0, 3, 255},
{1, 0, 255},
{7, 0, 255},
{14, 0, 255},
{19, 0, 255},
{26, 0, 255},
{32, 0, 255},
{37, 0, 255},
{44, 0, 255},
{49, 0, 255},
{56, 0, 255},
{62, 0, 255},
{67, 0, 255},
{74, 0, 255},
{80, 0, 255},
{85, 0, 255},
{92, 0, 255},
{97, 0, 255},
{103, 0, 255},
{110, 0, 255},
{115, 0, 255},
{122, 0, 255},
{128, 0, 255},
{133, 0, 255},
{140, 0, 255},
{145, 0, 255},
{152, 0, 255},
{158, 0, 255},
{163, 0, 255},
{170, 0, 255},
{176, 0, 255},
{181, 0, 255},
{188, 0, 255},
{193, 0, 255},
{199, 0, 255},
{206, 0, 255},
{211, 0, 255},
{218, 0, 255},
{224, 0, 255},
{229, 0, 255},
{236, 0, 255},
{241, 0, 255},
{248, 0, 255},
{254, 0, 255},
{255, 0, 252},
{255, 0, 245},
{255, 0, 240},
{255, 0, 234},
{255, 0, 227},
{255, 0, 222},
{255, 0, 216},
{255, 0, 209},
{255, 0, 204},
{255, 0, 197},
{255, 0, 192},
{255, 0, 186},
{255, 0, 179},
{255, 0, 174},
{255, 0, 167},
{255, 0, 161},
{255, 0, 156},
{255, 0, 149},
{255, 0, 144},
{255, 0, 138},
{255, 0, 131},
{255, 0, 126},
{255, 0, 120},
{255, 0, 113},
{255, 0, 108},
{255, 0, 101},
{255, 0, 96},
{255, 0, 90},
{255, 0, 83},
{255, 0, 78},
{255, 0, 71},
{255, 0, 65},
{255, 0, 60},
{255, 0, 53},
{255, 0, 48},
{255, 0, 42},
{255, 0, 35},
{255, 0, 30},
{255, 0, 24},
{255, 0, 17},
{255, 0, 12},
{255, 0, 5},
};
#endif // _HSV_LUT_H_

View file

@ -0,0 +1,264 @@
#ifndef INFERNO_LUT_H
#define INFERNO_LUT_H
static const unsigned char inferno_name[] = "Inferno";
static const unsigned char inferno[256][3] = {
{0, 0, 3},
{0, 0, 4},
{0, 0, 6},
{1, 0, 7},
{1, 1, 9},
{1, 1, 11},
{2, 1, 14},
{2, 2, 16},
{3, 2, 18},
{4, 3, 20},
{4, 3, 22},
{5, 4, 24},
{6, 4, 27},
{7, 5, 29},
{8, 6, 31},
{9, 6, 33},
{10, 7, 36},
{12, 7, 38},
{13, 8, 40},
{14, 8, 43},
{15, 9, 45},
{16, 9, 47},
{18, 10, 50},
{19, 10, 52},
{20, 11, 55},
{22, 11, 57},
{23, 11, 59},
{25, 11, 62},
{26, 12, 64},
{28, 12, 67},
{29, 12, 69},
{31, 12, 72},
{33, 12, 74},
{34, 11, 76},
{36, 11, 78},
{38, 11, 81},
{39, 11, 83},
{41, 11, 85},
{43, 10, 87},
{45, 10, 89},
{46, 10, 90},
{48, 10, 92},
{50, 9, 94},
{52, 9, 95},
{54, 9, 96},
{55, 9, 98},
{57, 9, 99},
{59, 9, 100},
{60, 9, 101},
{62, 9, 102},
{64, 9, 103},
{66, 9, 104},
{67, 10, 104},
{69, 10, 105},
{71, 10, 106},
{72, 11, 106},
{74, 11, 107},
{76, 12, 107},
{77, 12, 108},
{79, 13, 108},
{80, 13, 108},
{82, 14, 109},
{84, 14, 109},
{85, 15, 109},
{87, 15, 109},
{89, 16, 110},
{90, 17, 110},
{92, 17, 110},
{93, 18, 110},
{95, 18, 110},
{97, 19, 110},
{98, 20, 110},
{100, 20, 110},
{101, 21, 110},
{103, 21, 110},
{104, 22, 110},
{106, 23, 110},
{108, 23, 110},
{109, 24, 110},
{111, 24, 110},
{112, 25, 110},
{114, 26, 110},
{116, 26, 110},
{117, 27, 110},
{119, 27, 109},
{120, 28, 109},
{122, 28, 109},
{124, 29, 109},
{125, 29, 108},
{127, 30, 108},
{128, 31, 108},
{130, 31, 108},
{132, 32, 107},
{133, 32, 107},
{135, 33, 107},
{136, 33, 106},
{138, 34, 106},
{140, 35, 105},
{141, 35, 105},
{143, 36, 104},
{144, 36, 104},
{146, 37, 104},
{148, 37, 103},
{149, 38, 103},
{151, 39, 102},
{152, 39, 101},
{154, 40, 101},
{155, 40, 100},
{157, 41, 100},
{159, 42, 99},
{160, 42, 98},
{162, 43, 98},
{163, 43, 97},
{165, 44, 96},
{167, 45, 96},
{168, 45, 95},
{170, 46, 94},
{171, 47, 93},
{173, 47, 93},
{174, 48, 92},
{176, 49, 91},
{177, 49, 90},
{179, 50, 89},
{180, 51, 89},
{182, 52, 88},
{183, 52, 87},
{185, 53, 86},
{186, 54, 85},
{188, 55, 84},
{189, 56, 83},
{191, 56, 82},
{192, 57, 81},
{194, 58, 80},
{195, 59, 79},
{197, 60, 78},
{198, 61, 77},
{199, 62, 76},
{201, 63, 75},
{202, 64, 74},
{203, 65, 73},
{205, 66, 72},
{206, 67, 71},
{207, 68, 70},
{209, 69, 69},
{210, 70, 68},
{211, 71, 67},
{213, 72, 65},
{214, 73, 64},
{215, 74, 63},
{216, 76, 62},
{217, 77, 61},
{219, 78, 60},
{220, 79, 59},
{221, 81, 57},
{222, 82, 56},
{223, 83, 55},
{224, 85, 54},
{225, 86, 53},
{226, 87, 51},
{227, 89, 50},
{228, 90, 49},
{229, 91, 48},
{230, 93, 47},
{231, 94, 45},
{232, 96, 44},
{233, 97, 43},
{234, 99, 42},
{235, 100, 40},
{236, 102, 39},
{237, 103, 38},
{237, 105, 37},
{238, 106, 35},
{239, 108, 34},
{240, 110, 33},
{241, 111, 32},
{241, 113, 30},
{242, 114, 29},
{243, 116, 28},
{243, 118, 26},
{244, 119, 25},
{244, 121, 24},
{245, 123, 22},
{246, 125, 21},
{246, 126, 20},
{247, 128, 18},
{247, 130, 17},
{248, 132, 16},
{248, 133, 14},
{248, 135, 13},
{249, 137, 12},
{249, 139, 11},
{250, 141, 9},
{250, 142, 8},
{250, 144, 8},
{251, 146, 7},
{251, 148, 6},
{251, 150, 6},
{251, 152, 6},
{252, 153, 6},
{252, 155, 6},
{252, 157, 6},
{252, 159, 7},
{252, 161, 7},
{252, 163, 8},
{252, 165, 10},
{252, 167, 11},
{252, 169, 13},
{252, 170, 14},
{252, 172, 16},
{252, 174, 18},
{252, 176, 20},
{252, 178, 22},
{252, 180, 24},
{252, 182, 26},
{252, 184, 28},
{252, 186, 30},
{251, 188, 33},
{251, 190, 35},
{251, 192, 37},
{251, 194, 40},
{250, 196, 42},
{250, 198, 45},
{250, 200, 47},
{249, 202, 50},
{249, 204, 52},
{249, 206, 55},
{248, 208, 58},
{248, 210, 61},
{247, 212, 63},
{247, 214, 66},
{246, 216, 69},
{246, 217, 73},
{245, 219, 76},
{245, 221, 79},
{244, 223, 82},
{244, 225, 86},
{244, 227, 89},
{243, 229, 93},
{243, 231, 97},
{242, 233, 101},
{242, 234, 105},
{242, 236, 109},
{242, 238, 113},
{242, 239, 117},
{242, 241, 121},
{242, 243, 125},
{243, 244, 130},
{243, 245, 134},
{244, 247, 138},
{245, 248, 142},
{246, 249, 146},
{247, 251, 150},
{248, 252, 154},
{249, 253, 157},
{251, 254, 161},
{253, 255, 165},
};
#endif // INFERNO_LUT_H

264
src/colourmaps/magma_lut.h Normal file
View file

@ -0,0 +1,264 @@
#ifndef MAGMA_LUT_H
#define MAGMA_LUT_H
static const unsigned char magma_name[] = "Magma";
static const unsigned char magma[256][3] = {
{0, 0, 3},
{0, 0, 4},
{0, 0, 6},
{1, 0, 7},
{1, 1, 9},
{1, 1, 11},
{2, 2, 13},
{2, 2, 15},
{3, 3, 17},
{4, 3, 19},
{4, 4, 21},
{5, 4, 23},
{6, 5, 25},
{7, 5, 27},
{8, 6, 29},
{9, 7, 32},
{10, 7, 34},
{11, 8, 36},
{12, 9, 38},
{13, 10, 40},
{14, 10, 42},
{15, 11, 45},
{16, 12, 47},
{17, 12, 49},
{19, 13, 51},
{20, 13, 54},
{21, 14, 56},
{22, 14, 58},
{23, 15, 61},
{25, 15, 63},
{26, 16, 66},
{27, 16, 68},
{28, 16, 70},
{30, 17, 73},
{31, 17, 75},
{33, 17, 78},
{34, 17, 80},
{36, 17, 83},
{37, 17, 85},
{39, 17, 87},
{40, 17, 90},
{42, 17, 92},
{43, 17, 94},
{45, 17, 97},
{47, 16, 99},
{49, 16, 101},
{50, 16, 103},
{52, 16, 105},
{54, 15, 107},
{55, 15, 108},
{57, 15, 110},
{59, 15, 112},
{61, 15, 113},
{62, 15, 114},
{64, 15, 116},
{66, 15, 117},
{67, 15, 118},
{69, 15, 119},
{71, 15, 120},
{72, 16, 120},
{74, 16, 121},
{76, 16, 122},
{77, 17, 123},
{79, 17, 123},
{81, 18, 124},
{82, 18, 124},
{84, 19, 125},
{85, 20, 125},
{87, 20, 126},
{88, 21, 126},
{90, 21, 126},
{92, 22, 127},
{93, 23, 127},
{95, 23, 127},
{96, 24, 128},
{98, 25, 128},
{99, 25, 128},
{101, 26, 128},
{103, 26, 128},
{104, 27, 129},
{106, 28, 129},
{107, 28, 129},
{109, 29, 129},
{110, 30, 129},
{112, 30, 129},
{113, 31, 129},
{115, 32, 129},
{117, 32, 129},
{118, 33, 129},
{120, 33, 129},
{121, 34, 130},
{123, 35, 130},
{124, 35, 130},
{126, 36, 130},
{128, 36, 130},
{129, 37, 129},
{131, 37, 129},
{132, 38, 129},
{134, 39, 129},
{136, 39, 129},
{137, 40, 129},
{139, 40, 129},
{140, 41, 129},
{142, 41, 129},
{144, 42, 129},
{145, 42, 129},
{147, 43, 128},
{148, 43, 128},
{150, 44, 128},
{152, 44, 128},
{153, 45, 128},
{155, 46, 127},
{157, 46, 127},
{158, 47, 127},
{160, 47, 127},
{161, 48, 126},
{163, 48, 126},
{165, 49, 126},
{166, 49, 125},
{168, 50, 125},
{170, 50, 125},
{171, 51, 124},
{173, 51, 124},
{175, 52, 123},
{176, 52, 123},
{178, 53, 123},
{180, 53, 122},
{181, 54, 122},
{183, 55, 121},
{185, 55, 121},
{186, 56, 120},
{188, 56, 120},
{189, 57, 119},
{191, 57, 118},
{193, 58, 118},
{194, 59, 117},
{196, 59, 117},
{198, 60, 116},
{199, 61, 115},
{201, 61, 115},
{202, 62, 114},
{204, 63, 113},
{206, 63, 113},
{207, 64, 112},
{209, 65, 111},
{210, 66, 110},
{212, 67, 110},
{213, 67, 109},
{215, 68, 108},
{216, 69, 107},
{218, 70, 107},
{219, 71, 106},
{221, 72, 105},
{222, 73, 104},
{223, 74, 103},
{225, 75, 103},
{226, 76, 102},
{227, 78, 101},
{229, 79, 100},
{230, 80, 100},
{231, 81, 99},
{232, 83, 98},
{233, 84, 97},
{234, 85, 97},
{236, 87, 96},
{237, 88, 95},
{238, 90, 95},
{239, 91, 94},
{239, 93, 94},
{240, 95, 93},
{241, 96, 93},
{242, 98, 93},
{243, 100, 92},
{243, 101, 92},
{244, 103, 92},
{245, 105, 92},
{246, 107, 92},
{246, 108, 92},
{247, 110, 92},
{247, 112, 92},
{248, 114, 92},
{248, 116, 92},
{249, 118, 92},
{249, 120, 92},
{250, 121, 93},
{250, 123, 93},
{250, 125, 94},
{251, 127, 94},
{251, 129, 95},
{251, 131, 95},
{252, 133, 96},
{252, 135, 97},
{252, 137, 97},
{252, 139, 98},
{253, 140, 99},
{253, 142, 100},
{253, 144, 101},
{253, 146, 102},
{253, 148, 103},
{254, 150, 104},
{254, 152, 105},
{254, 154, 106},
{254, 156, 107},
{254, 157, 108},
{254, 159, 109},
{254, 161, 110},
{254, 163, 111},
{254, 165, 112},
{255, 167, 114},
{255, 169, 115},
{255, 171, 116},
{255, 172, 118},
{255, 174, 119},
{255, 176, 120},
{255, 178, 122},
{255, 180, 123},
{255, 182, 124},
{255, 184, 126},
{255, 185, 127},
{255, 187, 129},
{255, 189, 130},
{255, 191, 132},
{255, 193, 133},
{255, 195, 135},
{255, 197, 136},
{255, 198, 138},
{255, 200, 140},
{255, 202, 141},
{255, 204, 143},
{254, 206, 144},
{254, 208, 146},
{254, 209, 148},
{254, 211, 149},
{254, 213, 151},
{254, 215, 153},
{254, 217, 155},
{254, 219, 156},
{254, 220, 158},
{254, 222, 160},
{254, 224, 162},
{254, 226, 163},
{253, 228, 165},
{253, 230, 167},
{253, 231, 169},
{253, 233, 171},
{253, 235, 172},
{253, 237, 174},
{253, 239, 176},
{253, 241, 178},
{253, 242, 180},
{253, 244, 182},
{253, 246, 184},
{252, 248, 186},
{252, 250, 188},
{252, 251, 189},
{252, 253, 191},
};
#endif // MAGMA_LUT_H

264
src/colourmaps/parula_lut.h Normal file
View file

@ -0,0 +1,264 @@
#ifndef PARULA_LUT_H
#define PARULA_LUT_H
static const unsigned char parula_name[] = "Parula";
static const unsigned char parula[256][3] = {
{53, 42, 135},
{53, 44, 138},
{53, 45, 141},
{53, 47, 144},
{54, 48, 147},
{54, 50, 150},
{54, 51, 153},
{54, 53, 157},
{54, 54, 160},
{54, 56, 163},
{54, 57, 166},
{53, 59, 169},
{53, 60, 172},
{52, 62, 176},
{52, 64, 179},
{51, 65, 182},
{50, 67, 185},
{49, 69, 188},
{47, 70, 192},
{46, 72, 195},
{44, 74, 198},
{42, 76, 201},
{39, 78, 205},
{36, 80, 208},
{33, 82, 211},
{29, 84, 214},
{25, 86, 217},
{20, 89, 219},
{16, 91, 221},
{12, 93, 223},
{8, 95, 224},
{5, 97, 225},
{3, 98, 225},
{2, 100, 225},
{1, 101, 226},
{1, 102, 226},
{1, 104, 226},
{1, 105, 225},
{2, 106, 225},
{2, 107, 225},
{3, 108, 225},
{4, 109, 224},
{5, 110, 224},
{6, 111, 223},
{7, 112, 223},
{8, 113, 223},
{10, 114, 222},
{11, 115, 222},
{12, 116, 221},
{13, 117, 220},
{14, 118, 220},
{14, 119, 219},
{15, 120, 219},
{16, 121, 218},
{17, 122, 218},
{17, 123, 217},
{18, 124, 217},
{18, 125, 216},
{19, 126, 216},
{19, 127, 215},
{19, 128, 214},
{20, 129, 214},
{20, 130, 213},
{20, 131, 213},
{20, 132, 213},
{20, 133, 212},
{20, 134, 212},
{19, 135, 211},
{19, 136, 211},
{19, 137, 211},
{18, 139, 211},
{17, 140, 211},
{17, 141, 211},
{16, 142, 210},
{15, 144, 210},
{14, 145, 210},
{13, 146, 210},
{12, 147, 210},
{11, 149, 210},
{10, 150, 210},
{9, 151, 210},
{8, 152, 209},
{8, 153, 209},
{7, 155, 209},
{7, 156, 208},
{6, 157, 208},
{6, 158, 207},
{6, 159, 207},
{6, 160, 206},
{6, 160, 205},
{6, 161, 205},
{6, 162, 204},
{5, 163, 203},
{5, 164, 202},
{5, 164, 201},
{5, 165, 200},
{5, 166, 200},
{5, 167, 198},
{5, 167, 198},
{6, 168, 197},
{6, 169, 195},
{6, 169, 194},
{7, 170, 193},
{7, 171, 192},
{8, 171, 191},
{9, 172, 190},
{10, 173, 189},
{11, 173, 188},
{13, 174, 187},
{14, 174, 186},
{16, 175, 184},
{17, 176, 183},
{19, 176, 182},
{20, 177, 181},
{22, 177, 179},
{24, 178, 178},
{26, 178, 177},
{28, 179, 176},
{30, 179, 174},
{32, 180, 173},
{34, 180, 172},
{36, 181, 170},
{38, 181, 169},
{40, 182, 167},
{42, 182, 166},
{45, 183, 165},
{47, 183, 163},
{49, 184, 162},
{52, 184, 160},
{54, 185, 159},
{56, 185, 157},
{59, 186, 156},
{62, 186, 154},
{64, 187, 153},
{67, 187, 151},
{70, 187, 150},
{72, 188, 148},
{75, 188, 147},
{78, 188, 145},
{81, 189, 144},
{84, 189, 142},
{87, 189, 141},
{90, 190, 139},
{93, 190, 138},
{96, 190, 136},
{99, 190, 135},
{102, 191, 133},
{105, 191, 132},
{107, 191, 131},
{110, 191, 129},
{113, 191, 128},
{116, 191, 127},
{119, 191, 126},
{122, 191, 124},
{125, 191, 123},
{128, 191, 122},
{130, 191, 121},
{133, 191, 120},
{136, 191, 119},
{138, 191, 118},
{141, 191, 117},
{143, 191, 115},
{146, 191, 114},
{148, 191, 113},
{151, 191, 112},
{153, 191, 111},
{156, 191, 110},
{158, 191, 110},
{161, 191, 109},
{163, 190, 108},
{165, 190, 107},
{168, 190, 106},
{170, 190, 105},
{172, 190, 104},
{174, 190, 103},
{177, 190, 102},
{179, 190, 101},
{181, 189, 100},
{183, 189, 100},
{185, 189, 99},
{188, 189, 98},
{190, 189, 97},
{192, 189, 96},
{194, 188, 95},
{196, 188, 94},
{198, 188, 94},
{200, 188, 93},
{202, 188, 92},
{204, 187, 91},
{206, 187, 90},
{209, 187, 89},
{211, 187, 88},
{213, 187, 88},
{215, 187, 87},
{217, 186, 86},
{219, 186, 85},
{221, 186, 84},
{223, 186, 83},
{225, 186, 82},
{227, 186, 81},
{229, 186, 80},
{231, 185, 79},
{233, 185, 78},
{235, 185, 77},
{237, 185, 76},
{239, 185, 75},
{241, 185, 74},
{243, 185, 73},
{244, 186, 71},
{246, 186, 70},
{248, 186, 69},
{250, 187, 67},
{251, 188, 65},
{252, 189, 64},
{254, 190, 62},
{254, 191, 60},
{255, 192, 59},
{255, 193, 57},
{255, 195, 56},
{255, 196, 54},
{255, 197, 53},
{255, 199, 52},
{255, 200, 51},
{254, 201, 49},
{254, 203, 48},
{253, 204, 47},
{253, 205, 46},
{252, 206, 45},
{252, 208, 44},
{251, 209, 43},
{251, 210, 42},
{250, 212, 41},
{249, 213, 40},
{249, 214, 39},
{248, 216, 38},
{248, 217, 37},
{247, 218, 36},
{247, 220, 35},
{246, 221, 34},
{246, 223, 33},
{246, 224, 32},
{245, 226, 31},
{245, 227, 29},
{245, 229, 28},
{245, 230, 27},
{245, 232, 26},
{245, 234, 25},
{245, 236, 24},
{246, 237, 22},
{246, 239, 21},
{246, 241, 20},
{247, 243, 19},
{247, 245, 17},
{248, 247, 16},
{249, 249, 15},
{249, 251, 13},
};
#endif // PARULA_LUT_H

View file

@ -0,0 +1,41 @@
#ifndef PASTEL_RAINBOW_LUT_H
#define PASTEL_RAINBOW_LUT_H
static const unsigned char pastel_rainbow_name[] = "Pastel Rainbow";
static const unsigned char pastel_rainbow[256][3] = {
{255, 179, 186}, {255, 223, 186}, {255, 255, 186}, {186, 255, 201},
{186, 255, 255}, {186, 223, 255}, {186, 186, 255}, {223, 186, 255},
{255, 186, 255}, {255, 186, 223}, {255, 210, 210}, {255, 220, 210},
{255, 230, 210}, {255, 240, 210}, {250, 250, 210}, {240, 255, 210},
{230, 255, 210}, {220, 255, 210}, {210, 255, 210}, {210, 255, 220},
{210, 255, 230}, {210, 255, 240}, {210, 250, 250}, {210, 240, 255},
{210, 230, 255}, {210, 220, 255}, {210, 210, 255}, {220, 210, 255},
{230, 210, 255}, {240, 210, 255}, {250, 210, 250}, {255, 210, 240},
{255, 210, 230}, {255, 210, 220}, {255, 210, 210}, {255, 220, 220},
{255, 230, 230}, {255, 240, 230}, {250, 250, 230}, {240, 255, 230},
{230, 255, 230}, {220, 255, 230}, {210, 255, 230}, {210, 255, 240},
{210, 255, 250}, {210, 250, 255}, {210, 240, 255}, {210, 230, 255},
{210, 220, 255}, {210, 210, 255}, {220, 210, 255}, {230, 210, 255},
{240, 210, 255}, {250, 210, 255}, {255, 210, 250}, {255, 210, 240},
{255, 210, 230}, {255, 210, 220}, {255, 210, 210}, {255, 220, 220},
{255, 230, 220}, {255, 240, 220}, {250, 250, 220}, {240, 255, 220},
{230, 255, 220}, {220, 255, 220}, {210, 255, 220}, {210, 255, 230},
{210, 255, 240}, {210, 250, 250}, {210, 240, 255}, {210, 230, 255},
{210, 220, 255}, {210, 210, 255}, {220, 210, 255}, {230, 210, 255},
{240, 210, 255}, {250, 210, 255}, {255, 210, 250}, {255, 210, 240},
{255, 210, 230}, {255, 210, 220}, {255, 210, 210}, {255, 220, 220},
{255, 230, 220}, {255, 240, 220}, {250, 250, 220}, {240, 255, 220},
{230, 255, 220}, {220, 255, 220}, {210, 255, 220}, {210, 255, 230},
{210, 255, 240}, {210, 250, 250}, {210, 240, 255}, {210, 230, 255},
{210, 220, 255}, {210, 210, 255}, {220, 210, 255}, {230, 210, 255},
{240, 210, 255}, {250, 210, 255}, {255, 210, 250}, {255, 210, 240},
{255, 210, 230}, {255, 210, 220}, {255, 210, 210}, {255, 220, 220},
{255, 230, 220}, {255, 240, 220}, {250, 250, 220}, {240, 255, 220},
{230, 255, 220}, {220, 255, 220}, {210, 255, 220}, {210, 255, 230},
{210, 255, 240}, {210, 250, 250}, {210, 240, 255}, {210, 230, 255},
{210, 220, 255}, {210, 210, 255}, {220, 210, 255}, {230, 210, 255},
{240, 210, 255}, {250, 210, 255}, {255, 210, 250}, {255, 210, 240},
{255, 210, 230}, {255, 210, 220}, {255, 210, 210}
};
#endif // PASTEL_RAINBOW_LUT_H

264
src/colourmaps/plasma_lut.h Normal file
View file

@ -0,0 +1,264 @@
#ifndef PLASMA_LUT_H
#define PLASMA_LUT_H
static const unsigned char plasma_name[] = "Plasma";
static const unsigned char plasma[256][3] = {
{12, 7, 135},
{16, 7, 136},
{19, 6, 137},
{22, 6, 138},
{24, 6, 140},
{27, 6, 141},
{29, 6, 142},
{31, 5, 143},
{33, 5, 144},
{35, 5, 145},
{38, 5, 146},
{40, 5, 146},
{42, 5, 147},
{43, 5, 148},
{45, 4, 149},
{47, 4, 150},
{49, 4, 151},
{51, 4, 151},
{53, 4, 152},
{54, 4, 153},
{56, 4, 154},
{58, 4, 154},
{60, 3, 155},
{61, 3, 156},
{63, 3, 156},
{65, 3, 157},
{66, 3, 158},
{68, 3, 158},
{70, 3, 159},
{71, 2, 160},
{73, 2, 160},
{75, 2, 161},
{76, 2, 161},
{78, 2, 162},
{80, 2, 162},
{81, 1, 163},
{83, 1, 163},
{84, 1, 164},
{86, 1, 164},
{88, 1, 165},
{89, 1, 165},
{91, 0, 165},
{92, 0, 166},
{94, 0, 166},
{95, 0, 166},
{97, 0, 167},
{99, 0, 167},
{100, 0, 167},
{102, 0, 167},
{103, 0, 168},
{105, 0, 168},
{106, 0, 168},
{108, 0, 168},
{110, 0, 168},
{111, 0, 168},
{113, 0, 168},
{114, 0, 169},
{116, 0, 169},
{117, 0, 169},
{119, 1, 168},
{120, 1, 168},
{122, 1, 168},
{123, 2, 168},
{125, 2, 168},
{126, 3, 168},
{128, 3, 168},
{129, 4, 167},
{131, 4, 167},
{132, 5, 167},
{134, 6, 167},
{135, 7, 166},
{136, 7, 166},
{138, 8, 166},
{139, 9, 165},
{141, 11, 165},
{142, 12, 164},
{144, 13, 164},
{145, 14, 163},
{146, 15, 163},
{148, 16, 162},
{149, 17, 161},
{150, 18, 161},
{152, 19, 160},
{153, 20, 160},
{155, 21, 159},
{156, 23, 158},
{157, 24, 157},
{158, 25, 157},
{160, 26, 156},
{161, 27, 155},
{162, 28, 154},
{164, 29, 154},
{165, 30, 153},
{166, 32, 152},
{167, 33, 151},
{169, 34, 150},
{170, 35, 149},
{171, 36, 149},
{172, 37, 148},
{173, 38, 147},
{175, 40, 146},
{176, 41, 145},
{177, 42, 144},
{178, 43, 143},
{179, 44, 142},
{180, 45, 141},
{181, 46, 140},
{183, 47, 139},
{184, 49, 138},
{185, 50, 137},
{186, 51, 137},
{187, 52, 136},
{188, 53, 135},
{189, 54, 134},
{190, 55, 133},
{191, 57, 132},
{192, 58, 131},
{193, 59, 130},
{194, 60, 129},
{195, 61, 128},
{196, 62, 127},
{197, 63, 126},
{198, 64, 125},
{199, 66, 124},
{200, 67, 123},
{201, 68, 122},
{202, 69, 122},
{203, 70, 121},
{204, 71, 120},
{205, 72, 119},
{206, 73, 118},
{207, 75, 117},
{208, 76, 116},
{208, 77, 115},
{209, 78, 114},
{210, 79, 113},
{211, 80, 112},
{212, 81, 112},
{213, 83, 111},
{214, 84, 110},
{215, 85, 109},
{215, 86, 108},
{216, 87, 107},
{217, 88, 106},
{218, 89, 105},
{219, 91, 105},
{220, 92, 104},
{220, 93, 103},
{221, 94, 102},
{222, 95, 101},
{223, 96, 100},
{224, 98, 99},
{224, 99, 98},
{225, 100, 98},
{226, 101, 97},
{227, 102, 96},
{227, 104, 95},
{228, 105, 94},
{229, 106, 93},
{230, 107, 92},
{230, 108, 92},
{231, 110, 91},
{232, 111, 90},
{232, 112, 89},
{233, 113, 88},
{234, 114, 87},
{235, 116, 86},
{235, 117, 86},
{236, 118, 85},
{237, 119, 84},
{237, 121, 83},
{238, 122, 82},
{238, 123, 81},
{239, 124, 80},
{240, 126, 80},
{240, 127, 79},
{241, 128, 78},
{241, 129, 77},
{242, 131, 76},
{242, 132, 75},
{243, 133, 74},
{244, 135, 73},
{244, 136, 73},
{245, 137, 72},
{245, 139, 71},
{246, 140, 70},
{246, 141, 69},
{247, 143, 68},
{247, 144, 67},
{247, 145, 67},
{248, 147, 66},
{248, 148, 65},
{249, 149, 64},
{249, 151, 63},
{249, 152, 62},
{250, 154, 61},
{250, 155, 60},
{251, 156, 60},
{251, 158, 59},
{251, 159, 58},
{251, 161, 57},
{252, 162, 56},
{252, 164, 55},
{252, 165, 54},
{252, 166, 54},
{253, 168, 53},
{253, 169, 52},
{253, 171, 51},
{253, 172, 50},
{253, 174, 49},
{254, 175, 49},
{254, 177, 48},
{254, 178, 47},
{254, 180, 46},
{254, 181, 46},
{254, 183, 45},
{254, 185, 44},
{254, 186, 43},
{254, 188, 43},
{254, 189, 42},
{254, 191, 41},
{254, 192, 41},
{254, 194, 40},
{254, 195, 40},
{254, 197, 39},
{254, 199, 39},
{253, 200, 38},
{253, 202, 38},
{253, 203, 37},
{253, 205, 37},
{253, 207, 37},
{252, 208, 36},
{252, 210, 36},
{252, 212, 36},
{251, 213, 36},
{251, 215, 36},
{251, 217, 36},
{250, 218, 36},
{250, 220, 36},
{249, 222, 36},
{249, 223, 36},
{248, 225, 37},
{248, 227, 37},
{247, 229, 37},
{247, 230, 37},
{246, 232, 38},
{246, 234, 38},
{245, 235, 38},
{244, 237, 39},
{244, 239, 39},
{243, 241, 39},
{242, 242, 38},
{242, 244, 38},
{241, 246, 37},
{241, 247, 36},
{240, 249, 33},
};
#endif // PLASMA_LUT_H

264
src/colourmaps/turbo_lut.h Normal file
View file

@ -0,0 +1,264 @@
#ifndef TURBO_LUT_H
#define TURBO_LUT_H
static const unsigned char turbo_name[] = "Turbo";
static const unsigned char turbo[256][3] = {
{48, 18, 59},
{49, 21, 66},
{51, 24, 74},
{52, 27, 81},
{53, 30, 88},
{54, 33, 95},
{55, 36, 102},
{56, 38, 108},
{57, 41, 115},
{58, 44, 121},
{59, 47, 128},
{60, 50, 134},
{61, 53, 139},
{62, 56, 145},
{62, 58, 151},
{63, 61, 156},
{64, 64, 162},
{64, 67, 167},
{65, 70, 172},
{66, 72, 177},
{66, 75, 182},
{67, 78, 186},
{67, 81, 191},
{68, 83, 195},
{68, 86, 199},
{69, 89, 203},
{69, 91, 207},
{69, 94, 211},
{69, 97, 215},
{70, 99, 218},
{70, 102, 221},
{70, 105, 225},
{70, 107, 228},
{70, 110, 231},
{70, 113, 233},
{70, 115, 236},
{70, 118, 238},
{70, 120, 241},
{70, 123, 243},
{70, 125, 245},
{70, 128, 247},
{70, 130, 249},
{70, 133, 250},
{69, 135, 252},
{69, 138, 253},
{68, 140, 254},
{68, 143, 254},
{67, 145, 255},
{66, 148, 255},
{65, 150, 255},
{63, 153, 255},
{62, 155, 255},
{61, 158, 254},
{59, 161, 253},
{58, 163, 253},
{56, 166, 251},
{54, 168, 250},
{53, 171, 249},
{51, 173, 247},
{49, 176, 246},
{47, 178, 244},
{45, 181, 242},
{44, 183, 240},
{42, 185, 238},
{40, 188, 236},
{38, 190, 234},
{37, 192, 231},
{35, 195, 229},
{33, 197, 226},
{32, 199, 224},
{31, 201, 221},
{29, 204, 219},
{28, 206, 216},
{27, 208, 213},
{26, 210, 211},
{25, 212, 208},
{24, 214, 205},
{24, 216, 203},
{24, 218, 200},
{23, 219, 197},
{23, 221, 195},
{23, 223, 192},
{24, 224, 190},
{24, 226, 187},
{25, 227, 185},
{26, 229, 183},
{27, 230, 180},
{29, 232, 178},
{30, 233, 175},
{32, 234, 173},
{34, 236, 170},
{36, 237, 167},
{39, 238, 164},
{41, 239, 161},
{44, 240, 158},
{47, 241, 155},
{50, 242, 152},
{53, 243, 148},
{56, 244, 145},
{60, 245, 142},
{63, 246, 139},
{67, 247, 135},
{70, 248, 132},
{74, 249, 128},
{78, 250, 125},
{81, 250, 121},
{85, 251, 118},
{89, 252, 115},
{93, 252, 111},
{97, 253, 108},
{101, 253, 105},
{105, 254, 101},
{109, 254, 98},
{113, 254, 95},
{117, 255, 92},
{121, 255, 89},
{125, 255, 86},
{128, 255, 83},
{132, 255, 80},
{136, 255, 78},
{139, 255, 75},
{143, 255, 73},
{146, 255, 70},
{150, 255, 68},
{153, 255, 66},
{156, 254, 64},
{159, 254, 62},
{162, 253, 61},
{164, 253, 59},
{167, 252, 58},
{170, 252, 57},
{172, 251, 56},
{175, 250, 55},
{177, 249, 54},
{180, 248, 53},
{183, 248, 53},
{185, 246, 52},
{188, 245, 52},
{191, 244, 52},
{193, 243, 52},
{196, 242, 51},
{198, 240, 51},
{201, 239, 52},
{203, 238, 52},
{206, 236, 52},
{208, 235, 52},
{210, 233, 52},
{213, 232, 53},
{215, 230, 53},
{217, 228, 53},
{219, 226, 54},
{221, 225, 54},
{224, 223, 55},
{226, 221, 55},
{228, 219, 56},
{230, 217, 56},
{231, 215, 56},
{233, 213, 57},
{235, 211, 57},
{237, 209, 57},
{238, 207, 58},
{240, 205, 58},
{241, 203, 58},
{243, 201, 58},
{244, 199, 58},
{245, 197, 58},
{247, 195, 58},
{248, 193, 58},
{249, 191, 57},
{250, 189, 57},
{250, 186, 56},
{251, 184, 56},
{252, 182, 55},
{252, 180, 54},
{253, 177, 53},
{253, 175, 53},
{254, 172, 52},
{254, 169, 51},
{254, 167, 50},
{254, 164, 49},
{255, 161, 47},
{255, 158, 46},
{255, 156, 45},
{255, 153, 44},
{254, 150, 43},
{254, 147, 42},
{254, 144, 40},
{254, 141, 39},
{253, 138, 38},
{253, 135, 36},
{252, 132, 35},
{252, 129, 34},
{251, 126, 32},
{251, 123, 31},
{250, 120, 30},
{249, 117, 28},
{248, 114, 27},
{248, 111, 26},
{247, 108, 25},
{246, 105, 23},
{245, 102, 22},
{244, 99, 21},
{243, 96, 20},
{242, 93, 19},
{240, 91, 17},
{239, 88, 16},
{238, 85, 15},
{237, 83, 14},
{235, 80, 14},
{234, 78, 13},
{233, 75, 12},
{231, 73, 11},
{230, 71, 10},
{228, 69, 10},
{227, 66, 9},
{225, 64, 9},
{223, 62, 8},
{222, 60, 7},
{220, 58, 7},
{218, 56, 6},
{216, 54, 6},
{214, 52, 5},
{212, 50, 5},
{210, 49, 5},
{208, 47, 4},
{206, 45, 4},
{204, 43, 3},
{202, 41, 3},
{200, 40, 3},
{198, 38, 2},
{195, 36, 2},
{193, 35, 2},
{191, 33, 2},
{188, 31, 1},
{186, 30, 1},
{183, 28, 1},
{180, 27, 1},
{178, 25, 1},
{175, 24, 1},
{172, 22, 1},
{170, 21, 1},
{167, 20, 1},
{164, 18, 1},
{161, 17, 1},
{158, 16, 1},
{155, 15, 1},
{152, 13, 1},
{149, 12, 1},
{146, 11, 1},
{142, 10, 1},
{139, 9, 1},
{136, 8, 1},
{133, 7, 1},
{129, 6, 2},
{126, 5, 2},
{122, 4, 2},
};
#endif // TURBO_LUT_H

View file

@ -0,0 +1,264 @@
#ifndef VIRIDIS_LUT_H
#define VIRIDIS_LUT_H
static const unsigned char viridis_name[] = "Viridis";
static const unsigned char viridis[256][3] = {
{68, 1, 84},
{68, 2, 85},
{69, 3, 87},
{69, 5, 88},
{69, 6, 90},
{70, 8, 91},
{70, 9, 93},
{70, 11, 94},
{70, 12, 96},
{71, 14, 97},
{71, 15, 98},
{71, 17, 100},
{71, 18, 101},
{71, 20, 102},
{72, 21, 104},
{72, 22, 105},
{72, 24, 106},
{72, 25, 108},
{72, 26, 109},
{72, 28, 110},
{72, 29, 111},
{72, 30, 112},
{72, 32, 113},
{72, 33, 115},
{72, 34, 116},
{72, 36, 117},
{72, 37, 118},
{72, 38, 119},
{72, 39, 120},
{71, 41, 121},
{71, 42, 121},
{71, 43, 122},
{71, 44, 123},
{71, 46, 124},
{70, 47, 125},
{70, 48, 126},
{70, 49, 126},
{70, 51, 127},
{69, 52, 128},
{69, 53, 129},
{69, 54, 129},
{68, 56, 130},
{68, 57, 131},
{68, 58, 131},
{67, 59, 132},
{67, 60, 132},
{67, 62, 133},
{66, 63, 133},
{66, 64, 134},
{65, 65, 134},
{65, 66, 135},
{65, 67, 135},
{64, 69, 136},
{64, 70, 136},
{63, 71, 136},
{63, 72, 137},
{62, 73, 137},
{62, 74, 137},
{61, 75, 138},
{61, 77, 138},
{60, 78, 138},
{60, 79, 138},
{59, 80, 139},
{59, 81, 139},
{58, 82, 139},
{58, 83, 139},
{57, 84, 140},
{57, 85, 140},
{56, 86, 140},
{56, 87, 140},
{55, 88, 140},
{55, 89, 140},
{54, 91, 141},
{54, 92, 141},
{53, 93, 141},
{53, 94, 141},
{52, 95, 141},
{52, 96, 141},
{51, 97, 141},
{51, 98, 141},
{51, 99, 141},
{50, 100, 142},
{50, 101, 142},
{49, 102, 142},
{49, 103, 142},
{48, 104, 142},
{48, 105, 142},
{47, 106, 142},
{47, 107, 142},
{47, 108, 142},
{46, 109, 142},
{46, 110, 142},
{45, 111, 142},
{45, 112, 142},
{45, 112, 142},
{44, 113, 142},
{44, 114, 142},
{43, 115, 142},
{43, 116, 142},
{43, 117, 142},
{42, 118, 142},
{42, 119, 142},
{41, 120, 142},
{41, 121, 142},
{41, 122, 142},
{40, 123, 142},
{40, 124, 142},
{40, 125, 142},
{39, 126, 142},
{39, 127, 142},
{38, 128, 142},
{38, 129, 142},
{38, 130, 142},
{37, 131, 142},
{37, 131, 142},
{37, 132, 142},
{36, 133, 142},
{36, 134, 142},
{35, 135, 142},
{35, 136, 142},
{35, 137, 142},
{34, 138, 141},
{34, 139, 141},
{34, 140, 141},
{33, 141, 141},
{33, 142, 141},
{33, 143, 141},
{32, 144, 141},
{32, 145, 140},
{32, 146, 140},
{32, 147, 140},
{31, 147, 140},
{31, 148, 140},
{31, 149, 139},
{31, 150, 139},
{31, 151, 139},
{30, 152, 139},
{30, 153, 138},
{30, 154, 138},
{30, 155, 138},
{30, 156, 137},
{30, 157, 137},
{30, 158, 137},
{30, 159, 136},
{30, 160, 136},
{31, 161, 136},
{31, 162, 135},
{31, 163, 135},
{31, 163, 134},
{32, 164, 134},
{32, 165, 134},
{33, 166, 133},
{33, 167, 133},
{34, 168, 132},
{35, 169, 131},
{35, 170, 131},
{36, 171, 130},
{37, 172, 130},
{38, 173, 129},
{39, 174, 129},
{40, 175, 128},
{41, 175, 127},
{42, 176, 127},
{43, 177, 126},
{44, 178, 125},
{46, 179, 124},
{47, 180, 124},
{48, 181, 123},
{50, 182, 122},
{51, 183, 121},
{53, 183, 121},
{54, 184, 120},
{56, 185, 119},
{57, 186, 118},
{59, 187, 117},
{61, 188, 116},
{62, 189, 115},
{64, 190, 114},
{66, 190, 113},
{68, 191, 112},
{70, 192, 111},
{72, 193, 110},
{73, 194, 109},
{75, 194, 108},
{77, 195, 107},
{79, 196, 106},
{81, 197, 105},
{83, 198, 104},
{85, 198, 102},
{88, 199, 101},
{90, 200, 100},
{92, 201, 99},
{94, 201, 98},
{96, 202, 96},
{98, 203, 95},
{101, 204, 94},
{103, 204, 92},
{105, 205, 91},
{108, 206, 90},
{110, 206, 88},
{112, 207, 87},
{115, 208, 85},
{117, 208, 84},
{119, 209, 82},
{122, 210, 81},
{124, 210, 79},
{127, 211, 78},
{129, 212, 76},
{132, 212, 75},
{134, 213, 73},
{137, 213, 72},
{139, 214, 70},
{142, 215, 68},
{144, 215, 67},
{147, 216, 65},
{149, 216, 63},
{152, 217, 62},
{155, 217, 60},
{157, 218, 58},
{160, 218, 57},
{163, 219, 55},
{165, 219, 53},
{168, 220, 51},
{171, 220, 50},
{173, 221, 48},
{176, 221, 46},
{179, 221, 45},
{181, 222, 43},
{184, 222, 41},
{187, 223, 39},
{189, 223, 38},
{192, 223, 36},
{195, 224, 35},
{197, 224, 33},
{200, 225, 32},
{203, 225, 30},
{205, 225, 29},
{208, 226, 28},
{211, 226, 27},
{213, 226, 26},
{216, 227, 25},
{219, 227, 24},
{221, 227, 24},
{224, 228, 24},
{226, 228, 24},
{229, 228, 24},
{232, 229, 25},
{234, 229, 25},
{237, 229, 26},
{239, 230, 27},
{242, 230, 28},
{244, 230, 30},
{247, 230, 31},
{249, 231, 33},
{251, 231, 35},
{254, 231, 36},
};
#endif // VIRIDIS_LUT_H

65
src/input.c Normal file
View file

@ -0,0 +1,65 @@
#include "input.h"
#include "mandelbrot.h"
#include <GLFW/glfw3.h>
void processInput(GLFWwindow *window, double *zoom, double *offsetX,
double *offsetY) {
if (glfwGetKey(window, GLFW_KEY_0) == GLFW_PRESS) {
set_palette(VIRIDIS_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS) {
set_palette(CUBEHELIX_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS) {
set_palette(HSV_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS) {
set_palette(INFERNO_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS) {
set_palette(MAGMA_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_5) == GLFW_PRESS) {
set_palette(PARULA_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_6) == GLFW_PRESS) {
set_palette(PASTEL_RAINBOW_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_7) == GLFW_PRESS) {
set_palette(PLASMA_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_8) == GLFW_PRESS) {
set_palette(TURBO_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_9) == GLFW_PRESS) {
set_palette(CIVIDIS_LUT_COLOR);
}
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
*offsetY += 0.11 / *zoom;
}
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
*offsetY -= 0.11 / *zoom;
}
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
*offsetX -= 0.11 / *zoom;
}
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
*offsetX += 0.11 / *zoom;
}
if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) {
*zoom = 1.0;
*offsetX = -0.75;
*offsetY = 0.0;
}
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
*zoom *= 1.07;
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
*zoom /= 1.08;
}
}

8
src/input.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef INPUT_H
#define INPUT_H
#include <GLFW/glfw3.h>
void processInput(GLFWwindow *window, double *zoom, double *offsetX, double *offsetY);
#endif

233
src/main.c Normal file
View file

@ -0,0 +1,233 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <time.h>
#define STB_EASY_FONT_IMPLEMENTATION
#include "stb_easy_font.h"
#include "input.h"
#include "mandelbrot.h"
#include "mandelbrot_opencl_kernels.h"
#include "render.h"
#define WINDOW_WIDTH 960
#define WINDOW_HEIGHT 540
// Global variables for zoom and offsets
double zoom = 1.0;
double offsetX = -0.75;
double offsetY = 0.0;
// Mouse state for panning
bool isMouseDragging = false;
double lastMouseX = 0, lastMouseY = 0;
double lastTime = 0.0;
int frameCount = 0;
double currentFPS = 0.0;
double targetFrameTime = 1.0 / 10.0; // Target 30 FPS
// Mouse scroll callback for zooming
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
// Zoom in or out depending on the scroll direction
if (yoffset > 0) {
zoom *= 1.1; // Zoom in (increase resolution)
} else {
zoom /= 1.1; // Zoom out (decrease resolution)
}
// Clamp zoom to a reasonable range to avoid excessive zooming
if (zoom < 0.1)
zoom = 0.1; // Minimum zoom limit
if (zoom > 10000)
zoom = 10000; // Maximum zoom limit
}
// Mouse button callback for panning
void mouse_button_callback(GLFWwindow *window, int button, int action,
int mods) {
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if (action == GLFW_PRESS) {
isMouseDragging = true;
glfwGetCursorPos(window, &lastMouseX, &lastMouseY);
} else if (action == GLFW_RELEASE) {
isMouseDragging = false;
}
}
}
// Mouse motion callback for panning
void cursor_pos_callback(GLFWwindow *window, double xpos, double ypos) {
if (isMouseDragging) {
double dx = xpos - lastMouseX;
double dy = ypos - lastMouseY;
// Base pan factor for adjusting sensitivity
double basePanFactor = 0.01; // Base pan factor for small movements
// Apply logarithmic scaling to pan factor based on zoom level
// We reduce the pan factor more gradually at high zoom levels
double zoomAdjustedFactor =
basePanFactor / log(zoom * 100.0); // Logarithmic scaling with zoom
// Clamp pan factor to avoid excessive movement or tiny shifts
zoomAdjustedFactor = fmin(fmax(zoomAdjustedFactor, 0.0001),
0.0001); // Limit sensitivity range
// Update offsets based on mouse movement with the adjusted sensitivity
offsetX -= dx * zoomAdjustedFactor; // Horizontal pan
offsetY += dy * zoomAdjustedFactor; // Vertical pan
lastMouseX = xpos;
lastMouseY = ypos;
}
}
void drawText(const char *text, const float x, const float y) {
char buffer[99999]; // ~500 chars
glColor3f(1.0f, 1.0f, 1.0f); // White text
glEnableClientState(GL_VERTEX_ARRAY);
const int num_quads =
stb_easy_font_print(x, y, (char *)text, NULL, buffer, sizeof(buffer));
glVertexPointer(2, GL_FLOAT, 16, buffer);
glDrawArrays(GL_QUADS, 0, num_quads * 4);
glDisableClientState(GL_VERTEX_ARRAY);
}
int main() {
opencl_kernel_manager_init();
double frameDuration = 0.0;
if (!glfwInit()) {
return -1;
}
GLFWwindow *window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT,
"Mandelbrot Renderer", NULL, NULL);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Set up input callbacks
glfwSetScrollCallback(window, scroll_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetCursorPosCallback(window, cursor_pos_callback);
glfwSwapInterval(1); // Enable vsync
// Initialize OpenGL context (GLEW)
if (glewInit() != GLEW_OK) {
printf("GLEW initialization failed.\n");
return -1;
}
// SuperSample setup
GLuint fbo, highResTexture;
const int scaleFactor = 2; // Render at 2x
const int highW = WINDOW_WIDTH * scaleFactor;
const int highH = WINDOW_HEIGHT * scaleFactor;
glGenTextures(1, &highResTexture);
glBindTexture(GL_TEXTURE_2D, highResTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, highW, highH, 0, GL_RGB,
GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
highResTexture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
printf("Framebuffer not complete.\n");
return -1;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Main rendering loop
unsigned char *image = malloc(highW * highH * 3);
while (!glfwWindowShouldClose(window)) {
const double currentTime =
glfwGetTime(); // glfwGetTime() returns seconds as double
frameCount++;
// If 1 second has passed, update FPS
if (currentTime - lastTime >= 1.0) {
currentFPS = frameCount / (currentTime - lastTime);
lastTime = currentTime;
frameCount = 0;
}
// Poll for events and handle input
processInput(window, &zoom, &offsetX, &offsetY);
// Clear screen
glClear(GL_COLOR_BUFFER_BIT);
// Render Mandelbrot set, passing the window as an argument
renderMandelbrot(window, zoom, offsetX, offsetY, image, highResTexture,
scaleFactor, fbo);
char info[256];
snprintf(info, sizeof(info),
"Zoom: %.6e\nOffset: (%.6e, %.6e)\nFPS: %.1f\nFrame Time: %.2f "
"ms\nPalette: %s",
zoom, offsetX, offsetY, currentFPS, frameDuration * 1000.0,
get_palette_name());
// Set orthographic projection for 2D text
int winW, winH;
glfwGetFramebufferSize(window, &winW, &winH);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, winW, winH, 0, -1, 1); // Top-left = (0,0)
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Draw the text
drawText(info, 10, 10);
// Restore previous matrices
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
const double frameEndTime = glfwGetTime();
frameDuration = frameEndTime - currentTime;
if (frameDuration < targetFrameTime) {
const double sleepTime = targetFrameTime - frameDuration;
struct timespec ts;
ts.tv_sec = (time_t)sleepTime;
ts.tv_nsec = (long)((sleepTime - ts.tv_sec) * 1e9);
nanosleep(&ts, NULL);
}
}
free(image);
glfwDestroyWindow(window);
glfwTerminate();
opencl_kernel_manager_shutdown();
return 0;
}

382
src/mandelbrot.c Normal file
View file

@ -0,0 +1,382 @@
#include <immintrin.h>
#include <math.h>
#include <stdio.h>
#include "mandelbrot.h"
#include "colourmaps/colourmaps.h"
#include "mandelbrot_opencl_kernels.h"
#define MAX_ITERATIONS 10000 // Increase iterations for more detail
#define VEC_SIZE 8 // AVX2 vector size
static double colorShift = 0.0;
static const unsigned char (*activePalette)[256][3] = &viridis;
static colourmap_type currentPalette = VIRIDIS_LUT_COLOR;
const char *get_palette_name() {
switch (currentPalette) {
case VIRIDIS_LUT_COLOR:
return (const char *)viridis_name;
case CUBEHELIX_LUT_COLOR:
return (const char *)cubehelix_name;
case CIVIDIS_LUT_COLOR:
return (const char *)cividis_name;
case HSV_LUT_COLOR:
return (const char *)hsv_name;
case INFERNO_LUT_COLOR:
return (const char *)inferno_name;
case MAGMA_LUT_COLOR:
return (const char *)magma_name;
case PARULA_LUT_COLOR:
return (const char *)parula_name;
case PASTEL_RAINBOW_LUT_COLOR:
return (const char *)pastel_rainbow_name;
case PLASMA_LUT_COLOR:
return (const char *)plasma_name;
case TURBO_LUT_COLOR:
return (const char *)turbo_name;
}
}
void set_palette(const colourmap_type choice) {
currentPalette = choice;
switch (choice) {
case CIVIDIS_LUT_COLOR:
activePalette = &cividis;
break;
case CUBEHELIX_LUT_COLOR:
activePalette = &cubehelix;
break;
case HSV_LUT_COLOR:
activePalette = &hsv;
break;
case INFERNO_LUT_COLOR:
activePalette = &inferno;
break;
case MAGMA_LUT_COLOR:
activePalette = &magma;
break;
case PARULA_LUT_COLOR:
activePalette = &parula;
break;
case PASTEL_RAINBOW_LUT_COLOR:
activePalette = &pastel_rainbow;
break;
case PLASMA_LUT_COLOR:
activePalette = &plasma;
break;
case TURBO_LUT_COLOR:
activePalette = &turbo;
break;
case VIRIDIS_LUT_COLOR:
activePalette = &viridis;
break;
default:
activePalette = &viridis;
break;
}
}
void mandelbrot_long_double(const long double zoom, const long double offsetX,
const long double offsetY, const int width,
const int height, const int maxIterations,
unsigned char *restrict image) {
const long double scale = 3.0L / zoom;
const long double invW = 1.0L / width;
const long double invH = 1.0L / height;
const long double baseReal = -0.5L * scale + offsetX;
const long double baseImag = -0.5L * scale + offsetY;
#pragma omp parallel for schedule(dynamic)
for (int py = 0; py < height; py++) {
long double imagPart = py * invH * scale + baseImag;
#pragma omp simd
for (int px = 0; px < width; px++) {
long double realPart = px * invW * scale + baseReal;
long double real = realPart;
long double imag = imagPart;
int iteration = 0;
while (iteration < maxIterations) {
long double realSquared = real * real;
long double imagSquared = imag * imag;
if (realSquared + imagSquared > 4.0L)
break;
long double tempReal = realSquared - imagSquared + realPart;
imag = 2.0L * real * imag + imagPart;
real = tempReal;
iteration++;
}
int i = (py * width + px) * 3;
if (iteration == maxIterations) {
image[i + 0] = 0;
image[i + 1] = 0;
image[i + 2] = 0;
} else {
image[i + 0] = (*activePalette)[iteration][0];
image[i + 1] = (*activePalette)[iteration][1];
image[i + 2] = (*activePalette)[iteration][2];
}
}
}
}
static inline __m256d fast_log2_avx2(__m256d x) {
__m256i xi = _mm256_castpd_si256(x);
xi = _mm256_srli_epi64(xi, 52);
__m256d exp = _mm256_cvtepi64_pd(xi);
exp = _mm256_sub_pd(exp, _mm256_set1_pd(1023.0));
return exp;
}
void mandelbrot_avx2(const double zoom, const double offsetX,
const double offsetY, const int width, const int height,
const int maxIterations, unsigned char *restrict image) {
const double scale = 3.0 / zoom;
const double invW = 1.0 / width;
const double invH = 1.0 / height;
const double scaledInvW = invW * scale;
const double offsetReal = offsetX - 0.5 * scale;
#pragma omp parallel for
for (int py = 0; py < height; py++) {
const double y0 = ((double)py * invH - 0.5) * scale + offsetY;
for (int px = 0; px < width; px += VEC_SIZE) {
__m256d x_pixel = _mm256_set_pd(px + 3, px + 2, px + 1, px);
__m256d x0 = _mm256_fmadd_pd(x_pixel, _mm256_set1_pd(scaledInvW),
_mm256_set1_pd(offsetReal));
__m256d y0v = _mm256_set1_pd(y0);
__m256d x = x0;
__m256d y = y0v;
__m256d iter = _mm256_setzero_pd();
const __m256d two = _mm256_set1_pd(2.0);
const __m256d four = _mm256_set1_pd(4.0);
for (int i = 0; i < maxIterations; i++) {
__m256d x2 = _mm256_mul_pd(x, x);
__m256d y2 = _mm256_mul_pd(y, y);
__m256d xy = _mm256_mul_pd(x, y);
__m256d mag2 = _mm256_add_pd(x2, y2);
__m256d mask = _mm256_cmp_pd(mag2, four, _CMP_LT_OQ);
if (_mm256_movemask_pd(mask) == 0)
break;
x = _mm256_add_pd(_mm256_sub_pd(x2, y2), x0);
y = _mm256_fmadd_pd(two, xy, y0v);
iter = _mm256_add_pd(iter, _mm256_and_pd(mask, _mm256_set1_pd(1.0)));
}
__m256d final_iter = iter;
__m256d x2 = _mm256_mul_pd(x, x);
__m256d y2 = _mm256_mul_pd(y, y);
__m256d zn = _mm256_add_pd(x2, y2);
__m256d log2_zn = fast_log2_avx2(zn);
__m256d log_zn = _mm256_mul_pd(log2_zn, _mm256_set1_pd(log(2.0) / 2.0));
__m256d log2_logzn = fast_log2_avx2(log_zn);
__m256d nu = _mm256_div_pd(log2_logzn, _mm256_set1_pd(log(2.0)));
__m256d smooth =
_mm256_sub_pd(_mm256_add_pd(final_iter, _mm256_set1_pd(1.0)), nu);
__m256d t = _mm256_div_pd(smooth, _mm256_set1_pd((double)maxIterations));
double smooth_vals[VEC_SIZE];
double iter_vals[VEC_SIZE];
_mm256_storeu_pd(smooth_vals, t);
_mm256_storeu_pd(iter_vals, final_iter);
for (int i = 0; i < VEC_SIZE; i++) {
int offset = ((py * width) + (px + i)) * 3;
if ((int)iter_vals[i] >= maxIterations) {
image[offset + 0] = 0;
image[offset + 1] = 0;
image[offset + 2] = 0;
} else {
double t_shifted = fmod(smooth_vals[i] + colorShift, 1.0);
int idx = (int)(t_shifted * 255.0);
if (idx < 0)
idx = 0;
if (idx > 255)
idx = 255;
image[offset + 0] = viridis[idx][0];
image[offset + 1] = viridis[idx][1];
image[offset + 2] = viridis[idx][2];
}
}
}
}
}
__m512d fast_log2_avx512(__m512d x) {
__m512i xi = _mm512_castpd_si512(x);
xi = _mm512_srli_epi64(xi, 52);
__m512d exp = _mm512_cvtepi64_pd(xi);
exp = _mm512_sub_pd(exp, _mm512_set1_pd(1023.0));
return exp;
}
void mandelbrot_avx512(const double zoom, const double offsetX,
const double offsetY, const int width, const int height,
const int maxIterations, unsigned char *restrict image) {
const double scale = 3.0 / zoom;
const double invW = 1.0 / width;
const double invH = 1.0 / height;
const double scaledInvW = invW * scale;
const double offsetReal = offsetX - 0.5 * scale;
#pragma omp parallel for
for (int py = 0; py < height; py++) {
const double y0 = ((double)py * invH - 0.5) * scale + offsetY;
for (int px = 0; px < width; px += VEC_SIZE) {
const __m512d x_pixel = _mm512_set_pd(px + 7, px + 6, px + 5, px + 4,
px + 3, px + 2, px + 1, px);
const __m512d x0 = _mm512_fmadd_pd(x_pixel, _mm512_set1_pd(scaledInvW),
_mm512_set1_pd(offsetReal));
const __m512d y0v = _mm512_set1_pd(y0);
__m512d x = x0;
__m512d y = y0v;
__m512d iter = _mm512_setzero_pd();
const __m512d two = _mm512_set1_pd(2.0);
const __m512d four = _mm512_set1_pd(4.0);
for (int i = 0; i < maxIterations; i++) {
const __m512d x2 = _mm512_mul_pd(x, x);
const __m512d y2 = _mm512_mul_pd(y, y);
const __m512d xy = _mm512_mul_pd(x, y);
const __m512d mag2 = _mm512_add_pd(x2, y2);
const __mmask8 mask = _mm512_cmp_pd_mask(mag2, four, _CMP_LT_OQ);
if (mask == 0)
break;
x = _mm512_add_pd(_mm512_sub_pd(x2, y2), x0);
y = _mm512_fmadd_pd(two, xy, y0v);
iter = _mm512_mask_add_pd(iter, mask, iter, _mm512_set1_pd(1.0));
}
const __m512d final_iter = iter;
const __m512d x2 = _mm512_mul_pd(x, x);
const __m512d y2 = _mm512_mul_pd(y, y);
const __m512d zn = _mm512_add_pd(x2, y2);
const __m512d log2_zn = fast_log2_avx512(zn);
const __m512d log_zn =
_mm512_mul_pd(log2_zn, _mm512_set1_pd(log(2.0) / 2.0));
const __m512d log2_logzn = fast_log2_avx512(log_zn);
const __m512d nu = _mm512_div_pd(log2_logzn, _mm512_set1_pd(log(2.0)));
const __m512d smooth =
_mm512_sub_pd(_mm512_add_pd(final_iter, _mm512_set1_pd(1.0)), nu);
const __m512d t =
_mm512_div_pd(smooth, _mm512_set1_pd((double)maxIterations));
double smooth_vals[VEC_SIZE];
double iter_vals[VEC_SIZE];
_mm512_storeu_pd(smooth_vals, t);
_mm512_storeu_pd(iter_vals, final_iter);
for (int i = 0; i < VEC_SIZE; i++) {
const int offset = ((py * width) + (px + i)) * 3;
if ((int)iter_vals[i] >= maxIterations) {
image[offset + 0] = 0;
image[offset + 1] = 0;
image[offset + 2] = 0;
} else {
const double t_shifted = fmod(smooth_vals[i] + colorShift, 1.0);
const double ft = t_shifted * 255.0;
int idx = (int)ft;
const double frac = ft - idx;
if (idx < 0)
idx = 0;
if (idx >= 255)
idx = 254;
for (int ch = 0; ch < 3; ++ch) {
image[offset + ch] =
(unsigned char)((1.0 - frac) * (*activePalette)[idx][ch] +
frac * (*activePalette)[idx + 1][ch]);
}
}
}
}
}
}
int computeMaxIterations(const long double zoom) {
const int baseIterations = 150;
const double growthRate = 150.0; // How fast it grows
int dynamicMax = (int)(baseIterations + log2l(zoom) * growthRate);
// Clamp to reasonable bounds
if (dynamicMax < baseIterations)
dynamicMax = baseIterations;
if (dynamicMax > MAX_ITERATIONS)
dynamicMax = MAX_ITERATIONS;
return dynamicMax;
}
// OpenCL standard (double) Mandelbrot call
void mandelbrot_opencl_standard(const double zoom, const double offsetX,
const double offsetY, const int width,
const int height, int maxIterations,
unsigned char *restrict image) {
launch_opencl_kernel("mandelbrot_kernel", zoom, offsetX, offsetY, width,
height, maxIterations, image);
}
// OpenCL double-double Mandelbrot call
void mandelbrot_opencl_double_double(const double zoom, const double offsetX,
const double offsetY, const int width,
const int height, int maxIterations,
unsigned char *restrict image) {
launch_opencl_kernel("mandelbrot_kernel_dd", zoom, offsetX, offsetY, width,
height, maxIterations, image);
}
void mandelbrot(const long double zoom, const long double offsetX,
const long double offsetY, const int width, const int height,
unsigned char *restrict image) {
colorShift += 0.0005; // Slow shift
if (colorShift > 0.9)
colorShift -= 0.9;
const int dynamicIterations = computeMaxIterations(zoom);
#ifdef USE_OPENCL
if (zoom < 1e12)
mandelbrot_opencl_standard(zoom, offsetX, offsetY, width, height,
dynamicIterations, image);
else
mandelbrot_opencl_double_double(zoom, offsetX, offsetY, width, height,
dynamicIterations, image);
#else
if (zoom < 1e14)
mandelbrot_avx512(zoom, offsetX, offsetY, width, height, dynamicIterations,
image);
else
mandelbrot_long_double(zoom, offsetX, offsetY, width, height,
dynamicIterations, image);
#endif
}

12
src/mandelbrot.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef MANDELBROT_H
#define MANDELBROT_H
#include "colourmaps/colourmaps.h"
void set_palette(colourmap_type choice);
const char* get_palette_name();
void mandelbrot(long double zoom, long double offsetX, long double offsetY, int width, int height,
unsigned char* restrict image);
#endif

174
src/mandelbrot_kernel.cl Normal file
View file

@ -0,0 +1,174 @@
__kernel void mandelbrot_kernel(
__global uchar *output,
const double zoom,
const double offsetX,
const double offsetY,
const int width,
const int height,
const int maxIterations
)
{
const int px = get_global_id(0);
const int py = get_global_id(1);
if (px >= width || py >= height)
return;
const double scale = 3.0 / zoom;
const double real0 = ((double)px / width - 0.5) * scale + offsetX;
const double imag0 = ((double)py / height - 0.5) * scale + offsetY;
double real = real0;
double imag = imag0;
int iteration = 0;
while (real*real + imag*imag <= 4.0 && iteration < maxIterations)
{
double realTemp = real * real - imag * imag + real0;
imag = 2.0 * real * imag + imag0;
real = realTemp;
iteration++;
}
const int idx = (py * width + px) * 3;
if (iteration == maxIterations) {
output[idx + 0] = 0;
output[idx + 1] = 0;
output[idx + 2] = 0;
} else {
float t = (float)iteration / (float)maxIterations;
output[idx + 0] = (uchar)(9.0f * (1.0f - t) * t * t * t * 255.0f);
output[idx + 1] = (uchar)(15.0f * (1.0f - t) * (1.0f - t) * t * t * 255.0f);
output[idx + 2] = (uchar)(8.5f * (1.0f - t) * (1.0f - t) * (1.0f - t) * t * 255.0f);
}
}
// Double Double
typedef struct {
double hi;
double lo;
} dd_real;
inline dd_real dd_add(dd_real a, dd_real b)
{
double s = a.hi + b.hi;
double v = s - a.hi;
double t = ((b.hi - v) + (a.hi - (s - v))) + a.lo + b.lo;
dd_real result;
result.hi = s + t;
result.lo = t - (result.hi - s);
return result;
}
inline dd_real dd_sub(dd_real a, dd_real b)
{
double s = a.hi - b.hi;
double v = s - a.hi;
double t = ((-b.hi - v) + (a.hi - (s - v))) + a.lo - b.lo;
dd_real result;
result.hi = s + t;
result.lo = t - (result.hi - s);
return result;
}
inline dd_real dd_mul(dd_real a, dd_real b)
{
const double split = 134217729.0; // 2^27 + 1
double cona = a.hi * split;
double conb = b.hi * split;
double a1 = cona - (cona - a.hi);
double b1 = conb - (conb - b.hi);
double a2 = a.hi - a1;
double b2 = b.hi - b1;
double c11 = a.hi * b.hi;
double c21 = a2 * b2 - (((c11 - a1 * b1) - a2 * b1) - a1 * b2);
double c2 = a.hi * b.lo + a.lo * b.hi;
double t1 = c11 + c2;
double e = t1 - c11;
double t2 = ((c2 - e) + (c11 - (t1 - e))) + c21 + a.lo * b.lo;
dd_real result;
result.hi = t1 + t2;
result.lo = t2 - (result.hi - t1);
return result;
}
inline dd_real dd_sqr(dd_real a)
{
return dd_mul(a, a);
}
inline double dd_mag2(dd_real a, dd_real b)
{
double r = a.hi * a.hi + b.hi * b.hi;
return r;
}
__kernel void mandelbrot_kernel_dd(
__global uchar *output,
const double zoom,
const double offsetX,
const double offsetY,
const int width,
const int height,
const int maxIterations
)
{
const int px = get_global_id(0);
const int py = get_global_id(1);
if (px >= width || py >= height)
return;
const double scale = 3.0 / zoom;
const double centerReal = offsetX;
const double centerImag = offsetY;
dd_real real0;
real0.hi = ((double)px / width - 0.5) * scale + centerReal;
real0.lo = 0.0;
dd_real imag0;
imag0.hi = ((double)py / height - 0.5) * scale + centerImag;
imag0.lo = 0.0;
dd_real real = real0;
dd_real imag = imag0;
int iteration = 0;
while (dd_mag2(real, imag) <= 4.0 && iteration < maxIterations)
{
dd_real realSq = dd_sqr(real);
dd_real imagSq = dd_sqr(imag);
dd_real realTemp = dd_add(dd_sub(realSq, imagSq), real0);
dd_real two;
two.hi = 2.0;
two.lo = 0.0;
dd_real realImag = dd_mul(real, imag);
imag = dd_add(dd_mul(two, realImag), imag0);
real = realTemp;
iteration++;
}
const int idx = (py * width + px) * 3;
if (iteration == maxIterations) {
output[idx + 0] = 0;
output[idx + 1] = 0;
output[idx + 2] = 0;
} else {
float t = (float)iteration / (float)maxIterations;
output[idx + 0] = (uchar)(9.0f * (1.0f - t) * t * t * t * 255.0f);
output[idx + 1] = (uchar)(15.0f * (1.0f - t) * (1.0f - t) * t * t * 255.0f);
output[idx + 2] = (uchar)(8.5f * (1.0f - t) * (1.0f - t) * (1.0f - t) * t * 255.0f);
}
}

View file

@ -0,0 +1,94 @@
#include <CL/cl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static cl_context context = NULL;
static cl_command_queue queue = NULL;
static cl_program program = NULL;
static cl_device_id device = NULL;
void opencl_kernel_manager_init() {
cl_platform_id platform;
cl_int err;
err = clGetPlatformIDs(1, &platform, NULL);
err |= clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);
context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
queue = clCreateCommandQueueWithProperties(context, device, 0, &err);
// Load source
FILE *f = fopen("mandelbrot_kernel.cl", "rb");
if (!f) {
perror("Failed to open mandelbrot_opencl.cl");
exit(1);
}
fseek(f, 0, SEEK_END);
size_t src_size = ftell(f);
rewind(f);
char *src = (char *)malloc(src_size + 1);
fread(src, 1, src_size, f);
src[src_size] = '\0';
fclose(f);
program =
clCreateProgramWithSource(context, 1, (const char **)&src, NULL, &err);
free(src);
err = clBuildProgram(program, 1, &device, NULL, NULL, NULL);
if (err != CL_SUCCESS) {
size_t log_size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL,
&log_size);
char *log = malloc(log_size);
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, log,
NULL);
printf("CL Build Error:\n%s\n", log);
free(log);
exit(1);
}
}
void opencl_kernel_manager_shutdown() {
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
}
void launch_opencl_kernel(const char *kernel_name, double zoom, double offsetX,
double offsetY, int width, int height,
int maxIterations, unsigned char *restrict image) {
cl_int err;
cl_kernel kernel = clCreateKernel(program, kernel_name, &err);
if (err != CL_SUCCESS) {
printf("Failed to create kernel: %s\n", kernel_name);
exit(1);
}
size_t img_size = width * height * 3;
cl_mem output_buffer =
clCreateBuffer(context, CL_MEM_WRITE_ONLY, img_size, NULL, &err);
err |= clSetKernelArg(kernel, 0, sizeof(cl_mem), &output_buffer);
err |= clSetKernelArg(kernel, 1, sizeof(double), &zoom);
err |= clSetKernelArg(kernel, 2, sizeof(double), &offsetX);
err |= clSetKernelArg(kernel, 3, sizeof(double), &offsetY);
err |= clSetKernelArg(kernel, 4, sizeof(int), &width);
err |= clSetKernelArg(kernel, 5, sizeof(int), &height);
err |= clSetKernelArg(kernel, 6, sizeof(int), &maxIterations);
const size_t global_size[2] = {(size_t)width, (size_t)height};
err |= clEnqueueNDRangeKernel(queue, kernel, 2, NULL, global_size, NULL, 0,
NULL, NULL);
err |= clEnqueueReadBuffer(queue, output_buffer, CL_TRUE, 0, img_size, image,
0, NULL, NULL);
clReleaseMemObject(output_buffer);
clReleaseKernel(kernel);
clFinish(queue);
}

View file

@ -0,0 +1,12 @@
#ifndef MANDELBROT_OPENCL_KERNELS
#define MANDELBROT_OPENCL_KERNELS
void opencl_kernel_manager_init();
void opencl_kernel_manager_shutdown();
void launch_opencl_kernel(const char* kernel_name,
double zoom, double offsetX, double offsetY,
int width, int height, int maxIterations,
unsigned char* restrict image);
#endif

59
src/render.c Normal file
View file

@ -0,0 +1,59 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandelbrot.h"
#include "render.h"
void renderMandelbrot(GLFWwindow *window, const double zoom,
const double offsetX, const double offsetY,
unsigned char *restrict image,
const GLuint highResTexture, const int scaleFactor,
const GLuint fbo) {
int winW, winH;
glfwGetFramebufferSize(window, &winW, &winH);
const int highW = winW * scaleFactor;
const int highH = winH * scaleFactor;
memset(image, 0, highW * highH * 3); // Clear the image buffer
glBindTexture(GL_TEXTURE_2D, highResTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, highW, highH, 0, GL_RGB,
GL_UNSIGNED_BYTE, NULL);
// Generate the Mandelbrot set into the image buffer
mandelbrot(zoom, offsetX, offsetY, highW, highH, image);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, highW, highH);
glClear(GL_COLOR_BUFFER_BIT);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, highW, highH, GL_RGB,
GL_UNSIGNED_BYTE, image);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, highResTexture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, highW, highH, 0, 0, winW, winH, GL_COLOR_BUFFER_BIT,
GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, winW, winH);
}

10
src/render.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef RENDER_H
#define RENDER_H
#include <GLFW/glfw3.h>
// Function to render the Mandelbrot set
void renderMandelbrot(GLFWwindow* window, const double zoom, const double offsetX, const double offsetY,
unsigned char* image, GLuint highResTexture, int scaleFactor, GLuint fbo);
#endif

305
src/stb_easy_font.h Normal file
View file

@ -0,0 +1,305 @@
// stb_easy_font.h - v1.1 - bitmap font for 3D rendering - public domain
// Sean Barrett, Feb 2015
//
// Easy-to-deploy,
// reasonably compact,
// extremely inefficient performance-wise,
// crappy-looking,
// ASCII-only,
// bitmap font for use in 3D APIs.
//
// Intended for when you just want to get some text displaying
// in a 3D app as quickly as possible.
//
// Doesn't use any textures, instead builds characters out of quads.
//
// DOCUMENTATION:
//
// int stb_easy_font_width(char *text)
// int stb_easy_font_height(char *text)
//
// Takes a string and returns the horizontal size and the
// vertical size (which can vary if 'text' has newlines).
//
// int stb_easy_font_print(float x, float y,
// char *text, unsigned char color[4],
// void *vertex_buffer, int vbuf_size)
//
// Takes a string (which can contain '\n') and fills out a
// vertex buffer with renderable data to draw the string.
// Output data assumes increasing x is rightwards, increasing y
// is downwards.
//
// The vertex data is divided into quads, i.e. there are four
// vertices in the vertex buffer for each quad.
//
// The vertices are stored in an interleaved format:
//
// x:float
// y:float
// z:float
// color:uint8[4]
//
// You can ignore z and color if you get them from elsewhere
// This format was chosen in the hopes it would make it
// easier for you to reuse existing vertex-buffer-drawing code.
//
// If you pass in NULL for color, it becomes 255,255,255,255.
//
// Returns the number of quads.
//
// If the buffer isn't large enough, it will truncate.
// Expect it to use an average of ~270 bytes per character.
//
// If your API doesn't draw quads, build a reusable index
// list that allows you to render quads as indexed triangles.
//
// void stb_easy_font_spacing(float spacing)
//
// Use positive values to expand the space between characters,
// and small negative values (no smaller than -1.5) to contract
// the space between characters.
//
// E.g. spacing = 1 adds one "pixel" of spacing between the
// characters. spacing = -1 is reasonable but feels a bit too
// compact to me; -0.5 is a reasonable compromise as long as
// you're scaling the font up.
//
// LICENSE
//
// See end of file for license information.
//
// VERSION HISTORY
//
// (2020-02-02) 1.1 make everything static so can compile it in more than one src file
// (2017-01-15) 1.0 space character takes same space as numbers; fix bad spacing of 'f'
// (2016-01-22) 0.7 width() supports multiline text; add height()
// (2015-09-13) 0.6 #include <math.h>; updated license
// (2015-02-01) 0.5 First release
//
// CONTRIBUTORS
//
// github:vassvik -- bug report
// github:podsvirov -- fix multiple definition errors
#if 0
// SAMPLE CODE:
//
// Here's sample code for old OpenGL; it's a lot more complicated
// to make work on modern APIs, and that's your problem.
//
void print_string(float x, float y, char *text, float r, float g, float b)
{
static char buffer[99999]; // ~500 chars
int num_quads;
num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer));
glColor3f(r,g,b);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 16, buffer);
glDrawArrays(GL_QUADS, 0, num_quads*4);
glDisableClientState(GL_VERTEX_ARRAY);
}
#endif
#ifndef INCLUDE_STB_EASY_FONT_H
#define INCLUDE_STB_EASY_FONT_H
#include <stdlib.h>
#include <math.h>
static struct stb_easy_font_info_struct {
unsigned char advance;
unsigned char h_seg;
unsigned char v_seg;
} stb_easy_font_charinfo[96] = {
{ 6, 0, 0 }, { 3, 0, 0 }, { 5, 1, 1 }, { 7, 1, 4 },
{ 7, 3, 7 }, { 7, 6, 12 }, { 7, 8, 19 }, { 4, 16, 21 },
{ 4, 17, 22 }, { 4, 19, 23 }, { 23, 21, 24 }, { 23, 22, 31 },
{ 20, 23, 34 }, { 22, 23, 36 }, { 19, 24, 36 }, { 21, 25, 36 },
{ 6, 25, 39 }, { 6, 27, 43 }, { 6, 28, 45 }, { 6, 30, 49 },
{ 6, 33, 53 }, { 6, 34, 57 }, { 6, 40, 58 }, { 6, 46, 59 },
{ 6, 47, 62 }, { 6, 55, 64 }, { 19, 57, 68 }, { 20, 59, 68 },
{ 21, 61, 69 }, { 22, 66, 69 }, { 21, 68, 69 }, { 7, 73, 69 },
{ 9, 75, 74 }, { 6, 78, 81 }, { 6, 80, 85 }, { 6, 83, 90 },
{ 6, 85, 91 }, { 6, 87, 95 }, { 6, 90, 96 }, { 7, 92, 97 },
{ 6, 96,102 }, { 5, 97,106 }, { 6, 99,107 }, { 6,100,110 },
{ 6,100,115 }, { 7,101,116 }, { 6,101,121 }, { 6,101,125 },
{ 6,102,129 }, { 7,103,133 }, { 6,104,140 }, { 6,105,145 },
{ 7,107,149 }, { 6,108,151 }, { 7,109,155 }, { 7,109,160 },
{ 7,109,165 }, { 7,118,167 }, { 6,118,172 }, { 4,120,176 },
{ 6,122,177 }, { 4,122,181 }, { 23,124,182 }, { 22,129,182 },
{ 4,130,182 }, { 22,131,183 }, { 6,133,187 }, { 22,135,191 },
{ 6,137,192 }, { 22,139,196 }, { 6,144,197 }, { 22,147,198 },
{ 6,150,202 }, { 19,151,206 }, { 21,152,207 }, { 6,155,209 },
{ 3,160,210 }, { 23,160,211 }, { 22,164,216 }, { 22,165,220 },
{ 22,167,224 }, { 22,169,228 }, { 21,171,232 }, { 21,173,233 },
{ 5,178,233 }, { 22,179,234 }, { 23,180,238 }, { 23,180,243 },
{ 23,180,248 }, { 22,189,248 }, { 22,191,252 }, { 5,196,252 },
{ 3,203,252 }, { 5,203,253 }, { 22,210,253 }, { 0,214,253 },
};
static unsigned char stb_easy_font_hseg[214] = {
97,37,69,84,28,51,2,18,10,49,98,41,65,25,81,105,33,9,97,1,97,37,37,36,
81,10,98,107,3,100,3,99,58,51,4,99,58,8,73,81,10,50,98,8,73,81,4,10,50,
98,8,25,33,65,81,10,50,17,65,97,25,33,25,49,9,65,20,68,1,65,25,49,41,
11,105,13,101,76,10,50,10,50,98,11,99,10,98,11,50,99,11,50,11,99,8,57,
58,3,99,99,107,10,10,11,10,99,11,5,100,41,65,57,41,65,9,17,81,97,3,107,
9,97,1,97,33,25,9,25,41,100,41,26,82,42,98,27,83,42,98,26,51,82,8,41,
35,8,10,26,82,114,42,1,114,8,9,73,57,81,41,97,18,8,8,25,26,26,82,26,82,
26,82,41,25,33,82,26,49,73,35,90,17,81,41,65,57,41,65,25,81,90,114,20,
84,73,57,41,49,25,33,65,81,9,97,1,97,25,33,65,81,57,33,25,41,25,
};
static unsigned char stb_easy_font_vseg[253] = {
4,2,8,10,15,8,15,33,8,15,8,73,82,73,57,41,82,10,82,18,66,10,21,29,1,65,
27,8,27,9,65,8,10,50,97,74,66,42,10,21,57,41,29,25,14,81,73,57,26,8,8,
26,66,3,8,8,15,19,21,90,58,26,18,66,18,105,89,28,74,17,8,73,57,26,21,
8,42,41,42,8,28,22,8,8,30,7,8,8,26,66,21,7,8,8,29,7,7,21,8,8,8,59,7,8,
8,15,29,8,8,14,7,57,43,10,82,7,7,25,42,25,15,7,25,41,15,21,105,105,29,
7,57,57,26,21,105,73,97,89,28,97,7,57,58,26,82,18,57,57,74,8,30,6,8,8,
14,3,58,90,58,11,7,74,43,74,15,2,82,2,42,75,42,10,67,57,41,10,7,2,42,
74,106,15,2,35,8,8,29,7,8,8,59,35,51,8,8,15,35,30,35,8,8,30,7,8,8,60,
36,8,45,7,7,36,8,43,8,44,21,8,8,44,35,8,8,43,23,8,8,43,35,8,8,31,21,15,
20,8,8,28,18,58,89,58,26,21,89,73,89,29,20,8,8,30,7,
};
typedef struct
{
unsigned char c[4];
} stb_easy_font_color;
static int stb_easy_font_draw_segs(float x, float y, unsigned char *segs, int num_segs, int vertical, stb_easy_font_color c, char *vbuf, int vbuf_size, int offset)
{
int i,j;
for (i=0; i < num_segs; ++i) {
int len = segs[i] & 7;
x += (float) ((segs[i] >> 3) & 1);
if (len && offset+64 <= vbuf_size) {
float y0 = y + (float) (segs[i]>>4);
for (j=0; j < 4; ++j) {
* (float *) (vbuf+offset+0) = x + (j==1 || j==2 ? (vertical ? 1 : len) : 0);
* (float *) (vbuf+offset+4) = y0 + ( j >= 2 ? (vertical ? len : 1) : 0);
* (float *) (vbuf+offset+8) = 0.f;
* (stb_easy_font_color *) (vbuf+offset+12) = c;
offset += 16;
}
}
}
return offset;
}
static float stb_easy_font_spacing_val = 0;
static void stb_easy_font_spacing(float spacing)
{
stb_easy_font_spacing_val = spacing;
}
static int stb_easy_font_print(float x, float y, char *text, unsigned char color[4], void *vertex_buffer, int vbuf_size)
{
char *vbuf = (char *) vertex_buffer;
float start_x = x;
int offset = 0;
stb_easy_font_color c = { 255,255,255,255 }; // use structure copying to avoid needing depending on memcpy()
if (color) { c.c[0] = color[0]; c.c[1] = color[1]; c.c[2] = color[2]; c.c[3] = color[3]; }
while (*text && offset < vbuf_size) {
if (*text == '\n') {
y += 12;
x = start_x;
} else {
unsigned char advance = stb_easy_font_charinfo[*text-32].advance;
float y_ch = advance & 16 ? y+1 : y;
int h_seg, v_seg, num_h, num_v;
h_seg = stb_easy_font_charinfo[*text-32 ].h_seg;
v_seg = stb_easy_font_charinfo[*text-32 ].v_seg;
num_h = stb_easy_font_charinfo[*text-32+1].h_seg - h_seg;
num_v = stb_easy_font_charinfo[*text-32+1].v_seg - v_seg;
offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_hseg[h_seg], num_h, 0, c, vbuf, vbuf_size, offset);
offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_vseg[v_seg], num_v, 1, c, vbuf, vbuf_size, offset);
x += advance & 15;
x += stb_easy_font_spacing_val;
}
++text;
}
return (unsigned) offset/64;
}
static int stb_easy_font_width(char *text)
{
float len = 0;
float max_len = 0;
while (*text) {
if (*text == '\n') {
if (len > max_len) max_len = len;
len = 0;
} else {
len += stb_easy_font_charinfo[*text-32].advance & 15;
len += stb_easy_font_spacing_val;
}
++text;
}
if (len > max_len) max_len = len;
return (int) ceil(max_len);
}
static int stb_easy_font_height(char *text)
{
float y = 0;
int nonempty_line=0;
while (*text) {
if (*text == '\n') {
y += 12;
nonempty_line = 0;
} else {
nonempty_line = 1;
}
++text;
}
return (int) ceil(y + (nonempty_line ? 12 : 0));
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/