aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authormrfaptastic <12006953+mrfaptastic@users.noreply.github.com>2023-02-20 10:37:06 +1000
committerGitHub <noreply@github.com>2023-02-20 10:37:06 +1000
commit57d88db8aeb46ec8a151b20049df303f82582556 (patch)
tree523d82ba389690c505a7a092b77b356c94535b46 /examples
parente19898280a4a2f48a77817f2c755e3d468f4cc10 (diff)
parent19739da67fd1a5bfe21b786afa8648736726f249 (diff)
Merge pull request #403 from Kouzeru/master
New demo: Julia Set Demo
Diffstat (limited to 'examples')
-rw-r--r--examples/Julia_Set_Demo/Julia_Set_Demo.ino158
1 files changed, 158 insertions, 0 deletions
diff --git a/examples/Julia_Set_Demo/Julia_Set_Demo.ino b/examples/Julia_Set_Demo/Julia_Set_Demo.ino
new file mode 100644
index 0000000..9193006
--- /dev/null
+++ b/examples/Julia_Set_Demo/Julia_Set_Demo.ino
@@ -0,0 +1,158 @@
+#define PANEL_RES_X 128 // Number of pixels wide of each INDIVIDUAL panel module.
+#define PANEL_RES_Y 64 // Number of pixels tall of each INDIVIDUAL panel module.
+#define PANEL_CHAIN 1 // Total number of panels chained one to another
+#define USE_FLOATHACK // To boost float performance, comment if this doesn't work.
+
+#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
+
+MatrixPanel_I2S_DMA *dma_display = nullptr;
+
+// inspired by
+// https://en.wikipedia.org/wiki/Fast_inverse_square_root
+#ifdef USE_FLOATHACK
+// cast float as int32_t
+ int32_t intfloat(float n){ return *(int32_t *)&n; }
+// cast int32_t as float
+ float floatint(int32_t n){ return *(float *)&n; }
+// fast approx sqrt(x)
+ float floatsqrt(float n){ return floatint(0x1fbb4000+(intfloat(n)>>1)); }
+// fast approx 1/x
+ float floatinv(float n){ return floatint(0x7f000000-intfloat(n)); }
+// fast approx log2(x)
+ float floatlog2(float n){ return (float)((intfloat(n)<<1)-0x7f000000)*5.9604645e-08f; }
+#else
+ float floatinv(float n){ return 1.f/n;}
+ float floatsqrt(float n){ return std::sqrt(n); }
+ float floatlog2(float n){ return std::log2f(n); }
+#endif
+
+////////////////////////////////////////
+// Escape time mandelbrot set function,
+// with arbitrary start point zx, zy
+// and arbitrary seed point ax, ay
+//
+// For julia set
+// zx = pos_x, zy = pos_y;
+// ax = seed_x, ay = seed_y;
+//
+// For mandelbrot set
+// zx = 0, zy = 0;
+// ax = pos_x, ay = pos_y;
+//
+const float bailOut = 4; // Escape radius
+const int32_t itmult = 1<<10; // Color speed
+//
+// https://en.wikipedia.org/wiki/Mandelbrot_set
+int32_t iteratefloat(float ax, float ay, float zx, float zy, uint16_t mxIT) {
+ float zzl = 0;
+ for (int it = 0; it<mxIT; it++) {
+ float zzx = zx * zx;
+ float zzy = zy * zy;
+ // is the point is escaped?
+ if(zzx+zzy>=bailOut){
+ if(it>0){
+ // calculate smooth coloring
+ float zza = floatlog2(zzl);
+ float zzb = floatlog2(zzx+zzy);
+ float zzc = floatlog2(bailOut);
+ float zzd = (zzc-zza)*floatinv(zzb-zza);
+ return it*itmult+zzd*itmult;
+ }
+ };
+ // z -> z*z + c
+ zy = 2.f*zx*zy+ay;
+ zx = zzx-zzy+ax;
+ zzl = zzx+zzy;
+ }
+ return 0;
+}
+
+float sint[256]; // precalculated sin table, for performance reasons
+
+// Palette color taken from:
+// https://editor.p5js.org/Kouzerumatsukite/sketches/DwTiq9D01
+// color palette originally made by piano_miles, written in p5js
+// hsv2rgb(IT, cos(4096*it)/2+0.5, 1-sin(2048*it)/2-0.5)
+void drawPixelPalette(int x, int y, uint32_t m){
+ float r = 0.f, g = 0.f, b = 0.f;
+ if(m){
+ char n = m>> 4 ;
+ float l =abs(sint[m>> 2&255] )*255.f ;
+ float s = (sint[m &255]+ 1.f)*0.5f ;
+ r = (max(min(sint[n &255]+0.5f,1.f),0.f)*s+(1-s))*l;
+ g = (max(min(sint[n+ 85&255]+0.5f,1.f),0.f)*s+(1-s))*l;
+ b = (max(min(sint[n+170&255]+0.5f,1.f),0.f)*s+(1-s))*l;
+ }
+ dma_display->drawPixelRGB888(x,y,r,g,b);
+}
+
+void drawCanvas() {
+ uint32_t lastMicros = micros();
+ double t = (double)lastMicros/8000000;
+ double k = sin(t*3.212/2)*sin(t*3.212/2)/16+1;
+ float cosk = (k-cos(t))/2;
+ float xoff = (cos(t)*cosk+k/2-0.25);
+ float yoff = (sin(t)*cosk );
+ for(uint8_t y=0;y<PANEL_RES_Y;y++){
+ for(uint8_t x=0;x<PANEL_RES_X;x++){
+ uint32_t itcount = iteratefloat(xoff,yoff,((x-64)+1)/64.f,(y)/64.f,64);
+ uint32_t itcolor = itcount?floatsqrt(itcount)*4+t*1024:0;
+ drawPixelPalette(x,y,itcolor);
+ }
+ }
+}
+
+volatile int frameCounts=0;
+void Task1code(void *parameter){
+ while(true){
+ drawCanvas();
+ delay(1);
+ frameCounts++;
+ }
+}
+
+void setup() {
+ HUB75_I2S_CFG::i2s_pins _pins={
+// R1, G1, B1, R2, G2, B2, A, B, C, D, E,LAT, OE,CLK,
+ 25, 26, 27, 14, 12, 13, 23, 19, 5, 17, 18, 4, 15, 16,
+ };
+ HUB75_I2S_CFG mxconfig(
+ PANEL_RES_X, // Module width
+ PANEL_RES_Y, // Module height
+ PANEL_CHAIN, // chain length
+ _pins
+ );
+
+ // Display Setup
+ dma_display = new MatrixPanel_I2S_DMA(mxconfig);
+ dma_display->begin();
+ dma_display->clearScreen();
+ dma_display->setBrightness(64);
+ setCpuFrequencyMhz(240);
+
+ for(int i=0;i<256;i++){
+ sint[i] = sinf(i/256.f*2.f*PI);
+ }
+
+ xTaskCreatePinnedToCore(\
+ Task1code, /* Function to implement the task */\
+ "Task1", /* Name of the task */\
+ 10000, /* Stack size in words */\
+ NULL, /* Task input parameter */\
+ 4, /* Priority of the task */\
+ NULL, /* Task handle. */\
+ 0); /* Core where the task should run */
+
+ Serial.begin(115200);
+}
+
+uint64_t lastMillis=0;
+void loop() {
+ if(millis()-lastMillis>=1000){
+ // log frame rate to serial
+ Serial.print("fps: ");
+ Serial.println(frameCounts);
+ lastMillis += 1000;
+ frameCounts=0;
+ }
+}